Ioctl

In computing, codice_1 (an abbreviation of input/output control) is a system call for device-specific input/output operations and other operations which cannot be expressed by regular system calls. It takes a parameter specifying a request code; the effect of a call depends completely on the request code. Request codes are often device-specific. For instance, a CD-ROM device driver which can instruct a physical device to eject a disc would provide an codice_1 request code to do that. Device-independent request codes are sometimes used to give userspace access to kernel functions which are only used by core system software or still under development.
The codice_1 system call first appeared in Version 7 of Unix under that name. It is supported by most Unix and Unix-like systems, including Linux and macOS, though the available request codes differ from system to system. Microsoft Windows provides a similar function, named "codice_4", in its Win32 API.
Background.
Conventional operating systems can be divided into two layers, userspace and the kernel. Application code such as a text editor resides in userspace, while the underlying facilities of the operating system, such as the network stack, reside in the kernel. Kernel code handles sensitive resources and implements the security and reliability barriers between applications; for this reason, user mode applications are prevented by the operating system from directly accessing kernel resources.
Userspace applications typically make requests to the kernel by means of system calls, whose code lies in the kernel layer. A system call usually takes the form of a "system call vector", in which the desired system call is indicated with an index number. For instance, codice_5 might be system call number 1, and codice_6 number 4. The system call vector is then used to find the desired kernel function for the request. In this way, conventional operating systems typically provide several hundred system calls to the userspace.
Though an expedient design for accessing standard kernel facilities, system calls are sometimes inappropriate for accessing non-standard hardware peripherals. By necessity, most hardware peripherals (aka devices) are directly addressable only within the kernel. But user code may need to communicate directly with devices; for instance, an administrator might configure the media type on an Ethernet interface. Modern operating systems support diverse devices, many of which offer a large collection of facilities. Some of these facilities may not be foreseen by the kernel designer, and as a consequence it is difficult for a kernel to provide system calls for using the devices.
To solve this problem, the kernel is designed to be extensible, and may accept an extra module called a device driver which runs in kernel space and can directly address the device. An codice_1 interface is a single system call by which userspace may communicate with device drivers. Requests on a device driver are vectored with respect to this codice_1 system call, typically by a handle to the device and a request number. The basic kernel can thus allow the userspace to access a device driver without knowing anything about the facilities supported by the device, and without needing an unmanageably large collection of system calls.
Uses.
Hardware device configuration.
A common use of codice_1 is to control hardware devices.
For example, on Win32 systems, codice_1 calls can communicate with USB devices, or they can discover drive-geometry information of the attached storage-devices.
On OpenBSD and NetBSD, codice_1 is used by the codice_12 pseudo-device driver and the codice_13 utility to implement RAID volume management in a unified vendor-agnostic interface similar to codice_14.
On NetBSD, codice_1 is also used by the codice_16 framework.
Terminals.
One use of codice_1 in code exposed to end-user applications is terminal I/O.
Unix operating systems have traditionally made heavy use of command-line interfaces. The Unix command-line interface is built on pseudo terminals (ptys), which emulate hardware text terminals such as VT100s. A pty is controlled and configured as if it were a hardware device, using codice_1 calls. For instance, the window size of a pty is set using the codice_19 call. The TIOCSTI (terminal I/O control, simulate terminal input) ioctl function can push a character into a device stream.
Kernel extensions.
When applications need to extend the kernel, for instance to accelerate network processing, codice_1 calls provide a convenient way to bridge userspace code to kernel extensions. Kernel extensions can provide a location in the filesystem that can be opened by name, through which an arbitrary number of codice_1 calls can be dispatched, allowing the extension to be programmed without adding system calls to the operating system.
sysctl alternative.
According to an OpenBSD developer, codice_1 and codice_23 are the two system calls for extending the kernel, with codice_23 possibly being the simpler of the two.
In NetBSD, the codice_25 framework for hardware monitoring uses codice_1 through codice_27; whereas OpenBSD and DragonFly BSD instead use codice_23 for their corresponding codice_29 framework. The original revision of codice_30 in NetBSD was implemented with codice_1 before codice_27 was available, and had a message suggesting that the framework is experimental, and should be replaced by a codice_33 interface, should one be developed,<ref name=n40/envsys.4></ref> which potentially explains the choice of codice_23 in OpenBSD with its subsequent introduction of codice_29 in 2003. However, when the codice_30 framework was redesigned in 2007 around codice_27, the system call remained as codice_1, and the message was removed.
Implementations.
Unix.
The codice_1 system call first appeared in Version 7 Unix, as a renamed codice_40. An codice_1 call takes as parameters:
The kernel generally dispatches an codice_1 call straight to the device driver, which can interpret the request number and data in whatever way required. The writers of each driver document request numbers for that particular driver and provide them as constants in a header file.
Some Unix systems, including Linux, have conventions which encode within the request number the size of the data to be transferred to/from the device driver, the direction of the data transfer and the identity of the driver implementing the request. Regardless of whether such a convention is followed, the kernel and the driver collaborate to deliver a uniform error code (denoted by the symbolic constant codice_43) to an application which makes a request of a driver which does not recognise it.
The mnemonic codice_43 (traditionally associated with the textual message ""Not a typewriter") derives from the earliest systems that incorporated an codice_1 call, where only the teletype (codice_46) device raised this error. Though the symbolic mnemonic is fixed by compatibility requirements, some modern systems more helpfully render a more general message such as "Inappropriate device control operation"" (or a localization thereof).
codice_47 exemplifies an codice_1 call on a serial port. The normal read and write calls on a serial port receive and send data bytes. An codice_49 call, separate from such normal I/O, controls various driver options like handling of special characters, or the output signals on the port (such as the DTR signal).
Win32.
A Win32 codice_4 takes as parameters:
The Win32 device control code takes into consideration the mode of the operation being performed.
There are 4 defined modes of operation, impacting the security of the device driver -
Alternatives.
Other vectored call interfaces.
Devices and kernel extensions may be linked to userspace using additional new system calls, although this approach is rarely taken, because operating system developers try to keep the system call interface focused and efficient.
On Unix operating systems, two other vectored call interfaces are popular: the codice_56 ("file control") system call configures open files, and is used in situations such as enabling non-blocking I/O; and the codice_57 ("set socket option") system call configures open network sockets, a facility used to configure the codice_58 packet firewall on BSD Unix systems.
Netlink.
Netlink is a socket-like mechanism for inter-process communication (IPC), designed to be a more flexible successor to codice_1.
Implications.
Complexity.
codice_1 calls minimize the complexity of the kernel's system call interface. However, by providing a place for developers to "stash" bits and pieces of kernel programming interfaces, codice_1 calls complicate the overall user-to-kernel API. A kernel that provides several hundred system calls may provide several thousand ioctl calls.
Though the interface to codice_1 calls appears somewhat different from conventional system calls, there is in practice little difference between an codice_1 call and a system call; an codice_1 call is simply a system call with a different dispatching mechanism. Many of the arguments against expanding the kernel system call interface could therefore be applied to codice_1 interfaces.
To application developers, system calls appear no different from application subroutines; they are simply function calls that take arguments and return values. The runtime libraries of the OS mask the complexity involved in invoking system calls. Unfortunately, runtime libraries do not make codice_1 calls as transparent. Simple operations like discovering the IP addresses for a machine often require tangled messes of codice_1 calls, each requiring magic numbers and argument structures.
Libpcap and libdnet are two examples of third-party wrapper Unix libraries designed to mask the complexity of codice_1 interfaces, for packet capture and packet I/O, respectively.
Security.
The user-to-kernel interfaces of mainstream operating systems are often audited heavily for code flaws and security vulnerabilities prior to release. These audits typically focus on the well-documented system call interfaces; for instance, auditors might ensure that sensitive security calls such as changing user IDs are only available to administrative users.
codice_1 interfaces are more complicated, more diverse, and thus harder to audit than system calls. Furthermore, because codice_1 calls can be provided by third-party developers, often after the core operating system has been released, codice_1 call implementations may receive less scrutiny and thus harbor more vulnerabilities. Finally, many codice_1 calls, particularly for third-party device drivers, are undocumented.
Because the handler for an codice_1 call resides directly in kernel mode, the input from userspace should be validated carefully. Vulnerabilities in device drivers can be exploited by local users by passing invalid buffers to codice_1 calls.
Win32 and Unix operating systems can protect a userspace device name from access by applications with specific access controls applied to the device. Security problems can arise when device driver developers do not apply appropriate access controls to the userspace accessible object.
Some modern operating systems protect the kernel from hostile userspace code (such as applications that have been infected by buffer overflow exploits) using system call wrappers. System call wrappers implement role-based access control by specifying which system calls can be invoked by which applications; wrappers can, for instance, be used to "revoke" the right of a mail program to spawn other programs. codice_1 interfaces complicate system call wrappers because there are large numbers of them, each taking different arguments, some of which may be required by normal programs.