ioctl - ioctl


В вычислении , ioctl(аббревиатура от контроля ввода / вывода ) представляет собой системный вызов для конкретного устройства ввода / вывода операций и других операций , которые не могут быть выражены с помощью обычных системных вызовов. Требуется параметр, указывающий код запроса; эффект вызова полностью зависит от кода запроса. Коды запросов часто зависят от устройства. Например, драйвер устройства CD-ROM, который может дать указание физическому устройству извлечь диск, предоставит для этого ioctlкод запроса. Коды запросов, не зависящие от устройства, иногда используются для предоставления пользовательскому пространству доступа к функциям ядра, которые используются только основным системным программным обеспечением или все еще находятся в стадии разработки.

ioctlСистемный вызов впервые появился в версии 7 в Unix под этим именем. Он поддерживается большинством Unix и Unix-подобных систем, включая Linux и macOS , хотя доступные коды запросов различаются от системы к системе. Microsoft Windows предоставляет аналогичную функцию под названием " DeviceIoControl" в своем Win32 API .

Фон

Обычные операционные системы можно разделить на два уровня: пользовательское пространство и ядро . Код приложения, такой как текстовый редактор, находится в пользовательском пространстве , в то время как основные средства операционной системы, такие как сетевой стек , находятся в ядре. Код ядра обрабатывает конфиденциальные ресурсы и реализует барьеры безопасности и надежности между приложениями; по этой причине операционная система не позволяет приложениям пользовательского режима напрямую обращаться к ресурсам ядра.

Приложения пользовательского пространства обычно обращаются к ядру с помощью системных вызовов , код которых находится на уровне ядра. Системный вызов обычно принимает форму «вектора системного вызова», в котором желаемый системный вызов обозначается порядковым номером. Например, это exit()может быть системный вызов номер 1 и write()номер 4. Затем вектор системного вызова используется для поиска нужной функции ядра для запроса. Таким образом, обычные операционные системы обычно предоставляют несколько сотен системных вызовов пользовательскому пространству.

Хотя это целесообразный дизайн для доступа к стандартным средствам ядра, системные вызовы иногда не подходят для доступа к нестандартным периферийным устройствам. По необходимости, большинство аппаратных периферийных устройств (также называемых устройствами) имеют прямую адресацию только внутри ядра. Но пользовательскому коду может потребоваться прямая связь с устройствами; например, администратор может настроить тип носителя на интерфейсе Ethernet . Современные операционные системы поддерживают различные устройства, многие из которых предлагают большой набор функций. Некоторые из этих возможностей могут быть не предусмотрены разработчиком ядра, и, как следствие, ядру трудно обеспечить системные вызовы для использования устройств.

Чтобы решить эту проблему, ядро ​​разработано с возможностью расширения и может принимать дополнительный модуль, называемый драйвером устройства, который работает в пространстве ядра и может напрямую обращаться к устройству. ioctlИнтерфейс представляет собой единую систему вызова , с помощью которого пользовательское может взаимодействовать с драйверами устройств. Запросы к драйверу устройства направляются относительно этого ioctlсистемного вызова, обычно с помощью дескриптора устройства и номера запроса. Таким образом, базовое ядро ​​может позволить пользовательскому пространству получить доступ к драйверу устройства, ничего не зная о средствах, поддерживаемых устройством, и без необходимости в неуправляемом большом наборе системных вызовов.

Использует

Конфигурация аппаратного устройства

Обычно используется ioctlдля управления аппаратными устройствами.

Например, в системах Win32ioctl вызовы могут обмениваться данными с USB- устройствами или обнаруживать информацию о геометрии дисков подключенных запоминающих устройств.

На OpenBSD и NetBSD , ioctlиспользуются bio(4)драйвером псевдо-устройство и bioctlутилиты для реализации RAID управления тома в едином поставщике агностика интерфейс , похожем на ifconfig.

В NetBSD , ioctlтакже используется в sysmonрамках.

Терминалы

Одним из вариантов использования ioctlкода, доступного для приложений конечного пользователя, является терминальный ввод-вывод.

В операционных системах Unix традиционно широко используются интерфейсы командной строки . Интерфейс командной строки Unix построен на псевдотерминалах (ptys), которые имитируют аппаратные текстовые терминалы, такие как VT100 . Pty управляется и настраивается, как если бы это было аппаратное устройство, с помощью ioctlвызовов. Например, размер окна pty устанавливается с помощью TIOCSWINSZвызова. Функция ioctl TIOCSTI (управление вводом-выводом терминала, имитация ввода-вывода терминала) может помещать символ в поток устройства.

Расширения ядра

Когда приложениям необходимо расширить ядро, например, для ускорения сетевой обработки, ioctlвызовы предоставляют удобный способ связать код пользовательского пространства с расширениями ядра. Расширения ядра могут предоставить место в файловой системе, которое можно открыть по имени, через которое ioctlможет быть отправлено произвольное количество вызовов, что позволяет программировать расширение без добавления системных вызовов в операционную систему.

