Видео смотреть бесплатно

Смотреть в хорошем качестве hd видео

Официальный сайт toppromotion 24/7/365

Смотреть видео бесплатно

03.02.10 15:20 m039

CodingКопаимся в системе веселья ради - Системеный вызов Welinux


Часть первая. Появление собственного системного вызова.

Сначала, что же такое системный вызов ядра? Хм.. ну скажем так, есть функции С библиотек, они достаточно абстрактны, например функция puts или printf являются оболочкой и используют системные вызов ядра(write), с соответствующими параметрами. А что делает системный вызов.. хм.. их много, и все они достаточно разношерстные, для ознакомления мне нравится вот эта pdf-ка .

Заметка: можете использовать такие команды как ltrace и strace для анализа и удостоверения, что у системного вызова есть номер.

Сам по себе системный вызов это функция, но немного по особому определенная. А так как задача заключается в изменении её, приведу листинг написанный на коленке, который поможет вспомнить синтаксис сишника:
refresh_memory.c:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

#include <stdio.h>

static int my_precious = 0;

long welinuxing(int a){
        return my_precious += a;
}

long welinuxing_new(int a){
        return my_precious -= a;
}

long (* welinuxing_current) (int);

int main(){
        welinuxing_current = welinuxing;
        printf("Yeah.. now it is %d\n", welinuxing_current(10));
        welinuxing_current = welinuxing_new;
        printf("Yeah.. now it is %d\n", welinuxing_current(1));
        return 0;
}


Хм.. это.. а всё таки как написать системный вызов? И встроить его в ядро? Гугл ответил вот такой вот пдф-кой . , но в ней также есть информация как скомпилировать ядро под .. ubunty.

Заметка: Хочу посоветовать, что лучше все-таки это безобразие вытворять на виртуальной машине. Там все скомпилируйте. А если используете virtualbox, то советую настроить общие папки(share folders). Но с этими папками не всё гладко, компилировать ядро не получиться в этой папке, потому что оно не понимает что такое символические ссылки. Поэтому можно настроить либо nfs, если хотите что бы файлы компиляции находились на хостовой машине.

Итак, что бы добавить в само ядро новый системный вызов нужно: добавить в таблицу системных вызовов(о ней далее) указатель на новый системный вызов(банально - функцию) и определить где-то этот системный вызов(функцию). А потом все это слинковать. Исправлять файлы в includes не нужно. Хотя если делаем системный вызов Welinux, то не плохобы напомнить всем, что мы зарезервировали себе номер..

Таблица системных вызов, это массив в котором содержится указатели на функции. Открываем lxr и находим эту таблицу по названию sys_call_table

Ой, чуть не забыл, тут уже пошел ассемблер, а не сишник. Немного поясню, ".long <>" это равносильна сишному "long <>". Но сам не до конца всего знаю, поэтому далее интересуюсь, что значит макрос ENTRY , а вот оно:
1
2
3
4
5
6
7
8
 
#ifndef ENTRY
#define ENTRY(name) \
  .globl name; \        //  символ станет доступен для линковки вне файла.

  ALIGN; \              // если посмотрите выше , то уведите определение. Это выравнивание по 4 байта (для x86), где свободные места будут заполнены ассемблерной вставкой 0x90(nop - no operation)
  name:
#endif
#endif /* LINKER_SCRIPT */


Для тех, кто делает все в голове получим вот такую штуку в конце манипуляций. Т.е. в конце всех манипуляций будет приведено к виду:
1
2
3
4
5
6
7
 
.globl sys_call_table
.align 4,0x90
sys_call_table:
        .long sys_restart_syscall       /* 0 - old "setup()" system call, used for restarting */
        .long sys_exit
...


Долго искал, что значит 0x90, вроде бы в глаза бросается, что это nop, но до конца не был уверен. Ответ нашел на сайте .

Итак, теперь немного воочию убедились, что есть такая таблица. Осталось добавить свой системный вызов и прилинковать его. Можете для начала поискать в lxr определение системных вызовов, вот например этот sys_getpid вызов не такой уж сложный. Но попробуйте его найти, не заглядывай в спойлер. Я чтот много времени потратил искамши :(
тут


Пишем системы вызов welinux. (Большей частью руководствуясь pdf-кой):
Для это создаем папку в корне исходников линукса.
Помещаем в неё исходники wl.c и Makefile.
wl.c:
1
2
3
4
5
6

#include <linux/linkage.h>
static int my_precious = 0; // Копилка рейтинга..
asmlinkage long sys_welinuxing(int a){
        return my_precious += a; // Возможно надо было сделать "+1", а не "а"
}

Makefile:
1
2

obj-y := wl.o


Потом изменяем главный Makefile:
Строчку:
1
2

core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ /block

На:
1
2

core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ /block  welinux/


Ох-хо-хох, забыл добавить в таблицу системный вызов. Добавляем в конец файла "arch/x86/kernel/syscall_table_32.S" строчку ".long sys_welinuxing". И главное запоминаем номер под котором он идет! У меня виртуалка 6.26, номер будет 327.
Заметка: есть соглашение по поводу названий, т.е. sys_* предшествует названию системного вызова, но практически можно оставить любое название, которое придет на ум.

Усё, компилируем и запускаем ядро. Первый этап пройден. :)

Часть вторая. Захватываем мир.

Теперь можем поиграться с новым системным вызовом.
Для начало узнаем как прошли дела с компиляцией:
grep welinux /boot/System.map

