Systemy operacyjne 2008

Transkrypt

Systemy operacyjne 2008
Systemy operacyjne 2008
Plan ćwiczeń i pracowni grupy MSq
Marcin Skórzewski
Web: http://www.ii.uni.wroc.pl/~msq/so08/lab2/: HTML, PDF i TEXMACS
2 grudzień 2008
1. Zadanie
Niestety używanie „hostfs” w UML utrudnia testowanie „ioctl” (/dev), dlatego zadanie się trochę
zmienia:
Problem 1. Napisz moduł, który przechwyci kontrolę na wywołaniem systemowym open(), utworzy w /proc
plik open_spy. Tekst wprowadzony przez proces użytkowy do pliku będzie interpretowany jako ścieżka dostępu
do jakiegoś pliku, tekst czytywany to jakaś informacja o ostanim dostępie: PID procesu który otworzył plik,
UID użytkownika, itp.
2. User-Mode Linux
Nie chcemy, żeby każdy błąd pociągnął system w dół. Szkoda czasu. Warto korzystać z emulacji
lub UML.
Jak bawić się z modułami korzystając z User-Mode Linux? Kilka wariantów:
2.1. Gdy mam własnego Linuksa i skompilowałem jądro...
Celem jest otrzymanie dwóch podobnych jąder: jednego natywnego do używania, drugiego UserMode o jak najbardziej zbliżonej konfiguracji do testowania.
→
mam uprawnienia administratora i skompilowałem jądro w katalogu /usr/src/linux/:
# make mrproper
# make menuconfig
# make
# make modules_install
→
warto w menu konfiguracji zadbać o włączone opcje:
General setup > Kernel .config support (dostęp do konfiguracji przez /proc/config)
Enable loadable module support (obsługa sterownikó czyli modułów)
→
systemy plików wedle gustu, potrzebne będzie na pewno:
File systems > Filesystem in Userspace support (FUSE)
File systems > Pseudo filesystems > /proc file system support
→
oraz pomocne przy debugowaniu:
General setup > Configure standard kernel features > Enable support for
printk
Kernel hacking > Kernel debugging
Kernel hacking > Compile the kernel with debug info
1
2
Systemy operacyjne 2008
→
zachowuję kopię konfiguracji (w niektórych dystrybucjach konfiguracja jest zachowana w
katalogu /boot/ lub /etc/kernels/):
# cp .config /tam/gdzie/trzymam/konfigurację
→
oczyszczam źródła jądra:
# make ARCH=um mrproper
→
odzyskuje jak najwięcej z dotychczasowej konfiguracji i ustalam parametry specyficzne dla
trybu użytkownika (User-Mode):
# cp /tam/gdzie/trzymam/konfigurację .config
# make ARCH=um oldconfig
→
warto zaopiekować się parametrami:
Force a static link (STATIC_LINK): Y
Host filesystem (HOSTFS): Y
Management console (MCONSOLE): Y
Virtual block device (BLK_DEV_UBD): Y
stderr console (STDERR_CONSOLE): Y
port channel support (PORT_CHAN): Y
pty channel support (PTY_CHAN): Y
tty channel support (TTY_CHAN): Y
xterm channel support (XTERM_CHAN): Y
→
ostatnie spojrzenie na konfigurację:
# make ARCH=um menuconfig
→
w menu konfiguracyjnym dodaję do opcji „General setup/Local version” prefiks „-um”
→
wreszcie mogę kompilować:
# make ARCH=um
→
widzę, że jest plik uruchamialny o nazwie „linux” — to jest mój własny User-Mode Linux
→
instaluję sterowniki (moduły) do katalogu „/lib/modules/2.6.26-gentoo-r3-msq1-um/”
(„2.6.*-um” to wersja jądra zwracana przez „uname -r”):
# make ARCH=um modules_install
→
żegnam się z prawami administratora, uruchamiam UML jako zwykły użytkownik:
$ ./linux rootfstype=hostfs rw init=/bin/bash
→
wewnątrz UML jestem administratorem, ale proces UML „linux” ma uprawnienia użytkownika, potrzebuję tam jeszcze własnego systemy „/proc/”:
# mount -t proc /proc /proc
→
jeśli komenda „mount” się nie powiedzie, to system macierzysty nie daje użytkownikowi
uprawnień do czytania pliku programu mount — żeby uruchomić program normalnie
wystarczy uprawnienie +x, ale UML musi umieć przeczytać plik, który będzie wewnątrz
niego uruchomiony, więc musi być +r
→
testuję ładowanie sterowników — może być moduł „NTFS”:
Marcin Skórzewski
3
# modprobe ntfs
→
wszystko działa, jestem szczęśliwy i gotów do zabawy z modułami
2.2. Gdy mam własnego Linuksa i nie będę kompilować dla niego jądra
Korzystam z cudzego jądra w wersji zwracanej przez polecenie „uname -r”. Pobieram taką
samą wersję z Internetu lub płyty instalacyjnej dystrybucji. Rozpakowuję do „/usr/src/linux”.
Jego konfigurację mogę odzyskać z pliku „/proc/config” (może być skompresowany z prefiksem „.gz”) jeśli podczas konfiguracji było wybrane „General setup > Kernel .config
support”. W innym wypadku albo szukam pliku w innym miejscu (np.: /etc/kernels/, /boot/,
/usr/share/genkernel/), albo godzę się na rozbierzność konfiguracji UML i używanego jądra.
# cd /usr/src/linux
# make ARCH=um mrproper
# cp /proc/config .config
Reszta jak w pierwszym wariancie. Nie zapominam o dodaniu prefiksu „-um” do wersji. Dzięki temu
moduły zainstalowane będą do innego katalogu niż dla obecnego jądra i ich nie nadpiszą (zniszczą).
2.3. Gdy jestem na pracowni linuksowej...
Jak w wariancie wcześniejszym. Różnica polega na braku uprawnień administratora. Jedyną operacją, która wymaga wysokich uprawnień jest instalowanie modułów. Jednym z rozwiązań jest
wirtualna podmiana (podpięcie?) katalogu „/lib/modules/”. Na zewnątrz nie zostanie dokonana
żadna zmiana:
→
wybieram katalog docelowy na moduły:
$ mkdir /tmp/modules
→
uruchamiam UML:
$ ./linux rootfstype=hostfs rw init=/bin/bash
→
przypinam katalog na moduły:
mount -o bind /tmp/modules /lib/modules
→
instaluje moduły (na pozór do „/lib/modules/”, ale na prawdę do „/tmp/modules/”):
# cd /usr/src/linux
# make ARCH=um modules_install
2.4. Na pracowni brak miejsca na dysku
Źródła + kompilacja UML = 1.3GB. Decyduję się na całkowitą rozbieżność obecnej konfiguracji
i UML. Dostępny jest skompilowany podczas przygotowania tej pomocy UML wraz z modułami
i konfiguracją (.config.gz). Jest to wersja 2.6.26-gentoo-r3 z dystrybucji Gentoo z modyfikacją
m.in. do obsługi SquashFS (wymagane np. dla Puppy Linux). Nie znaczy to, że nie trzeba użyć
żródeł jądra. Potrzebne są żeby kompilować moduły. Po przygotowaniu ich za pomocą:
# cp /ścieżka/do/pliku/z/konfigucacją/config .config
# make ARCH=um oldconfig
# make ARCH=um prepare
w wersji i konfiguracji jak wyżej zajmują wciąż ponad 370MB. Na pracowni juz się zmieści.
4
Systemy operacyjne 2008
3. Moduły
Moduł piszę w pliku „test.c” i mam plik „Makefile” o zawartości:
obj-m += test.o
Kompiluję „test.ko” poleceniem:
$ make -C /usr/src/linux-2.6.26-gentoo-r3 M="$PWD" ARCH=um
gdzie „/usr/src/linux-2.6.26-gentoo-r3” jest katalogiem ze źródłami jądra, a zmienna „$PWD”
przechowuje ścieżkę bieżącego katalogu.
4. Komunikacja przez /proc i /dev
W „Access the Linux kernel using the /proc filesystem” jest prosty przykład odczytywania danych
wysłanych z przestrzeni użytkownika przez plik w „/proc”. Listing 9. zawiera szkielet inicjujący
moduł, który obsługuje /proc, natomiast w listingu 10. jest funkcja wywoływana podczas pisania
do pliku.
[[Rozdział 7. podręcznika The Linux Kernel Module Programming Guide pokazuje w przykładzie
7-1/7-2 jak wysłać dane przez /dev. Kod jest obficie skomentowany i część funkcjonalności nie jest
nam potrzebna: jak obsługa tylko jednego procesu użytkowego na raz czy obsługa pisania do pliku
w /dev.]]
5. Przechwytywanie wywołań systemowych
Tu pokazane jak to działa: System Call Redirection 2.6 Kernel Code That Works. W późniejszych wersjach jądra loops_per_jiffy i boot_cpu_data mają być zamienione odpowiednio na
unlock_kernel i loops_per_jiffy: Finding the Linux System Call table in 2.6 series kernels.
System identyfikuje pliki liczbą (numerem inode). Możemy uzyskać tą liczbę z tekstowej ścieżki
dostępu podczas rozpoczynania śledzenia (otrzymania rozkazu w /proc/open_spy). W praktyce
przestanie to działać gdy zostanie zmieniona nazwa pliku. Damy sobie z tym jakoś radę.