Article Title: Security Port allocation for device drivers in Linux. Linux is a technology channel of the IT lab in China. Includes basic categories such as desktop applications, Linux system management, kernel research, embedded systems, and open source.
Abstract:
Writing Device Drivers is a challenging and adventurous job. When the device is registered using the init_mo dule function, the device resources should be allocated. A major device resource is the I/O port. As a dynamically connected driver, developers should be careful to allocate unused I/O ports to these devices. First, the driver should detect whether these ports are used or released. Then apply for a port for the device. When the driver module is removed from the kernel, the port should be released. This article discusses the complexity of Secure port allocation for Linux device drivers.
Introduction
A major concern for device drivers is the allocation of device resources. These resources include I/O Ports, memory, and interruptions. This article attempts to explain the basic principles of the I/O subsystem and the importance of resource allocation, mainly the resource processing of the I/O port. It also explains how to detect, apply for, and release the port address of the device.
Basic hardware elements, such as ports, bus, and device controllers, constitute a large number of different I/O devices. The Device Driver provides a general device access interface to the I/O subsystem, which is very similar to the standard interface provided by the system call between the application and the operating system. There are many types of devices attached to a computer. For example, there are storage devices, such as disks, tapes, optical drives, and soft drives. Human-Computer Interaction devices, such as keyboards, mice, and screens; transmission devices, such as NICs and modems. Regardless of the number of these devices, we only need to understand some basic concepts, that is, how the device is loaded and how the software controls the hardware.
Basic Concepts
The device consists of two parts: one is the electrical part called the device controller, and the other is the mechanical part. The Controller is loaded to the computer through the system bus. Typically, a set of non-conflicting register groups are assigned to each controller. The I/O port contains four groups of registers, namely the status recorder, control register, data input register, and data output register. The Status Register has the (Status) bit that can be read by the host to indicate whether the current command has been executed, whether bytes can be read or written, and any error message. The control register is written by the host to start a command or change the device's (working) mode. The data input register is used to obtain the input, and the data output register sends the result to the host.
Therefore, the basic interface between the processor and the device is the control and Status Register. When the processor executes a program and encounters a device-related command, it sends a command to the corresponding device to execute the command. The Controller executes the required action, sets the special location of the Status Register, and then enters the waiting state. The processor is responsible for checking the status of the device until the discovery operation is completed. For example, the parallel port driver (used by the printer) usually polls the printer to see if the printer is ready. If the printer is not ready, the driver will sleep for a while (the processor will do other useful work at this time) and the process will repeat until the printer is ready. This round robin mechanism can improve the system performance. Another way is to do unnecessary "unnecessarily waiting" without any useful work.
Registers have clearly defined address ranges in the I/O space. These addresses are usually allocated at startup, using a set of parameters defined in the configuration file. The address range of each device may be pre-allocated if the device is statically loaded. This means that the kernel contains drivers of existing devices, so that the allocated I/O ports can be stored in the Proc directory. When the system uses these devices, you can run the "cat/proc/ioports" command to check their address ranges synchronously. The output in the first column shows the port range, while the second column shows the devices that use these ports. Some operating systems have the ability to dynamically load device driver modules at runtime. Therefore, any new device can be loaded to the system during system operation through the dynamic loading module, and can be controlled and accessed.
The concept of a device driver is very abstract and is at the lowest layer of the software running on a computer. Due to the limitation of hardware features directly to the device. Each device driver manages only one type of device. These types may be portable, fast, or network type. If an application requests (Actions) from the device. The kernel will be connected to the corresponding device driver, and the device driver then sends commands to specific devices. A device drive is a set of functions: including many call portals, such as open, close, read, write, ioctl, and llseek. When you insert your module, the init_module () function is called, and the module is removed, the cleanup_module () function is called. The device is registered in the init_module () routine of the device driver.
When the device logs in init_module (), the device's resources, such as the I/O port, memory and interrupt number, are also allocated in this function, this is also required for the driver to operate the device correctly. If you have allocated any wrong memory address, the system will display the error message segmentation fault. for I/O Ports, the system does not provide any information similar to wrong I/O Ports, But assigning any ports used by existing devices will cause system crash. When you remove a module, the device should be canceled. More specifically, the master (device) Number and resource will be released in the cleanup_module () function.
Read/write IO ports when device drivers work most frequently. Therefore, your driver should be sure to be perfect, and the port address used by the device is exclusive. This address range is not used by any other device. To confirm this, the driver should first check whether this address is in use. When the driver finds that this address is not used, you can request the kernel to allocate this address to the device.
Security Port allocation
Now let's take a look at how to use system functions to allocate and release resources. The following example is in linux 2. 4. All of the following implementations are only applicable to Linux operating systems and some extended Unix variants.
First, detect the available port (Address) range through the following function:
int check_region (unsigned long start, unsigned long len);
|
If the function returns 0, the port address is available. If the return value is less than zero or negative, the error code (-EBUSY or-EINVAL) indicates that the port address is in use. The function accepts two parameters: start is the starting value of the continuous region (or the I/O port range), and len is the number of ports in the region.
When the port is available, it should be allocated to the device through the request_region function.
Struct resource * request_region (unsigned long start, unsigned long len, char * name );
The first two parameters are the same as we have seen before. The character pointer variable name is the name of the device to which the port address is to be allocated. The function returns a pointer to the resource structure. The Resource structure is used to describe the Resource range, defined in . The structure format is defined as follows:
struct resource { const char *name; unsigned long start, end; unsigned long flags; struct resource *parent, *sibiling, *child; };
|
When a module is removed from the kernel, the port should be released for use by other devices. Therefore, we use the release_region () function in cleanup_module. The function syntax is as follows:
void release_region ( unsigned long start, unsigned long len);
|
The two parameters are interpreted as the same as those described above. The above three functions are actually macro definitions, defined in .
[1] [2] Next page