En informática , ioctl
(una abreviatura de control de entrada / salida ) es una llamada al sistema para operaciones de entrada / salida específicas del dispositivo y otras operaciones que no pueden expresarse mediante llamadas regulares al sistema. Toma un parámetro que especifica un código de solicitud; el efecto de una llamada depende completamente del código de solicitud. Los códigos de solicitud suelen ser específicos del dispositivo. Por ejemplo, un controlador de dispositivo de CD-ROM que puede indicarle a un dispositivo físico que expulse un disco proporcionaría un ioctl
código de solicitud para hacerlo. Los códigos de solicitud independientes del dispositivo a veces se usan para dar acceso al espacio de usuario a las funciones del kernel que solo usan el software del sistema central o que aún están en desarrollo.
La ioctl
llamada al sistema apareció por primera vez en la versión 7 de Unix con ese nombre. Es compatible con la mayoría de los sistemas Unix y similares a Unix, incluidos Linux y macOS , aunque los códigos de solicitud disponibles difieren de un sistema a otro. Microsoft Windows proporciona una función similar, denominada " DeviceIoControl
", en su API Win32 .
Fondo
Los sistemas operativos convencionales se pueden dividir en dos capas, el espacio de usuario y el kernel . El código de la aplicación, como un editor de texto, reside en el espacio de usuario , mientras que las funciones subyacentes del sistema operativo, como la pila de red , residen en el kernel. El código del núcleo maneja recursos sensibles e implementa las barreras de seguridad y confiabilidad entre aplicaciones; por esta razón, el sistema operativo impide que las aplicaciones en modo de usuario accedan directamente a los recursos del kernel.
Las aplicaciones del espacio de usuario suelen realizar solicitudes al kernel mediante llamadas al sistema , cuyo código se encuentra en la capa del kernel. Una llamada al sistema suele adoptar la forma de un "vector de llamada al sistema", en el que la llamada al sistema deseada se indica con un número de índice. Por ejemplo, exit()
podría ser la llamada al sistema número 1 y la write()
número 4. El vector de llamada al sistema se utiliza para encontrar la función del núcleo deseada para la solicitud. De esta forma, los sistemas operativos convencionales normalmente proporcionan varios cientos de llamadas al sistema al espacio de usuario.
Aunque es un diseño conveniente para acceder a las instalaciones del kernel estándar, las llamadas al sistema a veces son inapropiadas para acceder a periféricos de hardware no estándar. Por necesidad, la mayoría de los periféricos de hardware (también conocidos como dispositivos) son directamente direccionables solo dentro del kernel. Pero es posible que el código de usuario deba comunicarse directamente con los dispositivos; por ejemplo, un administrador puede configurar el tipo de medio en una interfaz Ethernet . Los sistemas operativos modernos admiten diversos dispositivos, muchos de los cuales ofrecen una gran variedad de funciones. Es posible que el diseñador del kernel no prevea algunas de estas funciones y, como consecuencia, es difícil para un kernel proporcionar llamadas al sistema para usar los dispositivos.
Para resolver este problema, el kernel está diseñado para ser extensible y puede aceptar un módulo adicional llamado controlador de dispositivo que se ejecuta en el espacio del kernel y puede dirigirse directamente al dispositivo. Una ioctl
interfaz es una única llamada al sistema mediante la cual el espacio de usuario puede comunicarse con los controladores de dispositivos. Las solicitudes en un controlador de dispositivo se vectorizan con respecto a esta ioctl
llamada al sistema, generalmente mediante un identificador del dispositivo y un número de solicitud. Por lo tanto, el kernel básico puede permitir que el espacio de usuario acceda a un controlador de dispositivo sin saber nada acerca de las funciones admitidas por el dispositivo y sin necesidad de una colección inmanejablemente grande de llamadas al sistema.
Usos
Configuración del dispositivo de hardware
Un uso común de ioctl
es controlar dispositivos de hardware.
Por ejemplo, en los sistemas Win32 , las ioctl
llamadas pueden comunicarse con dispositivos USB o pueden descubrir información sobre la geometría de la unidad de los dispositivos de almacenamiento conectados.
En OpenBSD y NetBSD , ioctl
el bio(4)
controlador de pseudodispositivo y la bioctl
utilidad lo utilizan para implementar la administración de volumen RAID en una interfaz unificada independiente del proveedor similar a ifconfig
. [1] [2]
En NetBSD , ioctl
también es utilizado por el sysmon
marco. [3]
Terminales
Un uso del ioctl
código expuesto a aplicaciones de usuario final es la E / S de terminal.
Los sistemas operativos Unix tradicionalmente han hecho un uso intensivo de las interfaces de línea de comandos . La interfaz de línea de comandos de Unix se basa en pseudo terminales (ptys), que emulan terminales de texto de hardware como los VT100 . Una pty se controla y configura como si fuera un dispositivo de hardware, mediante ioctl
llamadas. Por ejemplo, el tamaño de la ventana de un pty se establece mediante la TIOCSWINSZ
llamada. La función ioctl de TIOCSTI (control de E / S de terminal, simulación de entrada de terminal) puede insertar un carácter en un flujo de dispositivo. [4]
Extensiones de kernel
Cuando las aplicaciones necesitan extender el kernel, por ejemplo para acelerar el procesamiento de la red, las ioctl
llamadas proporcionan una forma conveniente de conectar el código del espacio de usuario con las extensiones del kernel. Las extensiones del kernel pueden proporcionar una ubicación en el sistema de archivos que se puede abrir por nombre, a través de la cual ioctl
se puede enviar una cantidad arbitraria de llamadas, lo que permite programar la extensión sin agregar llamadas al sistema al sistema operativo.
alternativa sysctl
Según un desarrollador de OpenBSD , ioctl
y sysctl
son las dos llamadas del sistema para extender el kernel, sysctl
posiblemente la más simple de las dos. [5]
En NetBSD , el sysmon_envsys
marco para el monitoreo de hardware utiliza a ioctl
través de proplib
; mientras que OpenBSD y DragonFly BSD utilizan sysctl
en su lugar para su hw.sensors
marco correspondiente . La revisión original de envsys
en NetBSD se implementó ioctl
antes de que proplib
estuviera disponible, y tenía un mensaje que sugería que el marco es experimental y debería ser reemplazado por una sysctl(8)
interfaz, en caso de que se desarrolle una, [6] [7] que potencialmente explica la elección de sysctl
en OpenBSD con su posterior introducción hw.sensors
en 2003. Sin embargo, cuando el envsys
marco fue rediseñado en 2007 proplib
, la llamada al sistema permaneció como ioctl
y el mensaje fue eliminado. [8]
Implementaciones
Unix
La ioctl
llamada al sistema apareció por primera vez en la versión 7 de Unix , con un nuevo nombre stty
. [9] Una ioctl
llamada toma como parámetros :
- un descriptor de archivo abierto
- un número de código de solicitud
- ya sea un valor entero, posiblemente sin firmar (yendo al controlador) o un puntero a los datos (ya sea yendo al controlador, regresando del controlador, o ambos).
El kernel generalmente envía una ioctl
llamada directamente al controlador del dispositivo, que puede interpretar el número de solicitud y los datos de la forma requerida. Los escritores de cada documento de controlador solicitan números para ese controlador en particular y los proporcionan como constantes en un archivo de encabezado .
Algunos sistemas Unix, incluido Linux , tienen convenciones que codifican dentro del número de solicitud el tamaño de los datos que se transferirán hacia / desde el controlador del dispositivo, la dirección de la transferencia de datos y la identidad del controlador que implementa la solicitud. Independientemente de si se sigue dicha convención, el núcleo y el controlador colaboran para entregar un código de error uniforme (indicado por la constante simbólica ENOTTY
) a una aplicación que realiza una solicitud a un controlador que no lo reconoce.
El mnemónico ENOTTY
(tradicionalmente asociado con el mensaje textual " No es una máquina de escribir ") deriva de los primeros sistemas que incorporaron una ioctl
llamada, donde solo el dispositivo teletipo ( tty
) generaba este error. Aunque el mnemotécnico simbólico está fijado por los requisitos de compatibilidad, algunos sistemas modernos presentan de forma más útil un mensaje más general como " Operación de control de dispositivo inapropiada " (o una localización del mismo).
TCSETS
ejemplifica una ioctl
llamada en un puerto serie . Las llamadas normales de lectura y escritura en un puerto serie reciben y envían bytes de datos. Una ioctl(fd,TCSETS,data)
llamada, separada de dicha E / S normal, controla varias opciones del controlador, como el manejo de caracteres especiales o las señales de salida en el puerto (como la señal DTR ).
Win32
Un Win32 DeviceIoControl
toma como parámetros:
- un identificador de objeto abierto (el equivalente Win32 de un descriptor de archivo)
- un número de código de solicitud (el "código de control")
- un búfer para parámetros de entrada
- longitud del búfer de entrada
- un búfer para los resultados de salida
- longitud del búfer de salida
- una
OVERLAPPED
estructura, si se utilizan E / S superpuestas .
El código de control del dispositivo Win32 tiene en cuenta el modo de operación que se está realizando.
Hay 4 modos de operación definidos, que afectan la seguridad del controlador del dispositivo:
METHOD_IN_DIRECT
: Se verifica que la dirección del búfer sea legible por el llamador en modo de usuario.METHOD_OUT_DIRECT
: El llamador del modo de usuario verifica que se pueda escribir en la dirección del búfer.METHOD_NEITHER
: Las direcciones virtuales del modo de usuario se pasan al controlador sin mapeo ni validación.METHOD_BUFFERED
: Los búferes compartidos controlados por IO Manager se utilizan para mover datos hacia y desde el modo de usuario.
Alternativas
Otras interfaces de llamadas vectorizadas
Los dispositivos y las extensiones del kernel pueden vincularse al espacio de usuario mediante nuevas llamadas al sistema adicionales, aunque este enfoque rara vez se adopta, porque los desarrolladores del sistema operativo intentan mantener la interfaz de llamadas del sistema enfocada y eficiente.
En los sistemas operativos Unix, otras dos interfaces de llamadas vectorizadas son populares: la fcntl
llamada al sistema ("control de archivos") configura archivos abiertos y se usa en situaciones tales como habilitar E / S sin bloqueo ; y la setsockopt
llamada al sistema ("establecer la opción de socket") configura los sockets de red abiertos , una función que se utiliza para configurar el ipfw
cortafuegos de paquetes en los sistemas BSD Unix .
Mapeo de memoria
- Unix
- Las interfaces del dispositivo y las capacidades de entrada / salida a veces se proporcionan mediante archivos mapeados en memoria . Las aplicaciones que interactúan con dispositivos abren una ubicación en el sistema de archivos correspondiente al dispositivo, como lo harían para una
ioctl
llamada, pero luego usan llamadas al sistema de mapeo de memoria para vincular una parte de su espacio de direcciones al del kernel. Esta interfaz es una forma mucho más eficiente de proporcionar transferencia de datos masiva entre un dispositivo y una aplicación de espacio de usuario ; Lasioctl
llamadas individuales o del sistema de lectura / escritura infligen gastos generales debido a las transiciones repetidas del espacio de usuario al kernel, donde el acceso a un rango de direcciones mapeado en memoria no incurre en tales gastos generales. - Win32
- Se pueden utilizar métodos de E / S en búfer o objetos de asignación de archivos con nombre; sin embargo, para controladores de dispositivos simples, los
DeviceIoControl METHOD_
accesos estándar son suficientes.
Netlink
Netlink es un mecanismo similar a un socket para la comunicación entre procesos (IPC), diseñado para ser un sucesor más flexible de ioctl
.
Trascendencia
Complejidad
ioctl
las llamadas minimizan la complejidad de la interfaz de llamadas al sistema del kernel. Sin embargo, al proporcionar un lugar para que los desarrolladores "escondan" bits y partes de las interfaces de programación del kernel, las ioctl
llamadas complican la API general de usuario a kernel. Un kernel que proporciona varios cientos de llamadas al sistema puede proporcionar varios miles de llamadas ioctl.
Aunque la interfaz para las ioctl
llamadas parece algo diferente de las llamadas al sistema convencionales, en la práctica hay poca diferencia entre una ioctl
llamada y una llamada al sistema; una ioctl
llamada es simplemente una llamada al sistema con un mecanismo de distribución diferente. Por lo tanto, muchos de los argumentos en contra de la expansión de la interfaz de llamadas al sistema del núcleo podrían aplicarse a las ioctl
interfaces.
Para los desarrolladores de aplicaciones, las llamadas al sistema no se diferencian de las subrutinas de la aplicación; son simplemente llamadas a funciones que toman argumentos y devuelven valores. Las bibliotecas de tiempo de ejecución del sistema operativo enmascaran la complejidad involucrada en la invocación de llamadas al sistema. Desafortunadamente, las bibliotecas en tiempo de ejecución no hacen ioctl
llamadas tan transparentes. Las operaciones simples, como descubrir las direcciones IP de una máquina, a menudo requieren un enredo de ioctl
llamadas, cada una de las cuales requiere números mágicos y estructuras de argumentos. [ cita requerida ]
Libpcap y libdnet son dos ejemplos de terceros envoltorio bibliotecas Unix diseñados para enmascarar la complejidad de ioctl
las interfaces, para la captura de paquetes y paquetes de E / S, respectivamente.
Seguridad
Las interfaces de usuario a kernel de los sistemas operativos principales a menudo se auditan en gran medida para detectar fallas de código y vulnerabilidades de seguridad antes de su lanzamiento. Estas auditorías suelen centrarse en las interfaces de llamadas del sistema bien documentadas; por ejemplo, los auditores pueden asegurarse de que las llamadas de seguridad sensibles, como el cambio de ID de usuario, solo estén disponibles para usuarios administrativos.
ioctl
Las interfaces son más complicadas, más diversas y, por lo tanto, más difíciles de auditar que las llamadas al sistema. Además, debido a que los desarrolladores ioctl
externos pueden proporcionar las llamadas, a menudo después de que se haya liberado el sistema operativo central, ioctl
las implementaciones de llamadas pueden recibir menos escrutinio y, por lo tanto, albergar más vulnerabilidades. Finalmente, muchas ioctl
llamadas, particularmente para controladores de dispositivos de terceros, no están documentadas.
Debido a que el controlador de una ioctl
llamada reside directamente en modo kernel, la entrada del espacio de usuario debe validarse con cuidado. Los usuarios locales pueden aprovechar las vulnerabilidades en los controladores de dispositivos pasando búferes no válidos a las ioctl
llamadas.
Los sistemas operativos Win32 y Unix pueden proteger el nombre de un dispositivo de espacio de usuario del acceso de aplicaciones con controles de acceso específicos aplicados al dispositivo. Pueden surgir problemas de seguridad cuando los desarrolladores de controladores de dispositivos no aplican los controles de acceso adecuados al objeto accesible del espacio de usuario .
Algunos sistemas operativos modernos protegen el kernel del código hostil del espacio de usuario (como las aplicaciones que han sido infectadas por vulnerabilidades de desbordamiento del búfer ) mediante envoltorios de llamadas del sistema . Los envoltorios de llamadas al sistema implementan el control de acceso basado en roles al especificar qué llamadas al sistema pueden ser invocadas por qué aplicaciones; Los contenedores se pueden utilizar, por ejemplo, para "revocar" el derecho de un programa de correo a generar otros programas. ioctl
Las interfaces complican los envoltorios de llamadas al sistema porque hay un gran número de ellos, cada uno con argumentos diferentes, algunos de los cuales pueden ser requeridos por programas normales.
Otras lecturas
- W. Richard Stevens , Programación avanzada en el entorno UNIX (Addison-Wesley, 1992, ISBN 0-201-56317-7 ), sección 3.14.
- Operaciones genéricas de control de E / S en el manual en línea de la biblioteca GNU C
- - Versión 7 del manual del programador de Unix
- - Manual del programador de Linux - Llamadas al sistema
- - Manual de llamadas al sistema FreeBSD
- - Manual de llamadas al sistema OpenBSD
- - Manual de referencia de llamadas al sistema Solaris 10
- "Documentación de DeviceIoControl en Microsoft Developer Network
Referencias
- ^ Niklas Hallqvist (2002); Marco Peereboom (2006). "bio (4) - pseudodispositivo de túnel ioctl de E / S de bloque" . Referencia cruzada BSD . OpenBSD . Lay resumen .
- ^ Marco Peereboom (2005). "bioctl (8) - interfaz de gestión RAID" . Referencia cruzada BSD . OpenBSD . Lay resumen .
- ^ "sysmon (4) - interfaz de administración de energía y monitoreo del sistema" . NetBSD .
Una interfaz ioctl (2) disponible a través de / dev / sysmon.
- ^ Christiansen, Tom ; Torkington, Nathan (1998). "12: Paquetes, Bibliotecas y Módulos". Libro de recetas de Perl: Soluciones y ejemplos para programadores de Perl (2 ed.). Sebastopol, California: O'Reilly Media, Inc. (publicado en 2003). pag. 482. ISBN 9780596554965. Consultado el 15 de noviembre de 2016 .
[...] TIOCSTI [...] significa 'control de E / S de terminal, simular entrada de terminal'. En los sistemas que implementan esta función, insertará un carácter en el flujo de su dispositivo para que la próxima vez que cualquier proceso lea desde ese dispositivo, obtenga el carácter que puso allí.
- ^ Federico Biancuzzi (28 de octubre de 2004). "OpenBSD 3.6 Live" . ONLamp . O'Reilly Media . Consultado el 20 de marzo de 2019 .
Hay dos llamadas al sistema que se pueden usar para agregar funcionalidad al kernel (sin agregar otra llamada al sistema): ioctl (2) y sysctl (3). Se eligió este último porque era muy sencillo implementar la nueva función.
- ^ Tim Rightnour; Bill Squier (19 de diciembre de 2007). "envsys - API de sistemas ambientales" . NetBSD 4.0.
Esta API es experimental y puede quedar obsoleta en cualquier momento ... Toda esta API debe ser reemplazada por una interfaz sysctl (8) o un mecanismo de eventos del kernel, si se desarrolla uno.
- ^ Constantine A. Murenin (17 de abril de 2007). "3.5. Sysmon de NetBSD (4)". Interfaz generalizada con monitores de hardware del sistema de microprocesador . Actas de la Conferencia Internacional IEEE de 2007 sobre redes, detección y control, 15-17 de abril de 2007. Londres, Reino Unido: IEEE . págs. 901–906. doi : 10.1109 / ICNSC.2007.372901 . ISBN 978-1-4244-1076-7. IEEE ICNSC 2007, págs. 901—906.
- ^ Constantine A. Murenin (21 de mayo de 2010). "6.1. Cronograma del marco; 7.1. NetBSD envsys / sysmon". Sensores de hardware OpenBSD - Monitoreo ambiental y control de ventiladores ( tesis MMath ). Universidad de Waterloo : UWSpace. hdl : 10012/5234 . ID de documento: ab71498b6b1a60 ff817 b29d56997a418.
- ^ McIlroy, MD (1987). Un lector de investigación Unix: extractos comentados del Manual del programador, 1971–1986 (PDF) (Informe técnico). CSTR. Bell Labs. 139.