Linux Kernel (Ядро линукса) (часть 2)


Проверка параметров

Все параметры системного вызова должны быть тщательно проверены, прежде чем ядро попытается удовлетворить запрос. Вид проверки зависит как от системного вызова, так и от конкретного параметра. Вернемся к системному вызову write , о котором мы говорили в предыдущем разделе. Параметр fd должен представлять собой дескриптор файла и идентифицировать конкретный файл, поэтому функция sys writeo проверяет, действительно ли fd является дескриптором уже открытого файла, и разрешено ли процессу записывать в него данные. Если хотя бы одно из этих условий не выполнено, функция должна возвратить отрицательное значение, в данном случае — код ошибки -ebadf.

Впрочем, одна проверка является общей для всех системных вызовов. Если в параметре задается адрес, ядро должно проверить, входит ли он в адресное пространство процесса.

Существуют два способа проведения этой проверки:

- убедиться, что линейный адрес принадлежит адресному пространству процесса, и, если это действительно так, что у содержащей его области памяти имеются соответствующие права доступа;
- убедиться, что линейный адрес меньше значения page offset (то есть что он не попадает в диапазон адресов, зарезервированных для ядра).
В ранних версиях ядра Linux выполнялась проверка первого типа. Однако она требует много времени, поскольку проводится для каждого параметра с
адресом, переданного системному вызову. Кроме того, в ней обычно нет смысла, поскольку программы с такими ошибками встречаются не очень часто.
Поэтому, начиная с версии 2.2, Linux выполняет проверку второго типа. Она намного эффективнее, потому что не требует перебора дескрипторов областей памяти процесса. Очевидно, что это очень грубая проверка: требование, чтобы линейный адрес был меньше, чем page offset, является необходимым, но не достаточным условием его допустимости. Однако, ограничиваясь этой грубой проверкой, ядро ничем не рискует, поскольку другие ошибки будут выловлены позже.

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

У читателя может возникнуть вопрос: а зачем вообще проводится эта грубая проверка. Такой тип проверки, на самом деле, исключительно важен для защиты адресных пространств ядра от несанкционированного доступа. В главе 2 мы видели, что оперативная память отображается, начиная с page offset. Это означает, что процедуры ядра могут обращаться ко всем страницам, присутствующим в памяти. Следовательно, если бы грубая проверка не производилась, процесс режима пользователя мог бы передать в качестве параметра адрес, принадлежащий адресному пространству ядра. Это позволило бы процессу читать или записывать в любую страницу, находящуюся в памяти, не вызывая исключения ошибка обращения к странице”.
Проверка адресов, передаваемых системным вызовам, выполняется макросом access ok о, который принимает два параметра: addr и size. Макрос проверяет интервал адресов между addr и addr + size - 1. Он фактически эквивалентен следующей функции:
int access_ok(const void addr, unsigned long size)
{
unsigned long a = (unsigned long) addr; if (a + size current_thread_info()->addr_limit.seg) return 0; return 1;
}
Эта функция вначале проверяет, превышает ли сумма addr + size (то есть максимальный адрес) значение 232-1. Поскольку длинные целые без знака и
указатели представлены в компиляторе GNU С (дсс) в виде 32-битовых чисел, такая проверка равносильна проверке на переполнение. Кроме того, функция проверяет, превышает ли сумма addr + size значение, хранящееся в поле addr iimit.seg структуры thread info процесса current. Обычно это поле содержит значение page offset для нормальных процессов и Oxf f f f f f f f для потоков ядра. Значение в поле addr iimit.seg может быть динамически изменено макросами get fs и set fs, что позволяет ядру обходить проверки, выполняемые макросом access oko в целях безопасности, и обращаться к служебным процедурам системных вызовов, напрямую передавая им адреса в сегменте данных ядра.

Функция verif у агеа Делает ту же проверку, ЧТО и макрос access_ok . Хотя она и считается морально устаревшей, она по-прежнему часто встречается в исходном коде.

Предыдущая страница | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | Следующая страница




Возможно, Вас также заинтересует:

ОС Knoppix - это Linux без про...

ВведениеЕсли вы цените свое время, умеете считать деньги и знаете стоимость информации, то эта книга...

Linux Kernel (Ядро линукса) (ч...

Спин-блокировкаСпин-блокировка необходима в многопроцессорной системе, потому что могут возникнуть...

Linux Kernel (Ядро линукса) (ч...

Копирование при записи В системах Unix первых поколений создание процесса было реализовано довольно...

Linux Kernel (Ядро линукса) (ч...

Буферы блоков и головы буферовУ каждого буфера есть дескриптор голова буфера, имеющий тип buffer...