Реалізація системних викликів

Реалізація системного виклику в ОС Linux не повязана з поведінкою обробника системних викликів Додавання нового системного виклику в операційній системі Linux є порівняно простою справою Важка робота повязана з розробкою і реалізацією самого системного виклику Реєстрація його в ядрі проста Давайте розглянемо кроки, які необхідно вжити, щоб написати новий системний виклик в операційній системі Linux

Перший крок у реалізації системного виклику – це визначення його призначення, тобто що він повинен робити Кожен системний виклик повинен мати тільки одне призначення Мультиплексні системні виклики (Один системний виклик, який виконує великий набір різних операцій, залежно від значення прапора, переданого як аргумент) в операційній системі Linux використовувати не рекомендується Для прикладу того, якне треба робити,можна звернутися до системної функції ioctl ()

Які повинні бути аргументи, повертаються значення та коди помилок для нової системної функції Системна функція повинна мати зрозумілий і простий інтерфейс, по можливості з меншою кількістю аргументів Семантика і поведінку системних функцій – це дуже важливі речі, вони не повинні змінюватися, тому що від них залежатиме робота прикладних програм

Важливим є розробка інтерфейсу з прицілом на майбутнє Не обмежені чи можливості функції без необхідності Розроблюваний системний виклик повинен бути максимально спільним Не потрібно вважати, що завтра він буде використовуватися так само, як сьогодні Призначеннясистемного виклику повинно залишатися постійним, але йоговикористанняможе змінюватися Чи є системний виклик стерпним Не потрібно робити припущень про можливий розмір машинного слова або порядку проходження байтів У главі 19, Переносимість, розглядаються відповідні питання Потрібно впевнитися, що ніякі невірні допущення не заважатимуть використанню системного виклику в майбутньому Памятайте девіз Unix: Забезпечувати механізм, а не стратегію .

При розробці системного виклику важливо памятати, що переносимість і стійкість необхідні не тільки сьогодні, але й будуть необхідні в майбутньому Основні системні виклики ОС Unix витримали це випробування часом Більшість з них такі ж корисні і застосовні сьогодні, як і майже тридцять років тому

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

Системні виклики повинні ретельно перевіряти всі свої параметри для того, щоб переконатися, що їх значення адекватні і законні Системні виклики виконуються в просторі ядра, і якщо користувач може передати неправильні значення ядру, то стабільність і безпеку системи можуть постраждати

Наприклад, системні виклики для файлового вводу-виводу даних повинні перевірити, чи є значення файлового дескриптора допустимим Функції, повязані з управлінням процесами, повинні перевірити, чи є значення переданого ідентифікатора PID допустимим Кожен параметр повинен перевірятися не тільки на предмет допустимості та законності, а й на предмет правильності значення

Одна з найбільш важливих перевірок-це перевірка покажчиків, які передає користувач Уявіть, що процес може передати будь покажчик, навіть той, який вказує на область памяті, що не має прав читання Процес може таким обманом змусити ядро ​​скопіювати дані, до яких процес не має доступу, наприклад дані, що належать іншому процесу Перед тим як слідувати вказівником, переданим з простору користувача, система повинна переконатися в наступному

• Покажчик вказує на область памяті в просторі користувача Не можна, щоб процес змусив ядро ​​звернутися до памяті ядра від імені процесу

• Покажчик вказує на область памяті в адресному просторі поточного процесу Не можна дозволяти, щоб процес змусив ядро ​​читати дані інших процесів

• Для операцій читання є права на читання області памяті Для операцій запису є права на запис області памяті Не можна, щоб процеси змогли обійти обмеження на читання і запис

Ядро надає дві функції для виконання необхідних перевірок при копіюванні даних в простір користувача і з нього Слід памятати, що ядро ​​ніколи не повинно сліпо слідувати за дороговказом у просторі користувача Одна з цих двох функцій повинна використовуватися завжди

