Loadable Kernel Module Exploits
Now we graduate to a more advanced example. Listing 1 presents a module that logs a message every time someone other than uid 0 (root) or uid 500 (me on my workstation) invokes the write system call with the word “Linux” somewhere in the buffer. You may have to stretch a little to find a use for this module by itself, but I assure you it demonstrates several useful concepts. We are able to do this all by replacing the write system call with our own function that performs the checking and logging, and then calls write. Let's go through this example step by step.
Notice all of the include files. There sure are a lot of them, but don't despair, the ones we are going to worry about are linux/sched.h and asm/uaccess.h. The sched.h include allows you to access the current task_struct structure via the current macro, providing a great deal of useful information about the current process (see Table 1 for a list of some useful fields in task_struct), while uaccess.h provides useful macros for accessing user-space memory (more on this later).
Even these few fields in task_struct are enough to enable some really interesting modules. Should arbitrary users be allowed to su to root? You can prevent them from doing so by wrapping setuid and checking for one of several prespecified UIDs before allowing the “real” setuid. This will allow you to develop, at the kernel level, an equivalent to the wheel group, or group of users that are allowed to su root. As an aside, the FSF has long held that the wheel group is a tool of fascist administrators (see the documentation for GNU su for more information).
Being able to audit or alter the behavior of system calls, simply on the basis of which uid invokes them, is obviously a powerful ability. It can make for good security policy to control and audit the actions of the “nobody” user and its friends, the uucp, mail and postgres users carefully. However, an even more powerful technique is to alter behavior based on an argument. We will ignore sys_call_table and origwrite for now and proceed directly to wrapped_write, which examines both the uid of the invoking process and its buffer argument.
The first thing you should notice is that wrapped_write begins with a call to kmalloc. Why not malloc, you may ask? Remember, we're still in kernel space, and we don't have access to malloc and other standard library functions. Even if we did, calling malloc, which returns a pointer to user-space memory, would be worthless. We need to allocate some memory in kernel space to copy data into from the buf argument. This is an important point: the same memory visibility barrier between kernel and user space that keeps your programs from crashing the kernel also adds a little bit of complexity to your kernel programming. When you call write from a C program, you pass a pointer to a user-space memory block that is inaccessible from the kernel. Therefore, if you want to do any operations on data pointed to by a user-space pointer, you will have to first copy that memory area into kernel space. The copy_from_user macro does this for you. copy_from_user takes three arguments, a “to” pointer, a “from” pointer and a count.
The remainder of wrapped_write is fairly straightforward, given what we know about current and task_struct. Perhaps a more interesting module would use strstr to check for the string “Linux sucks”, and if it existed, alter write_buf at that point to contain “Linux rule”, then transfer write_buf back to user space (with the copy_to_user macro) before calling the original write. Then, if unsuspecting users wrote “Linux sucks”, it would be replaced with “Linux rules”. kfree is important here. Leaking memory in the kernel is a bad thing, so be sure to kfree everything you kmalloc.
It is in init_module that we actually make the switch so that our function is called instead of the original write. Recall that syss_call_table is an array of pointers to functions. By altering the value at index SYS_write (a constant representing the system call number for write), we are able to cause another function to replace write. Be sure to save the original function, so you can replace it when the module is unloaded! You can test this module out by compiling and installing it with insmod; then su to some user other than 0 or 500, and type
% echo "I like Linux"
on a virtual console. You should get a message from the kernel that you're talking about Linux again. Congratulations! You are now ready for a module that does something useful.
Fast/Flexible Linux OS Recovery
On Demand Now
In this live one-hour webinar, learn how to enhance your existing backup strategies for complete disaster recovery preparedness using Storix System Backup Administrator (SBAdmin), a highly flexible full-system recovery solution for UNIX and Linux systems.
Join Linux Journal's Shawn Powers and David Huffman, President/CEO, Storix, Inc.
Free to Linux Journal readers.Register Now!
- Download "Linux Management with Red Hat Satellite: Measuring Business Impact and ROI"
- ServersCheck's Thermal Imaging Camera Sensor
- The Italian Army Switches to LibreOffice
- Linux Mint 18
- Petros Koutoupis' RapidDisk
- Oracle vs. Google: Round 2
- The FBI and the Mozilla Foundation Lock Horns over Known Security Hole
- Privacy and the New Math
- Ben Rady's Serverless Single Page Apps (The Pragmatic Programmers)
Until recently, IBM’s Power Platform was looked upon as being the system that hosted IBM’s flavor of UNIX and proprietary operating system called IBM i. These servers often are found in medium-size businesses running ERP, CRM and financials for on-premise customers. By enabling the Power platform to run the Linux OS, IBM now has positioned Power to be the platform of choice for those already running Linux that are facing scalability issues, especially customers looking at analytics, big data or cloud computing.
￼Running Linux on IBM’s Power hardware offers some obvious benefits, including improved processing speed and memory bandwidth, inherent security, and simpler deployment and management. But if you look beyond the impressive architecture, you’ll also find an open ecosystem that has given rise to a strong, innovative community, as well as an inventory of system and network management applications that really help leverage the benefits offered by running Linux on Power.Get the Guide