альтернатива sysctl

Согласно OpenBSD разработчика, ioctlи sysctlявляются два системных вызова для расширения ядра, с , sysctlвозможно , является более простым из двух.

В NetBSD , то sysmon_envsysоснова для аппаратного мониторинга использования ioctlчерез proplib; тогда как OpenBSD и DragonFly BSD вместо этого используют sysctlдля своих соответствующих hw.sensorsфреймворков. Первоначальная версия envsysNetBSD была реализована ioctlдо того, как proplibбыла доступна, и содержала сообщение о том, что структура является экспериментальной и должна быть заменена sysctl(8)интерфейсом, если он будет разработан, что потенциально объясняет выбор sysctlв OpenBSD с последующим введением hw.sensorsв 2003 году. Однако, когда envsysв 2007 году структура была переработана proplib, системный вызов остался как ioctl, а сообщение было удалено.

Реализации

Unix

ioctlСистемный вызов впервые появился в версии 7 Unix , как переименовали stty. ioctlВызов принимает в качестве параметров :

  1. дескриптор открытого файла
  2. номер кода запроса
  3. либо целочисленное значение, возможно, без знака (переход к драйверу), либо указатель на данные (либо переход к драйверу, возвращение от драйвера, либо оба).

Ядро обычно отправляет ioctlпрямой вызов драйвер устройства, который может истолковать номер запроса и данные любого способа требуется. Авторы каждого документа драйвера запрашивают номера для этого конкретного драйвера и предоставляют их в виде констант в файле заголовка .

Некоторые системы Unix, включая Linux , имеют соглашения, которые кодируют в номере запроса размер данных, которые должны быть переданы в / из драйвера устройства, направление передачи данных и идентификатор драйвера, реализующего запрос. Независимо от того, соблюдается ли такое соглашение, ядро ​​и драйвер взаимодействуют, чтобы доставить единый код ошибки (обозначенный символической константой ENOTTY) приложению, которое делает запрос к драйверу, который его не распознает.

Мнемоника ENOTTY(традиционно связанная с текстовым сообщением « Не пишущая машинка ») происходит от самых ранних систем, которые включали ioctlвызов, где только устройство teletype ( tty) вызывало эту ошибку. Хотя символическая мнемоника фиксируется требованиями совместимости, некоторые современные системы более эффективно отображают более общее сообщение, такое как « Несоответствующая операция управления устройством » (или его локализация ).

TCSETSиллюстрирует ioctlвызов через последовательный порт . Обычные вызовы чтения и записи через последовательный порт принимают и отправляют байты данных. ioctl(fd,TCSETS,data)Вызова, отдельно от такого нормального ввода / вывода, управлений различными вариантов драйверов , таких как обработка специальных символов , или выходных сигналов на порт (например, DTR сигнала).

Win32

Win32 DeviceIoControlпринимает в качестве параметров:

  1. дескриптор открытого объекта (эквивалент дескриптора файла в Win32)
  2. номер кода запроса («контрольный код»)
  3. буфер для входных параметров
  4. длина входного буфера
  5. буфер для результатов вывода
  6. длина выходного буфера
  7. OVERLAPPEDструктура, если перекрытый ввод / вывод используется.

Управляющий код устройства Win32 учитывает режим выполняемой операции.

Существует 4 определенных режима работы, влияющих на безопасность драйвера устройства:

  1. METHOD_IN_DIRECT: Адрес буфера проверяется на возможность чтения вызывающей стороной пользовательского режима.
  2. METHOD_OUT_DIRECT: Адрес буфера проверяется на возможность записи вызывающей стороной пользовательского режима.
  3. METHOD_NEITHER: Виртуальные адреса пользовательского режима передаются драйверу без сопоставления или проверки.
  4. METHOD_BUFFERED: Управляемые диспетчером ввода-вывода разделяемые буферы используются для перемещения данных в пользовательский режим и из него.

Альтернативы

Другие интерфейсы векторных вызовов

Устройства и расширения ядра могут быть связаны с пользовательским пространством с помощью дополнительных новых системных вызовов, хотя этот подход применяется редко, потому что разработчики операционной системы стараются сохранить сфокусированный и эффективный интерфейс системных вызовов.

В операционных системах Unix популярны два других интерфейса векторных вызовов: fcntlсистемный вызов («управление файлами») настраивает открытые файлы и используется в таких ситуациях, как включение неблокирующего ввода-вывода ; а setsockoptсистемный вызов ("установить параметр сокета") настраивает открытые сетевые сокеты , средство, используемое для настройки ipfwмежсетевого экрана пакетов в системах BSD Unix .

Отображение памяти

