Table of Contents

1. Mediul de dezvoltare pentru cod kernel

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.

Subiecte abordate

Resurse utile

Exerciții

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

Pornirea mediului QEMU

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ă “intrați” în mediul QEMU dați click în cadrul ferestrei QEMU.

Ca să “ieșiți” din mediul QEMU apăsați pe Alt și Ctrl.

Investigarea stării sistemului

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?

Investigarea imaginii de kernel

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

Urmărirea intrărilor din /proc/kallsyms

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ă?

Verificarea conectivității la rețea

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.

Dacă pe mașina virtuală VirtualBox interfața 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:

  1. Se oprește mașina virtuală QEMU folosind combinația de taste Ctrl+c.
  2. Se șterge interfața tap0 folosind comanda
    sudo ip link del dev tap0
  3. Se repornește mașina virtuală QEMU folosind comanda
    make
  4. Se verifică faptul că acum interfața tap0 este activă folosind comanda
    ip 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:

Vizualizarea mesajelor din kernel prin rețea

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.

Este foarte util să fie folosit un astfel de server pentru a captura mesaje. De multe ori fereastră mașinii virtuale QEMU e prea mică, sau se pierd informații, sau îngheață. Într-un ecran distinct, pe mașina virtuală VirtualBox, nu vor exista astfel de probleme.

Adăugarea unui fișier în mașina virtuală QEMU

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

Mașina virtuală QEMU se dorește a fi cât de simplă se poate pentru a putea fi pornită și oprită cât mai rapid. De aceea nu vom face compilări, editări sau schimbări în cadrul acesteia ci în cadrul mașinii virtuale VirtualBox. Urmând ca apoi să aducem acele fișiere în mașina virtuală QEMU și să o pornim cu acestea.

Folosirea netcat pentru comunicarea între mașini virtuale

Pentru a face ceva mai interesant, veți copia în mașina virtuală QEMU un fișier netcat compilat static.

Este vorba de fișierul 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.

La nevoie puteți transmite și fișiere în acest mod folosind comenzi de forma:

(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>

Folosirea unui client de SSH

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

În general, este de preferat o comunicare în celălalt sens, cu serverul SSH rulând pe mașina virtuală QEMU. Este nevoie de configuarea unui executabil static SSH pe mașina virtuală QEMU; se poate face acest lucru cu serverul dropbear.

Alterarea opțiunilor de pornire a nucleului

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

Mai sus am schimbat opțiunea 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.

Adăugarea unei opțiuni de bootare a nucleului

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.

[BONUS] Compilarea unui nou kernel

Compilați nucleul în directorul /home/training/linux-kernel-dev/linux-3.13.

[BONUS] Rularea unui server SSH pe mașina virtuală QEMU

Folosiți sursele Dropbear, compilați serverul și configurați-l pentru a funcționa pe mașina virtuală QEMU.

E foarte greu. Eu am încercat și nu am reușit. O să mai încerc. E recomandat să aveți acces la Internet ca să vă puteți documenta (acolo cât se poate) legat de ce aveți de făcut.