Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1707316
  • 博文数量: 607
  • 博客积分: 10031
  • 博客等级: 上将
  • 技术积分: 6633
  • 用 户 组: 普通用户
  • 注册时间: 2006-03-30 17:41
文章分类

全部博文(607)

文章存档

2011年(2)

2010年(15)

2009年(58)

2008年(172)

2007年(211)

2006年(149)

我的朋友

分类: LINUX

2006-09-20 14:51:15

Search the Catalog

Linux Device Drivers, 2nd Edition


2nd Edition June 2001
0-59600-008-1, Order Number: 0081
586 pages, $39.95

Chapter 11
kmod and Advanced Modularization

Contents:





In this second part of the book, we discuss more advanced topics than we've seen up to now. Once again, we start with modularization.

The implementation of demand loading of modules has changed significantly over time. This chapter discusses the 2.4 implementation, as usual. The sample code works, as far as possible, on the 2.0 and 2.2 kernels as well; we cover the differences at the end of the chapter.

To make it easier for users to load and unload modules, to avoid wasting kernel memory by keeping drivers in core when they are not in use, and to allow the creation of "generic'' kernels that can support a wide variety of hardware, Linux offers support for automatic loading and unloading of modules. To exploit this feature, you need to enable kmod support when you configure the kernel before you compile it; most kernels from distributors come with kmod enabled. This ability to request additional modules when they are needed is particularly useful for drivers using module stacking.

One example of a driver that benefits from demand loading is the Advanced Linux Sound Architecture (ALSA) sound driver suite, which should (someday) replace the current sound implementation (Open Sound System, or OSS) in the Linux kernel.[42] ALSA is split into many pieces. The set of core code that every system needs is loaded first. Additional pieces get loaded depending on both the installed hardware (which sound card is present) and the desired functionality (MIDI sequencer, synthesizer, mixer, OSS compatibility, etc.). Thus, a large and complicated system can be broken down into components, with only the necessary parts being actually present in the running system.

[43]Most distributions run depmod -a automatically at boot time, so you don't need to worry about that unless you installed new modules after you rebooted. See the modprobe documentation for more details.

Module Loading and Security

The loading of a module into the kernel has obvious security implications, since the loaded code runs at the highest possible privilege level. For this reason, it is important to be very careful in how you work with the module-loading system.

Note that insmod will normally refuse to load any modules that are not owned by the root account; this behavior is an attempt at a defense against an attacker who obtains write access to a module directory. You can override this check with an option to insmod (or a modules.conf line), but doing so reduces the security of your system.

One other thing to keep in mind is that the module name parameter that you pass to request_module eventually ends up on the modprobe command line. If that module name is provided by a user-space program in any way, it must be very carefully validated before being handed off to request_module. Consider, for example, a system call that configures network interfaces. In response to an invocation of ifconfig, this system call tells request_module to load the driver for the (user-specified) interface. A hostile user can then carefully choose a fictitious interface name that will cause modprobe to do something improper. This is a real vulnerability that was discovered late in the 2.4.0-test development cycle; the worst problems have been cleaned up, but the system is still vulnerable to malicious module names.

As we have seen, the request_module function runs a program in user mode (i.e., running as a separate process, in an unprivileged processor mode, and in user space) to help it get its job done. In the 2.3 development series, the kernel developers made the "run a user-mode helper'' capability available to the rest of the kernel code. Should your driver need to run a user-mode program to support its operations, this mechanism is the way to do it. Since it's part of the kmod implementation, we'll look at it here. If you are interested in this capability, a look at kernel/kmod.c is recommended; it's not much code and illustrates nicely the use of user-mode helpers.

The interface for running helper programs is fairly simple. As of kernel 2.4.0-test9, there is a function call_usermodehelper; it is used primarily by the hot-plug subsystem (i.e., for USB devices and such) to perform module loading and configuration tasks when a new device is attached to the system. Its prototype is:

The arguments will be familiar: they are the name of the executable to run, arguments to pass to it (argv[0], by convention, is the name of the program itself), and the values of any environment variables. Both arrays must be terminated by NULL values, just like with the execve system call. call_usermodehelper will sleep until the program has been started, at which point it returns the status of the operation.

Very late in the pre-2.4.0 development series, the kernel developers added a new interface providing limited communication between modules. This intermodule scheme allows modules to register strings pointing to data of interest, which can be retrieved by other modules. We'll look briefly at this interface, using a variation of our master and slavemodules.

One of the main problems with modules is their version dependency, which was introduced in Chapter 2, "Building and Running Modules". The need to recompile the module against the headers of each kernel version being used can become a real pain when you run several custom modules, and recompiling is not even possible if you run a commercial module distributed in binary form.

Fortunately, the kernel developers found a flexible way to deal with version problems. The idea is that a module is incompatible with a different kernel version only if the software interface offered by the kernel has changed. The software interface, then, can be represented by a function prototype and the exact definition of all the data structures involved in the function call. Finally, a CRC algorithm[45] can be used to map all the information about the software interface to a single 32-bit number.

There are some limitations to this scheme. A common source of surprises has been loading a module compiled for SMP systems into a uniprocessor kernel, or vice versa. Because numerous inline functions (e.g., spinlock operations) and symbols are defined differently for SMP kernels, it is important that modules and the kernel agree on whether they are built for SMP. Version 2.4 and recent 2.2 kernels throw an extra smp_ string onto each symbol when compiling for SMP to catch this particular case. There are still potential traps, however. Modules and the kernel can differ in which version of the compiler was used to build them, which view of memory they take, which version of the processor they were built for, and more. The version support scheme can catch the most common problems, but it still pays to be careful.

Driver writers must add some explicit support if their modules are to work with versioning. Version control can be inserted in one of two places: in the makefile or in the source itself. Since the documentation of the modutils package describes how to do it in the makefile, we'll show you how to do it in the C source. The master module used to demonstrate how kmod works is able to support versioned symbols. The capability is automatically enabled if the kernel used to compile the module exploits version support.

To enable versioning in the module if it has been enabled in the kernel, we must make sure that CONFIG_MODVERSIONS has been defined in . That header controls what features are enabled (compiled) in the current kernel. Each CONFIG_ macro defined states that the corresponding option is active.[46]

The one thing not covered by the previous discussion is what happens when a module exports symbols to be used by other modules. If we rely on version information to achieve module portability, we'd like to be able to add a CRC code to our own symbols. This subject is slightly trickier than just linking to the kernel, because we need to export the mangled symbol name to other modules; we need a way to build the checksums.

The demand-loading capability was entirely reimplemented in the 2.1 development series. Fortunately, very few modules need to be aware of the change in any way. For completeness, however, we will describe the old implementation here.

This chapter introduced the following kernel symbols.

/etc/modules.conf

This macro is defined only if the current kernel has been compiled to support versioned symbols.



Back to:


| | | | | |

© 2001, O'Reilly & Associates, Inc.

阅读(501) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~