Кафедра ПО ЭВМ и информационные технологии
Курсовая Работа
На тему: Мониторинг системных вызовов создания, обращения и удаления сегментов разделяемой памяти в ОС Linux
Содержание
1. Введение
2. Аналитическая часть
2.1. Архитектура ОС Linux
2.2. Перехват и мониторинг системных вызовов
2.3. Средства IPC. Системный вызов sys_ipc
2.4. Разделяемая память (SharedMemory)
2.5. Системные вызовы shmget, shmat, shmctl, shmdt
3. Конструкторская часть
3.1. Технические требования к системе. Перекомпиляция ядра
3.2. Написание и внедрение модуля ядра
3.3. Выбор языка программирования
3.4. Структура программного обеспечения
3.5. Структуры данных
3.6. Реализация мониторинга создания, управления и удаления сегментов разделяемой памяти
3.7. Пользовательский интерфейс
4. Заключение
Список используемой литературы
1. Введение
С развитием операционных систем и увеличением сложности программ появилась необходимость в обмене данными между процессами. Именно поэтому в операционную систему сейчас встраивается множество механизмов, которые обеспечивают так называемый Interproccess Communication (IPC), то есть межпроцессное взаимодействие.
Одной из самых распространённых операционных систем на данный момент является ОС Linux, которая представляет собой интерактивную систему с открытым кодом, разработанную для одновременной поддержки нескольких процессов и нескольких пользователей. Традиционный подход ОС семейства Unix заключается в том, чтобы позволить многопроцессорным системам запускать приложения в отдельных процессах для сокращения времени, требуемого на выполнение специфических задач. Средства IPC позволяют избежать создания огромных программ с большим количеством функций, а заменить их набором отдельных, малых приложений, способных обмениваться данными между собой.
ОС Linux относится к стандарту UnixSystemV, который поддерживает три вида IPC-объектов:
· Очереди сообщений, которые представляют собой связный список в адресном пространстве ядра. Сообщения могут посылаться в очередь по порядку и доставаться из очереди несколькими разными путями.
· Семафоры – счетчики, управляющие доступом к общим ресурсам. Чаще всего они используются как блокирующий механизм, не позволяющий одному процессу захватить ресурс, пока этим ресурсом пользуется другой.
· Разделяемая память – средство, обеспечивающее возможность наличия общей памяти у нескольких процессов.
Механизм взаимодействия, основанный на сегментах SharedMemory, является более быстрым, чем очереди сообщений и семафоры. Здесь нет никакого посредничества в виде каналов, очередей сообщений и т.п., что значительно упрощает этот механизм. Поэтому данный курсовой проект посвящён именно этому типу межпроцессного взаимодействия.
Мониторинг создания, удаления сегментов разделяемой памяти и обращения к ним позволяет проследить, какой пользователь имеет дело с объектами SharedMemory и получить информацию о том, сегмент какого размера и для каких целей запрашивается, по какому адресу он находится в виртуальной памяти и т.д.
2. Аналитическая часть
2.1 Краткий обзор архитектуры ОС Linux
Чтобы понять принцип работы программы мониторинга, для начала следует кратко рассмотреть архитектуру данной операционной системы. Linux, как операционную систему семейства UNIX, можно рассматривать в виде пирамиды, у основания которой располагается аппаратное обеспечение, состоящее из центрального процессора, памяти, дисков, терминалов и других устройств (рис. 1). Функции самой ОС заключаются в управлении аппаратным обеспечением и предоставлении всем программам интерфейса системных вызовов, позволяющего создавать процессы, файлы и прочие ресурсы и управлять ими.
Рис. 1. Структура ОС UNIX
Программы обращаются к системным вызовам, помещая аргументы в регистры центрального процессора и выполняя команду эмулированного прерывания для переключения из пользовательского режима в режим ядра и передачи управления операционной системе. Стандарт POSIX определяет библиотечные процедуры, соответствующие системным вызовам, их параметры, что они должны делать и какой результат возвращать.
Таким образом, взаимодействие с ядром происходит посредством стандартного интерфейса системных вызовов, который представляет собой набор услуг ядра и определяет формат запросов на услуги. Фактически, это набор функций, реализованных в ядре ОС. Процесс запрашивает услугу посредством системного вызова определенной процедуры ядра, внешне похожего на обычный вызов библиотечной функции. Ядро от имени процесса выполняет запрос и возвращает процессу необходимые данные. Любой запрос приложения пользователя в конечном итоге трансформируется в системный вызов, который выполняет запрашиваемое действие.
Прежде чем реализовать перехват какого-либо системного вызова, нужно подробнее рассмотреть механизм системных вызовов.
Точка перехода в ядре, называется system_call. Процедура, которая там находится, проверяет номер системного вызова, который сообщает ядру, какую именно услугу запрашивает процесс. Затем, она просматривает таблицу системных вызовов (sys_call_table) отыскивает адрес функции ядра, которую следует вызвать, после чего вызывается нужная функция. По окончании работы системного вызова, выполняется ряд дополнительных проверок и лишь после этого управление возвращается вызывающему процессу (или другому процессу, если вызывающий процесс исчерпал свой квант времени).
2.2 Перехват и мониторинг системных вызовов
Перехват системных вызовов можно осуществить следующими способами:
· методом прямого доступа к адресному пространству ядра
· с помощью загружаемого модуля ядра
Прямой доступ к адресному пространству ядра обеспечивает файл устройства /dev/kmem. В этом файле отображено все доступное виртуальное адресное пространство. Для работы с файлом kmem используются стандартные системные функции - open(), read(), write(). Открыв стандартным способом /dev/kmem, мы можем обратиться к любому адресу в системе, задав его как смещение в этом файле.
Обращение к системным функциям осуществляется посредством загрузки параметров функции в регистры процессора и последующим вызовом программного прерывания 0x80. Обработчик этого прерывания, функция system_call, помещает параметры вызова в стек, извлекает из таблицы sys_call_table адрес вызываемой системной функции и передает управление по этому адресу.
Имея полный доступ к адресному пространству ядра, мы можем получить все содержимое таблицы системных вызовов, т.е. адреса всех системных функций. Изменив адрес любого системного вызова, мы, тем самым, осуществим его перехват. Но для этого необходимо знать адрес таблицы, или, другими словами, смещение в файле /dev/kmem, по которому эта таблица расположена.
Для вычисления адреса функции system_call из таблицы IDT необходимо извлечь шлюз прерывания int $0x80, а из него - адрес соответствующего обработчика, т.е. адрес функции system_call. Найдя сигнатуру этой команды в файле /dev/kmem, мы найдем и адрес таблицы системных вызовов.
Но мы работает в адресном пространстве пользователя, а новый системный вызов необходимо разместить в адресном пространстве ядра. Для этого необходимо получить блок памяти в пространстве ядра и разместить в этом блоке новый системный вызов.
Выделить память в пространстве ядра можно при помощи функции kmalloc. Но вызвать напрямую функцию ядра из адресного пространства пользователя нельзя, поэтому для этого используется специальный алгоритм, в результате которого в нашем распоряжении будет блок памяти, расположенный в пространстве ядра.
Нетрудно заметить, что данный механизм довольно трудоёмок, поэтому на практике часто используется другой метод.
Перехват системных вызовов реализуется посредством механизма загружаемого модуля ядра (общепринятое сокращение LKM - LoadableKernelModule). LKMпредставляет собой программный код, выполняемый в пространстве ядра. Главной особенностью этого механизма является возможность динамической загрузки и выгрузки без необходимости перезагрузки всей системы или перекомпиляции ядра. Модули расширяют функциональные возможности. Например, одна из разновидностей модулей ядра, драйверы устройств, позволяют ядру взаимодействовать с аппаратурой компьютера. При отсутствии поддержки модулей пришлось бы писать монолитные ядра и добавлять новые возможности прямо в ядро. При этом, после добавления в ядро новых возможностей, пришлось бы перезагружать систему.
Подробнее принцип создания и загрузки модуля ядра будет описан в конструкторском разделе.
Для реализации модуля, перехватывающего системный вызов, необходимо определить алгоритм перехвата, представленный на рис. 2.
Рис.2. Алгоритм перехвата системного вызова с помощью LKM
Другими словами, в ядро загружается модуль, который
· Сохраняет указатель на оригинальный (исходный) вызов для возможности его восстановления.
· Содержит функцию, реализующую новый системный вызов.
· В таблице системных вызовов sys_call_table производит замену вызовов (настраивает соответствующий указатель на новый системный вызов)
· По окончании работы (при выгрузке модуля) восстанавливает оригинальный системный вызов, используя ранее сохраненный указатель
Данный механизм позволяет создать монитор – программу, которая отслеживает вызовы конкретных системных функций, перехватывает и сохраняет информацию об их параметрах, что и было проделано в данном курсовом проекте.
2.3. Средства IPC. Системный вызов sys_ipc
Одной из важнейших особенностей ОС семейства UNIX считается реализация механизмов IPC, или, другими словами, межпроцессного взаимодействия. Термин подразумевает различные средства обмена данными между процессами, стартовавшими в одной системе.