Dodanie nowego wywołania systemowego do Linuksa 3.2.xz ładowalnym modułem jądra [zamknięty]

11

Chcę dodać szczególne nowe wywołanie systemowe w jądrze Linuksa 3.2.x, ale jako moduł jądra do załadowania (ponieważ nie chcę ponownie i ponownie kompilować jądra)

Przeczytałem wiele postów w Internecie i na SO, a niektóre miejsca twierdzą, że implementacja wywołań systemowych jako modułów ładowalnych nie jest możliwa, podczas gdy inne twierdzą, że jest to możliwe.

Który to jest? Jak to zrobić, jeśli to możliwe?

abhi
źródło
To pytanie jest nie na temat: Unix i Linux dotyczą użytkowania i administracji, a nie programowania. Powinieneś zapytać o przepełnienie stosu . Nie bądź taki niejasny: link do postów znalezionych na stosie przepełnienia stosu i wyjaśnij, co znalazłeś niejednoznaczne lub sprzeczne.
Gilles „SO- przestań być zły”
2
Uważam, że to pytanie jest bardziej związane z Linuksem jako systemem operacyjnym niż z samym programowaniem. Ważne jest również, aby wiedzieć, jakie są możliwości rozszerzenia naszych możliwości systemu i jakie są jego ograniczenia. To na przykład pozwala zrozumieć, dlaczego niektórych funkcji nie można zaimplementować jako modułu ładowalnego i wymaga łatania jądra. Wiedząc, dlaczego tak jest, może dać ci kilka pomysłów na bezpieczeństwo w porównaniu z użytecznością, którą muszą opracować programiści jądra. Czy to pytanie byłoby bardziej na ten temat, gdyby PO zapytał tylko, czy jest to możliwe, a dlaczego nie, a jak to wdrożyć?
Krzysztof Adamski,
1
Było wiele dyskusji na temat <stroke> flames </stroke> na liście mailingowej jądra Linux, na przykład reiserfs używał własnych wywołań systemowych, które nie były tak naprawdę ukochane przez niektórych głównych programistów, w tym Linusa. W twoim przypadku po prostu użyłbym ioctl()s do zadania, są one łatwo modularne. Afaik, główny powód, dla którego jest to tak trudne, jak to możliwe, że liczba połączeń systemowych jest bardzo zakodowana i nikt nie chce chaosu, który pojawiłby się na zdjęciu. Ale istnieje wiele interfejsów jądra, aby osiągnąć tę samą funkcjonalność, na przykład sysfs, ioctls lub podobne.
peterh - Przywróć Monikę

Odpowiedzi:

14

Nie jest to możliwe, ponieważ tablica wywołań systemowych (wywoływana sys_call_table) jest tablicą rozmiarów statycznych. A jego rozmiar jest określany w czasie kompilacji na podstawie liczby zarejestrowanych wywołań systemowych. Oznacza to, że nie ma miejsca na kolejne.

Możesz sprawdzić implementację na przykład architektury x86 w arch/x86/kernel/syscall_64.cpliku, w którym sys_call_tablejest zdefiniowany. Jego rozmiar jest dokładnie __NR_syscall_max+1. __NR_syscall_maxjest zdefiniowane arch/x86/kernel/asm-offsets_64.cjako sizeof(syscalls) - 1(jest to liczba ostatniego wywołania syscallsystemowego ), gdzie jest tabela ze wszystkimi wywołaniami systemowymi.

Jednym z możliwych rozwiązań jest ponowne użycie części istniejącego (lub przestarzałego, jeśli twoja architektura go posiada, patrz sys_setaltrootna przykład) numer systemowy z twoim, ponieważ nie będzie to wymagało więcej miejsca w pamięci. Niektóre architektury mogą mieć również dziury w tabeli syscall (np. 64-bitowa wersja x86), więc możesz również z tego korzystać.

Możesz użyć tej techniki, jeśli tworzysz nowe połączenie systemowe i chcesz uniknąć ponownego uruchamiania podczas eksperymentów. Będziesz musiał zdefiniować nowe wywołanie systemowe, znaleźć istniejący wpis w tabeli syscall, a następnie zastąpić go z modułu.

Wykonanie tego z modułu jądra nie jest trywialne, ponieważ jądro nie eksportuje sys_call_tabledo modułów od wersji 2.6 (ostatnia wersja jądra, z której ten symbol został wyeksportowany, to była 2.5.41).

Jednym ze sposobów obejścia tego jest zmiana jądra w celu wyeksportowania sys_call_tablesymbolu do modułów. Aby to zrobić, musisz dodać następujące dwa wiersze kernel/kallsyms.c( nie rób tego na maszynach produkcyjnych ):

extern void *sys_call_table;
EXPORT_SYMBOL(sys_call_table);

Inną techniką jest dynamiczne znajdowanie tabeli syscall. Iterujesz po pamięci jądra, porównując każde słowo ze wskaźnikiem ze znaną funkcją wywołania systemowego. Ponieważ znasz przesunięcie tego znanego połączenia systemowego w tabeli, możesz obliczyć początkowy adres tabeli.

Krzysztof Adamski
źródło
1

Niestety nie można dodawać wywołań systemowych do jądra jako modułów do załadowania. Musisz nakładać się na kompilację jądra za każdym razem, gdy dodajesz nowe wywołanie systemowe.

PaulDaviesC
źródło