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.
Practical Task Scheduling Deployment
July 20, 2016 12:00 pm CDT
One of the best things about the UNIX environment (aside from being stable and efficient) is the vast array of software tools available to help you do your job. Traditionally, a UNIX tool does only one thing, but does that one thing very well. For example, grep is very easy to use and can search vast amounts of data quickly. The find tool can find a particular file or files based on all kinds of criteria. It's pretty easy to string these tools together to build even more powerful tools, such as a tool that finds all of the .log files in the /home directory and searches each one for a particular entry. This erector-set mentality allows UNIX system administrators to seem to always have the right tool for the job.
Cron traditionally has been considered another such a tool for job scheduling, but is it enough? This webinar considers that very question. The first part builds on a previous Geek Guide, Beyond Cron, and briefly describes how to know when it might be time to consider upgrading your job scheduling infrastructure. The second part presents an actual planning and implementation framework.
Join Linux Journal's Mike Diehl and Pat Cameron of Help Systems.
Free to Linux Journal readers.Register Now!
- SUSE LLC's SUSE Manager
- My +1 Sword of Productivity
- Non-Linux FOSS: Caffeine!
- Managing Linux Using Puppet
- Control Your Linux Desktop with D-Bus
- Download "Linux Management with Red Hat Satellite: Measuring Business Impact and ROI"
- Doing for User Space What We Did for Kernel Space
- SuperTuxKart 0.9.2 Released
- Google's SwiftShader Released
- Murat Yener and Onur Dundar's Expert Android Studio (Wrox)
With all the industry talk about the benefits of Linux on Power and all the performance advantages offered by its open architecture, you may be considering a move in that direction. If you are thinking about analytics, big data and cloud computing, you would be right to evaluate Power. The idea of using commodity x86 hardware and replacing it every three years is an outdated cost model. It doesn’t consider the total cost of ownership, and it doesn’t consider the advantage of real processing power, high-availability and multithreading like a demon.
This ebook takes a look at some of the practical applications of the Linux on Power platform and ways you might bring all the performance power of this open architecture to bear for your organization. There are no smoke and mirrors here—just hard, cold, empirical evidence provided by independent sources. I also consider some innovative ways Linux on Power will be used in the future.Get the Guide