Или:
grep welinux /proc/kallsyms


Выдало "c0211db8 T sys_welinuxing", что означает, что адрес нашей функции в ядре 0хc0211db8.

Тестируем вот такой вот исходничек:
1
2
3
4
5
6
7
8
9

#include <unistd.h>
#include <stdio.h>
#define __NR_mycall 327

int main() {
        printf("Мой рейтинг равен %d\n", syscall(__NR_mycall, 1));
        return 0;
}


Ну вы уже должны знать, что должно произойти. Уфф.. на данный момент системный вызов должен работать.

Часть третья. Люто бешено минусуем

Теперь переходим к 3му этапу написанию модуля ядра.
Создаем где угодно папку и помещаем туда 2 файла:
1
2
3
4
5
6
7
8
9
10

Makefile
obj-m += w.o

all:
        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
 

Первый вариант w.c:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>


static int example_init(){
        printk(KERN_ALERT"W: init\n");
        return 0;
}

static void example_exit(){
        printk(KERN_ALERT"W: exit\n");
}

module_init(example_init);

module_exit(example_exit);


После чего убедитесь в том, что система в состоянии скомпилоровать модули. Это я жестко опущу

А теперь вы уже может быть догадались, что у нашей таблицы(sys_call_table) есть свой адрес. Делается той же коммандой:
 grep call_table /proc/kallsyms

Вывод:
"c042a86c R sys_call_table"

Теперь изменяем наш модуль на вот такой вот:
w.c:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/linkage.h>

long * welinuxing  = 0xc042a86c + 4 * 327;

static int example_init(){
        printk(KERN_ALERT"W: init %lx\n", *welinuxing);
        return 0;
}

static void example_exit(){
        printk(KERN_ALERT"W: exit\n");
}

module_init(example_init);

module_exit(example_exit);


Ну как, тот же адрес вывела на экран, как если бы использовали функцию "grep welinux /proc/kallsyms"?

А теперь попробуем из самого ядра вызвать эту функцию с помощью, этого файла:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/linkage.h>

asmlinkage long (* welinuxing)(int);

static int example_init(){
        welinuxing =  *((long *) (0xc042a86c + 4 * 327));
        printk(KERN_ALERT"W: init %ld\n", welinuxing(10));
        return 0;
}

static void example_exit(){
        printk(KERN_ALERT"W: exit\n");
}

module_init(example_init);

module_exit(example_exit);


А теперь подменим её:
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

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/linkage.h>

#define pWelinux (long *) (0xc042a86c + 4 * 327)

asmlinkage long (* welinuxing_old)(int);

asmlinkage welinuxing(int a){
        return welinuxing_old(-a); // Кто хочет тщеславия, можете заменить на "a * 9000"
};

static int example_init(){
        welinuxing_old =  *(pWelinux);
        *(pWelinux) = welinuxing;
        printk(KERN_ALERT"W: init\n");
        return 0;
}

static void example_exit(){
        *(pWelinux) = welinuxing_old;
        printk(KERN_ALERT"W: exit\n");
}

module_init(example_init);

module_exit(example_exit);


Теперь вставляя один модуль, мы управляли системным вызовом которым мы сделали.
Уфф.. закончил. На самом деле писать это кажется гораздо дольше чем делать, но думаю что кому-нибудь веселье доставить такой подход.

Из оставшихся вопросов:
Как отследить, то что произошло изменение ядра и старый системный вызов стал уже не тот.
Говорят, что есть динамическое создание системных вызовов.
Научить системный вызов генерировать прерывания, следовательно создать свой обработчик.



warchief 03.02.10 19:36 # +0
отлично, давно хотел написать модуль к ядру.
booley 03.02.10 19:57 # +0
Недавно была статья, где предлагалась замерить скорость компилирования, там хардкора гораздо меньше.

ТС! Сходи проветрись, да и выкинь свой косяк и проверь комнату. Такого жесткача я давно не видел :)
booley 03.02.10 19:58 # +0
скорость компилирования

*скорость компилирования ядра
m039 03.02.10 20:02 # +0
Смысл не вижу в измерением скорости компиляции. А замене системного вызова смысл куда глубже. :)
ZogG 03.02.10 20:07 # +0
зачем выкидывать косяк? написал статью - передай косяк по кругу, пусть все пишут.
aspire89 03.02.10 23:44 # +0
правильно будет копаЕмся
Shtsh 04.02.10 00:11 # +0
в мемориз по-любому. Вдруг придётся заниматься системным программированием, хоть и сисадмин.

Посты Комментарии
Последние посты
    Посты Комментарии
    Последние комментарии
      Посты Комментарии
      Изменения
        Посты Комментарии Изменения Черновики Избранное
        Черновики (все)
          Посты Комментарии Изменения Черновики Избранное
          Избранное (всё)
            Посты Комментарии Изменения Черновики Избранное
            Лучшие блоги (все 88)
            Топ пользователей Топ блогов
            Топ пользователей Топ блогов
            Элита (все 1809 из 142 городов)
            Топ пользователей Топ блогов
            welinux.ru

            Смотреть онлайн бесплатно

            Онлайн видео бесплатно


            Смотреть русское с разговорами видео

            Online video HD

            Видео скачать на телефон

            Русские фильмы бесплатно

            Full HD video online

            Смотреть видео онлайн

            Смотреть HD видео бесплатно

            School смотреть онлайн