Unix
Интерфейсы устройств и возможности ввода / вывода иногда предоставляются с помощью файлов с отображением в памяти . Приложения, которые взаимодействуют с устройствами, открывают место в файловой системе, соответствующее устройству, как и для ioctlвызова, но затем используют системные вызовы отображения памяти, чтобы связать часть своего адресного пространства с адресным пространством ядра. Этот интерфейс - гораздо более эффективный способ обеспечить массовую передачу данных между устройством и приложением пользовательского пространства ; отдельные ioctlсистемные вызовы или системные вызовы чтения / записи вызывают накладные расходы из-за повторяющихся переходов из пользовательского пространства в ядро, когда доступ к диапазону адресов, отображаемых в памяти, не вызывает таких накладных расходов.
Win32
Могут использоваться буферизованные методы ввода-вывода или именованные объекты сопоставления файлов; однако для простых драйверов устройств DeviceIoControl METHOD_достаточно стандартного доступа.

Netlink

Netlink - это механизм, подобный сокету, для межпроцессного взаимодействия (IPC), призванный стать более гибким преемником ioctl.

Подразумеваемое

Сложность

ioctlвызовы минимизируют сложность интерфейса системных вызовов ядра. Однако, предоставляя разработчикам место для «спрятать» кусочки и части программных интерфейсов ядра, ioctlвызовы усложняют общий API- интерфейс взаимодействия пользователя с ядром. Ядро, которое предоставляет несколько сотен системных вызовов, может обеспечивать несколько тысяч вызовов ioctl.

Хотя интерфейс ioctlвызовов несколько отличается от обычных системных вызовов, на практике разница между ioctlвызовом и системным вызовом незначительна ; ioctlвызов просто системный вызов с другим механизмом координирования. Поэтому многие аргументы против расширения интерфейса системного вызова ядра могут быть применены к ioctlинтерфейсам.

Для разработчиков приложений системные вызовы не отличаются от подпрограмм приложения; это просто вызовы функций, которые принимают аргументы и возвращают значения. Библиотеки времени выполнения ОС маскируют сложность, связанную с вызовом системных вызовов. К сожалению, библиотеки времени выполнения не делают ioctlвызовы такими прозрачными. Простые операции, такие как обнаружение IP-адресов для машины, часто требуют запутанных ioctlвызовов, каждый из которых требует магических чисел и структур аргументов.

Libpcap и libdnet - это два примера сторонних библиотек- оболочек Unix, предназначенных для маскировки сложности ioctlинтерфейсов для захвата пакетов и ввода-вывода пакетов соответственно.

Безопасность

Интерфейсы «пользователь-ядро» в основных операционных системах перед выпуском часто подвергаются тщательному аудиту на предмет недостатков кода и уязвимостей безопасности. Эти аудиты обычно сосредоточены на хорошо задокументированных интерфейсах системных вызовов; например, аудиторы могут гарантировать, что конфиденциальные вызовы безопасности, такие как изменение идентификаторов пользователей, доступны только администраторам.

ioctlинтерфейсы сложнее, разнообразнее и, следовательно, их труднее контролировать, чем системные вызовы. Более того, поскольку ioctlвызовы могут быть предоставлены сторонними разработчиками, часто после выпуска основной операционной системы, ioctlреализации вызовов могут подвергаться меньшей проверке и, таким образом, содержать больше уязвимостей. Наконец, многие ioctlвызовы, особенно для сторонних драйверов устройств, не документированы.

Поскольку обработчик ioctlвызова находится непосредственно в режиме ядра, ввод из пользовательского пространства следует тщательно проверять. Уязвимости в драйверах устройств могут использоваться локальными пользователями, передавая ioctlвызовам недопустимые буферы .

Операционные системы Win32 и Unix могут защищать имя устройства в пользовательском пространстве от доступа приложений с помощью специальных средств управления доступом, применяемых к устройству. Проблемы безопасности могут возникнуть, когда разработчики драйверов устройств не применяют соответствующие средства управления доступом к доступному объекту пользовательского пространства .

Некоторые современные операционные системы защищают ядро ​​от враждебного кода пользовательского пространства (например, приложений, которые были заражены эксплойтами из- за переполнения буфера ) с помощью оболочек системных вызовов . Оболочки системных вызовов реализуют управление доступом на основе ролей , указывая, какие системные вызовы могут быть вызваны какими приложениями; Оболочки могут, например, использоваться для «отзыва» права почтовой программы порождать другие программы. ioctlИнтерфейсы усложняют обертки системных вызовов, потому что их большое количество, каждая из которых принимает разные аргументы, некоторые из которых могут потребоваться для обычных программ.

дальнейшее чтение

  • W. Ричард Стивенс , Расширенное программирование в среде UNIX (Addison-Wesley, 1992, ISBN  0-201-56317-7 ), раздел 3.14.
  • Общие операции управления вводом-выводом в онлайн-руководстве для библиотеки GNU C
  • ioctl(2) -  Руководство программиста Unix версии 7
  • ioctl(2) -  Руководство программиста Linux - Системные вызовы
  • ioctl(2) -  Руководство по системным вызовам FreeBSD
  • ioctl(2) -  Руководство по системным вызовам OpenBSD
  • ioctl(2) -  Справочное руководство по системным вызовам Solaris 10
  • "Документация по DeviceIoControl в сети разработчиков Microsoft.

использованная литература