Шлюз вызовов — это механизм в архитектуре Intel x86 для изменения уровня привилегий процесса, когда он выполняет предопределенный вызов функции с помощью инструкции CALL FAR.
Шлюзы вызовов предназначены для того, чтобы позволить менее привилегированному коду вызывать код с более высоким уровнем привилегий. Этот тип механизма необходим в современных операционных системах, которые используют защиту памяти , поскольку он позволяет пользовательским приложениям использовать функции ядра и системные вызовы таким образом, что операционная система может это контролировать .
Шлюзы вызовов используют специальное значение селектора для ссылки на дескриптор, доступ к которому осуществляется через таблицу глобальных дескрипторов или локальную таблицу дескрипторов , содержащую информацию, необходимую для вызова через границы привилегий. Это похоже на механизм, используемый для прерываний .
Предполагая, что вызов шлюза уже был настроен ядром операционной системы , код просто выполняет CALL FAR с необходимым селектором сегмента (поле смещения игнорируется). Процессор выполнит ряд проверок, чтобы убедиться, что запись действительна и код работал с достаточными привилегиями для использования шлюза. Предполагая, что все проверки пройдены, новый CS/ EIP загружается из дескриптора сегмента , и информация о продолжении помещается в стек нового уровня привилегий (старый SS, старый ESP, старый CS, старый EIP, в таком порядке). Параметры также могут быть скопированы из старого стека в новый, если это необходимо. Количество параметров для копирования находится в дескрипторе вызова шлюза.
Ядро может вернуться в программу пользовательского пространства, используя инструкцию RET FAR, которая извлекает информацию о продолжении из стека и возвращается на внешний уровень привилегий.
typedef struct _CALL_GATE { USHORT OffsetLow ; USHORT Selector ; UCHAR NumberOfArguments : 5 ; UCHAR Reserved : 3 ; UCHAR Type : 5 ; // 01100 в i386, 00100 в i286 UCHAR Dpl : 2 ; UCHAR Present : 1 ; USHORT OffsetHigh ; } CALL_GATE , * PCALL_GATE ;
Multics был первым пользователем call gates. Honeywell 6180 имел call gates как часть архитектуры, но Multics имитировал их на более старом GE 645 .
OS/2 была одним из первых пользователей шлюзов вызовов Intel для передачи данных между кодом приложения, работающим в кольце 3, привилегированным кодом, работающим в кольце 2, и кодом ядра в кольце 0.
Windows 95 выполняет драйверы и переключение процессов в кольце 0, в то время как приложения, включая API DLL, такие как kernel32.dll и krnl386.exe, выполняются в кольце 3. Драйвер VWIN32.VXD предоставляет основные примитивы операционной системы в кольце 0. Он позволяет вызывать функции драйвера из 16-разрядных приложений (MSDOS и Win16). Этот адрес получается путем вызова INT 2Fh с 1684h в регистре AX. Чтобы определить, для какого VxD запрашивается точка входа, регистр BX устанавливается на 16-разрядный идентификатор VxD. После возврата из инструкции INT регистры ES.DI содержат дальний указатель, который может быть вызван для передачи управления VxD, работающему в кольце 0. Дескриптор, на который указывает ES, на самом деле является шлюзом вызова. [1] Однако 32-разрядные приложения, когда им требуется доступ к коду драйвера Windows 95, вызывают недокументированную функцию VxDCall в KERNEL32.DLL, которая по сути вызывает INT 30h, что изменяет режим звонка.
Современные операционные системы x86 переходят от вызовов CALL FAR. С введением инструкций x86 для системных вызовов (SYSENTER/SYSEXIT от Intel и SYSCALL/SYSRET от AMD) был представлен новый более быстрый механизм для передачи управления для программ x86. Поскольку большинство других архитектур не поддерживают вызовы, их использование было редким даже до появления этих новых инструкций, поскольку программные прерывания или ловушки были предпочтительны для переносимости, хотя вызовы значительно быстрее прерываний.
Шлюзы вызовов более гибкие, чем инструкции SYSENTER/SYSEXIT и SYSCALL/SYSRET, поскольку в отличие от последних двух, шлюзы вызовов позволяют изменять произвольный уровень привилегий на произвольный (хотя и более высокий или равный) уровень привилегий. Быстрые инструкции SYS* позволяют только передавать управление с кольца 3 на 0 и наоборот.
Для сохранения безопасности системы глобальная таблица дескрипторов должна храниться в защищенной памяти, в противном случае любая программа сможет создать свой собственный шлюз вызовов и использовать его для повышения своего уровня привилегий. Шлюзы вызовов использовались в эксплойтах безопасности программного обеспечения , когда были найдены способы обойти эту защиту. [2] Одним из примеров этого является почтовый червь Gurong.A , написанный для эксплуатации операционной системы Microsoft Windows , которая использует \Device\PhysicalMemory для установки шлюза вызовов. [3]