Для запису в простір користувача надається функція copy_to_user () Вона приймає три параметри: адреса памяті призначення в просторі користувача адреса памяті джерела в просторі ядра і розмір даних, які необхідно скопіювати, в байтах

Для читання з простору користувача використовується функція copy_from_user (), яка аналогічна функції copy_to_use r () Ця функція зчитує дані, на які вказує другий параметр, в область памяті, на яку вказує перший параметр, кількість даних – третій параметр

Обидві ці функції повертають кількість байтів, які вони не змогли скопіювати в разі помилки При успішному виконанні операції повертається нуль У разі такої помилки стандартним є повернення системним викликом значення-EFAULT

Давайте розглянемо приклад системного виклику, який використовує функції copy_from_use r () і copy_to_use r () Системний виклик silly_cop y () є до крайності марним Він просто копіює дані зі свого першого параметра у другій Це дуже не ефективно, так як використовується додаткове проміжне копіювання в простір ядра без будь-якої причини Але зате це дозволяє проілюструвати суть справи

/*

* Системний виклик silly copy – вкрай даремна функція,

* Яка копіює len байтів ІЕ області памяті,

* На яку вказує параметр src, в область памяті,

* На яку вказує параметр dst, з використанням ядра

* Без будь-якої на те причини Але це хороший приклад

*/

asmlinkage long sys_silly_copy(unsigned long *src, unsigned long *dst, unsigned long len)

}

unsigned long buf

/ * Повертаємо помилку, якщо розмір машинного слова в ядрі

не збігається з розміром даних, переданих користувачем * /

if (len = sizeof(buf))

return-EINVAL

/ * Копіюємо з src, який є адресою в просторі користувача, в buf * /

if (copy_from_user (&ampbuf, src, len))

return -EFAULT

/ * Копіюємо з buf в dst, який гоже є адресою в просторі користувача * /

if(copy_to_user(dst, &ampbuf, len) )

return -EFAULT

/ * Повертаємо кількість скопійованих даних * /

return len

}

Слід зауважити, що обидві функції, copy_from_use r () і copy_to_use r (), можуть блокуватися Це виникає, наприклад, якщо сторінка памяті, що містить дані користувача, не знаходиться у фізичній памяті, а в даний момент витіснена на диск У такому випадку процес буде перебувати в загальмованому стані до тек пір, поки обробник переривань через відсутність сторінок (page fault handler) не поверне сторінку памяті в оперативну память з файлу підкачки на диску

Остання перевірка – це перевірка на відповідність правам доступу У старих версіях ядра Linux стандартом було використання функції suse r () для системних викликів, які вимагають прав користувача root Ця функція просто перевіряла, чи запущений процес від користувача root Зараз цю функцію прибрали і замінили більш дрібно структурованим набором системних можливостей використання (Capabilities) У нових системах надається можливість перевіряти специфічні права доступу до специфічних ресурсів Функція capabl e ()

з допустимим значенням прапора, що визначає тип прав, повертає нульове значення, якщо користувач володіє зазначеним правом, і нуль-інакше Наприклад, виклик capabl e (CAP_SYS_NICE) перевіряє, чи має викликає процес можливість модифікувати значення параметра nice інших процесів За замовчуванням суперкористувач володіє всіма правами, а користувач, який не є користувачем root, не має ніяких додаткових прав Наступний приклад системного виклику, який демонструє використання можливостей використання, теж є практично марним

asmlinkage long sys_am_i_popular (void)

{

/ * Перевірити, має пі право процес використовувати можливість CAP_SYS_NICE * /

if (capable(CAP_SYS_NICE))

return -EPERM

/ * Повернути нуль, щоб позначити успішне завершення * /

return 0

}

Список всіх можливостей використання і прав, які за ними закріплені, міститься у файлі

Джерело: Лав, Роберт Розробка ядра Linux, 2-е видання : Пер з англ – М: ТОВ «ІД Вільямс »2006 – 448 с : Ил – Парал тит англ

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*