Traditionally, the
operating system kernel was responsible for providing an abstract interface to the hardware the system ran on. Applications used the
system call interface, or performed file
I/O on
device nodes in order to communicate with hardware through these abstractions. This sufficed for the simple hardware of early desktop computing. Computer hardware, however, has increased in complexity and the abstractions provided by Unix kernels have not kept pace with the proliferating number of device and
peripheral types now common on both server and desktop computers. Most modern
buses have also become
hotplug-capable and can have non-trivial
topologies. As a result, devices are discovered or change state in ways which can be difficult to track through the system call interface or Unix IPC. The complexity of doing so forces application authors to re-implement hardware support logic. Some devices also require privileged helper programs to prepare them for use. These must often be invoked in ways that can be awkward to express with the Unix permissions model (for example, allowing users to join
wireless networks only if they are logged into the video console). Application authors resort to using
setuid binaries or run service
daemons to provide their own access control and privilege separation, potentially introducing security holes each time. == Design ==