Программирование в Linux: Linux Kernel Modules #3: адресное пространство (исходники)Источник: CodingClub
Если до этого момента для понимания написанного почти ничего знать не нужно было, то теперь необходимы хотя бы базовые знания архитектуры операционной системы. Давайте проанализируем наш модуль, а точнее его работу в ядре. Так как модуль меняет оригинальную функцию open на my_sys_open, то и анализировать мы будем эту функцию. Представьте себе ситуацию: обычный пользователь пытается открыть файл. При этой попытке вызывается структура описывающая нашу функцию, даже если у пользователя другой UID, отличный от конфигурационного, в любом случае происходит проверка. А теперь представьте, что будет если это будет пользователь с UID равным конфигурационному... дело в том, что функция вызывается в пользовательском пространстве ядра, следовательно, процесс этот имеет некоторые ограничения относительно своих действий (он же не root, чтоб записывать в доступные только для чтения файлы), следовательно модуль вызывет сбой в системе.
Вторым способом может послужить передача данных из пользовательского адресного пространства в пространство ядра. Для этого существует функция
При помощи этой функции можно переносить любые данные, следовательно, воспользовавшись этой функцией, мы могли бы перенести дескриптор файла в "наше" пространство и творить уже от имени ядра все, что может root. Это то, что касается переноса "в сторону ядра". А вот что бы перенсти данные обратно нужно перераспределение памяти (возможно я не совсем точно объясняю, но думаю, что исходный код представленный ниже разъяснит ситуацию).
где *to - пользовательское пространство. Дело в том, что напрямую из ядра мы не можем изменить размер памяти, отведенный пользователю для его нужд, поэтому, часто используется следующий трюк (предложен журналом Phrack):
Рассмотрим подробнее. Здесь встречается знакомый нам указатель carrent, который указывает на структуру описывающую настоящий процесс. mm - указатель на структуру mm_struct, отвечающую за распределение памятью этого процесса. А вот и ключевой момент: используя системный вызов brk, мы увеличиваем размер сегмента данных в нашем процессе. Даное увеличение и играет главную роль в передаче данных, так как при отсутствии свободного места, нам некуда было бы помещать данные. |