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ę.