Vom face primi pași în investigarea nucleului Linux și ne vom acomoda cu infrastructura (minimalistă) de dezvoltare la nivelul nucleului. Infrastructura folosește o mașină virtuală QEMU.
Arhiva de suport pentru exerciții se găsește aici. Descărcați arhiva și apoi decomprimați-o folosind comanda
unzip cap-01-tasks.zip
Pentru partea practică vom folosi mașina virtuală VirtualBox și o mașină virtuală (emulator) QEMU rulând în aceasta. Pentru aceasta vom intra în directorul linux-kernel-dev/qemu-vm/
din mașina virtuală QEMU. Acest director conține o serie de script-uri pentru pornirea mașinii virtuale QEMU. Pe scurt, se construiește un sistem de fișiere virtual care este apoi folosit pentru pornirea mașinii virtuale.
Pentru pornirea mașinii virtuale folosim comanda
make
În urma rulării comenzii se deschide un prompt QEMU în care este pornită mașina virtuală.
Mașina virtuală ne va afișa un prompt de root în care putem include comenzi. Mașina virtuală conține un sistem de fișiere minimal cuprins din:
În acest mod vom porni mereu mașina virtuală QEMU
Pentru oprirea mașinii virtuale folosim comanda poweroff
în cadrul mașinii virtuale QEMU sau folosim combinația de taste Ctrl+c
în fereastra din mașina virtuală VirtualBox în care am rulat comanda make
.
Ca să “ieșiți” din mediul QEMU apăsați pe Alt
și Ctrl
.
Ca să aflăm informații, în mașina virtuală QEMU folosim comenzi precum cele de mai jos
uname -a ps dmesg cat /proc/cmdline
Observați care este versiunea nucleului.
Observați că sunt doar procese shell pornite (restul sunt thread-uri kernel). Ca să parcurgeți diferitele procese shell folosiți combinațiile de taste Alt+F1
, Alt+F2
, Alt+F3
etc.
Puteți observa că shell-ul folosit este busybox
folosind comanda
ls -l /bin/sh
Puteți observa linia de comandă cu care a fost pornit nucleul (opțiunile nucleului). Acestea sunt cele introduse în fișierul Makefile
cu ajutorul căruia pornim mașina virtuală QEMU.
Aceste comenzi le puteți rula și pe mașina virtuală VirtualBox. Ce versiune de nucleu are mașina virtuală VirtualBox? Ce shell folosește? Care este linia de comandă cu care a fost pornit nucleul mașinii virtuale VirtualBox?
Imaginea de kernel (fișierul imagine al nucleului) nu este disponibil în cadrul mașinii virtuale QEMU. Aceasta se găsește pe mașina virtuală indicată de link-urile simbolice bzImage
și vmlinux
. Folosim comenzile ls
și file
pentru a investiga cele două imagini:
training@box:~/linux-kernel-dev/qemu-vm$ ls -lh /home/training/linux-kernel-dev/linux-3.13/arch/x86/boot/bzImage -rw-r--r-- 1 training training 5.6M Feb 16 2014 /home/training/linux-kernel-dev/linux-3.13/arch/x86/boot/bzImage itraining@box:~/linux-kernel-dev/qemu-vm$ file /home/training/linux-kernel-dev/linux-3.13/arch/x86/boot/bzImage /home/training/linux-kernel-dev/linux-3.13/arch/x86/boot/bzImage: Linux kernel x86 boot executable bzImage, version 3.13.0 (ddvlad@doppleganger) #10 SMP Sun Feb 16 18:16:42 EET 20, RO-rootFS, swap_dev 0x5, Normal VGA training@box:~/linux-kernel-dev/qemu-vm$ ls -lh /home/training/linux-kernel-dev/linux-3.13/vmlinux -rwxr-xr-x 1 training training 223M Feb 16 2014 /home/training/linux-kernel-dev/linux-3.13/vmlinux training@box:~/linux-kernel-dev/qemu-vm$ file /home/training/linux-kernel-dev/linux-3.13/vmlinux /home/training/linux-kernel-dev/linux-3.13/vmlinux: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, BuildID[sha1]=2d1540041ec6cbf7edd08929364579e753537bac, not stripped
Ce puteți spune despre cele două fișiere? De ce este fișierul vmlinux
atât de mare? Care este utilitatea acestui fișier?
Aplicați aceleași comenzi pe mașina virtuală VirtualBox, pe imaginea de kernel din /boot/
.
Folosiți comanda de mai jos pentru a afla simbolurile definite în fișierul vmlinux
nm /home/training/linux-kernel-dev/linux-3.13/vmlinux | less
Informații despre simbolurile unui kernel aflat în rulare se găsesc în fișierul /proc/kallsyms
pe care îl putem investiga folosind comanda
less /proc/kallsyms
Simbolurile (funcții și variabile) pe care nucleul le are definite sunt vizibile în fișierul /proc/kallsyms
. Acest fișier poate fi investigat pentru fiecare nucleu din fiecare mașină virtuală, atât cel de pe mașina virtuală QEMU, cât și cel de pe mașina virtuală VirtualBox.
De la ce adresă pornesc adresele din fișierele /proc/kallsyms
din fiecare mașină virtuală?
Pentru a verifica legătura la rețea între mașina virtuală QEMU și sistemul pe care rulează (mașina virtuală VirtualBox) este folosită o interfață tap0
.
tap0
este dezactivată, va trebui să o repornim.
Pentru a investiga aceste lucru, folosim comanda ip a s
iar dacă output-ul este cel de mai jos (adică apare șirul DOWN
), atunci interfața este dezactivată
training@box:~/linux-kernel-dev/qemu-vm$ ip a s tap0 4: tap0: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast state DOWN group default qlen 500 link/ether 36:ec:be:96:ec:08 brd ff:ff:ff:ff:ff:ff
Dacă așa este cazul, atunci trebuie urmați pașii:
Ctrl+c
.tap0
folosind comandasudo ip link del dev tap0
make
tap0
este activă folosind comandaip a s
Pentru a verifica conectivitatea se folosește comanda ping
având ca adresă IP adresa celeilalte mașini virtuale. În fiecare mașină virtuală aflăm adresa IP folosind comanda ip a s
:
ip a s eth0
ip a s tap0
Atunci când avem conectivitate între două sisteme, putem configura modulul netconsole
pe sistemul pe care dezvoltăm în nucleul Linux pentru a transmite mesaje de kernel în rețea.
Pe mașina virtuală QEMU modulul netconsole
este deja configurat să transmită mesaje către adresa 172.20.0.1
pe portul UDP 6666
. Puteți observa acest lucru în fișierul de startup /etc/rcS
sau în mesajele de kernel vizibile cu ajutorul comenzii dmesg
.
Pentru a captura mesajele nucleului, pe mașina virtuală VirtualBox pornim un “seerver” UDP care asculta mesaje pe portul 6666
. Folosim un alt tab de terminal și rulăm comanda
nc -lup 6666
Acum orice pornire a mașinii virtuale QEMU și orice mesaje furnizate de nucleul mașinii virtuale QEMU va fi capturat de serverul UDP.
În forma curentă mașina virtuală QEMU este destul de spartană și puțin dinamică. Avem nevoie de fișiere care să ne ofere funcționalități suplimentare. Vom folosi mașina virtuală VirtualBox pentru operații de compilare de module de kernel sau altele, iar fișierele rezultate vor forma apoi sistemul de fișiere al mașinii virtuale QEMU.
Pentru a obține fișiere pe mașina virtuală QEMU, acestea trebuie copiate în subdirectorul fsimg/
din directorul de pornire al mașinii virtuale. Cel mai recomandat este să fie copiate în fsimg/root/
. Apoi se pornește mașina virtuală.
Doar ca exemplu să copiem fișierul /etc/protocols
de pe mașina virtuală VirtualBox în directorul fsimg/root/
. Apoi pornim mașina virtuală QEMU folosind comanda make
. După pornire vom vedea că în directorul /root
din cadrul mașinii virtuala QEMU avem fișierul protocols
.
Pentru a face ceva mai interesant, veți copia în mașina virtuală QEMU un fișier netcat
compilat static.
nc-static
din directorul /home/training/linux-kernel-dev/
. Copiați acest fișier în fsimg/root/programs/
.
O dată copiat acest utilitar static, îl puteți folosi pentru comunicare cu mașina virtuală VirtualBox. Porniți pe mașina virtuală QEMU un server care ascultă mesaje pe un port UDP. Iar apoi trimiteți un mesaj de pe mașina virtuală VirtualBox folosind tot netcat
.
(receiver/server) netcat -u -l -p 12345 > <filename> (sender/client) cat <filename> | ./nc-static -u <IP-receiver> 12345
unde <filename>
este numele fișierului (sau calea către fișier) iar <IP-receiver>
este adresa IP a a receiver-ului>
Putem să folosim conexiune SSH pentru comunicarea între cele două mașini virtuale. O formă mai simplă este să folosim un client SSH pe mașina virtuală. Pentru aceasta găsiți în arhiva capitolului executabilul dbclient
.
Copiați executabilul dbclient
pe mașina virtuală QEMU și apoi folosiți o comandă precum cea de mai jos pentru vă autentifica pe mașina virtuală VirtualBox
DROPBEAR_PASSWORD="training" ./dbclient -l training 172.20.0.1
Putem afecta modul în care se comportă nucleul prin alterarea opțiunilor de pornire a sa. Pentru aceasta edităm scriptul build-iso.sh
și actualizăm intrarea ce definește linia de bootare (linia 146 din fișier). Astfel, pentru a face bootare quiet schimbăm linia din
append root=/dev/ram ro noquiet rdinit=/init initrd=ramdisk.gz debug apci=off noapic
în
append root=/dev/ram ro quiet rdinit=/init initrd=ramdisk.gz nodebug apci=off noapic
noquiet
în opțiunea quiet
și debug
în nodebug
.
Pornim mașina virtuală QEMU folosind comanda
make
La pornirea mașinii virtuale vom vedea reducerea drastică a mesajelor afișate de kernel.
Urmăriți opțiunile de bootare ale nucleului și dezactivați folosirea vdso
.
Pentru a verifica faptul că un proces folosește sau nu vdso
urmăriți spațiul său de adresă folosind comanda
cat /proc/self/maps
În mapările afișate se va afla (sau nu) și vdso
.
Compilați nucleul în directorul /home/training/linux-kernel-dev/linux-3.13
.
Folosiți sursele Dropbear, compilați serverul și configurați-l pentru a funcționa pe mașina virtuală QEMU.