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?
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.Odpowiedzi:
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.c
pliku, w którymsys_call_table
jest zdefiniowany. Jego rozmiar jest dokładnie__NR_syscall_max+1
.__NR_syscall_max
jest zdefiniowanearch/x86/kernel/asm-offsets_64.c
jakosizeof(syscalls) - 1
(jest to liczba ostatniego wywołaniasyscall
systemowego ), 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_setaltroot
na 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_table
do modułów od wersji 2.6 (ostatnia wersja jądra, z której ten symbol został wyeksportowany, to była2.5.41
).Jednym ze sposobów obejścia tego jest zmiana jądra w celu wyeksportowania
sys_call_table
symbolu do modułów. Aby to zrobić, musisz dodać następujące dwa wierszekernel/kallsyms.c
( nie rób tego na maszynach produkcyjnych ):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.
źródło
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.
źródło