This shows you the differences between two versions of the page.
so2:laboratoare:lab02:exercitii [2017/03/02 17:12] george.muraru [Laborator 2: Exercitii - added root directory when adding/removing module] |
so2:laboratoare:lab02:exercitii [2019/02/25 15:18] (current) ionel.ghita [Extra] |
||
---|---|---|---|
Line 1: | Line 1: | ||
====== Laborator 2: Exerciții ====== | ====== Laborator 2: Exerciții ====== | ||
- | Pentru desfășurarea laboratorului pornim de la [[http://elf.cs.pub.ro/so2/res/laboratoare/lab02-tasks.zip|arhiva de sarcini a laboratorului]]. Descărcăm și decomprimăm arhiva în directorul ''so2/'' din directorul home al utilizatorului ''student'' de pe sistemul de bază (stația ''asgard''):<code bash> | + | ===== Pregătirea laboratorului ===== |
- | student@asgard:~$ cd so2/ | + | |
- | student@asgard:~/so2$ wget http://elf.cs.pub.ro/so2/res/laboratoare/lab02-tasks.zip | + | Pentru rezolvarea laboratorului, vom lucra în același director din care pornim mașina virtuală (''~/so2/linux/tools/labs''). |
- | student@asgard:~/so2$ unzip lab02-tasks.zip | + | |
- | student@asgard:~/so2$ tree lab02-tasks | + | Pașii de rezolvare sunt următorii: |
+ | * pregătirea scheletului de laborator | ||
+ | * compilarea modulelor de Kernel | ||
+ | * copierea modulelor pe mașina virtuală | ||
+ | * pornirea mașinii virtuale și testarea modulelor | ||
+ | |||
+ | ==== Pregătirea scheletului de laborator ==== | ||
+ | |||
+ | Scheletul de laborator este generat din sursele din directorul ''tools/labs/templates''. Putem genera scheletele pentru toate laboratoarele folosind următoarea comanda: | ||
+ | |||
+ | <code bash> | ||
+ | tools/labs $ make skels | ||
</code> | </code> | ||
- | În cadrul directorului ''lab02-tasks/'' se găsesc resursele necesare pentru dezvoltarea exercițiilor de mai jos: fișiere schelet de cod sursă, fișiere Makefile și Kbuild, scripturi și programe de test. | ||
- | Vom dezvolta exercițiile pe sistemul de bază (stația ''asgard'') și apoi le vom testa pe [[:so2:resurse:masini-virtuale|mașina virtuală QEMU]]. După editarea și compilarea unui modul de kernel îl vom copia în directorul dedicat pentru mașina virtuală QEMU folosind o comandă de forma<code bash> | + | Pentru a genera scheletul pentru un singur laborator, vom folosi variabila de mediu ''LABS'': |
- | student@asgard:~/so2$ cp /path/to/module.ko ~/so2/qemu-so2/fsimg/root/modules/ | + | |
- | </code> unde ''/path/to/module.ko'' este calea către fișierul obiect aferent modulului de kernel. Apoi vom porni, din directorul ''~/so2/qemu-so2/'', mașina virtuală QEMU folosind comanda<code bash> | + | <code bash> |
- | student@asgard:~/so2/qemu-so2$ make | + | tools/labs $ make clean |
+ | tools/labs $ LABS=<lab name> make skels | ||
+ | </code> | ||
+ | |||
+ | <note important> | ||
+ | Numele laboratorului curent este ''kernel_modules''. | ||
+ | </note> | ||
+ | |||
+ | Similar, putem genera și scheletul pentru un singur exercițiu, atribuind valoarea ''<lab_name>/<task_name>'' variabilei ''LABS''. | ||
+ | |||
+ | <note> | ||
+ | Scheletul este generat în directorul ''tools/labs/skels''. | ||
+ | </note> | ||
+ | |||
+ | ==== Compilarea modulelor ==== | ||
+ | |||
+ | Comanda ''make build'' compilează toate modulele din directorul ''skels''. | ||
+ | |||
+ | <code bash> | ||
+ | student@eg106:~/so2/linux/tools/labs$ make build | ||
+ | echo "# autogenerated, do not edit " > skels/Kbuild | ||
+ | echo "ccflags-y += -Wno-unused-function -Wno-unused-label -Wno-unused-variable " >> skels/Kbuild | ||
+ | for i in ./kernel_modules/9-kdb ./kernel_modules/7-list-proc ./kernel_modules/3-error-mod ./kernel_modules/1-2-test-mod ./kernel_modules/5-oops-mod ./kernel_modules/6-cmd-mod ./kernel_modules/8-kprobes ./kernel_modules/4-multi-mod; do echo "obj-m += $i/" >> skels/Kbuild; done | ||
+ | ... | ||
+ | </code> | ||
+ | |||
+ | ==== Copierea modulelor pe mașina virtuală ==== | ||
+ | |||
+ | Putem copia modulele generate pe mașina virtuală folosind target-ul ''copy'' al comenzii make, atunci când mașina virtuală este oprită. | ||
+ | |||
+ | <code bash> | ||
+ | student@eg106:~/so2/linux/tools/labs$ make copy | ||
+ | student@eg106:~/so2/linux/tools/labs$ make boot | ||
+ | </code> | ||
+ | |||
+ | Alternativ, putem copia fișierele prin ''scp'', pentru e evita repornirea mașinii virtuale. Pentru detalii despre folosirea interacțiunea prin rețea cu mașina virtuală citiți [[https://ocw.cs.pub.ro/courses/so2/resurse/masini-virtuale#interactiunea_cu_masina_virtuala|Interacțiunea cu mașina virtuală]]. | ||
+ | |||
+ | ==== Testarea modulelor ==== | ||
+ | |||
+ | Modulele generate sunt copiate pe mașina virtuală în directorul ''/home/root/skels/<lab_name>/<task_name>''. | ||
+ | |||
+ | <code bash> | ||
+ | root@qemux86:~/skels/kernel_modules$ ls | ||
+ | 1-2-test-mod 3-error-mod 5-oops-mod 6-cmd-mod 7-list-proc 8-kprobes 9-kdb | ||
+ | root@qemux86:~/skels/kernel_modules$ ls 1-2-test-mod/ | ||
+ | hello_mod.ko | ||
</code> | </code> | ||
- | După pornirea mașinii virtuale QEMU vom putea folosi comenzi în fereastra QEMU pentru a încărca și descărca modulul de kernel:<code> | + | După pornirea mașinii virtuale QEMU vom putea folosi comenzi în fereastra QEMU (sau în ''minicom'') pentru a încărca și descărca modulul de kernel:<code> |
- | # insmod root/modules/module-name.ko | + | root@qemux86:~# insmod skels/<lab_name>/<task_name>/<module_name>.ko |
- | # rmmod root/modules/module-name | + | root@qemux86:~# rmmod skels/<lab_name>/<task_name>/<module_name>.ko |
- | </code> unde ''module-name'' este numele modulului de kernel. | + | </code> |
<note> | <note> | ||
Pentru dezvoltarea laboratorului, este recomandat să folosim trei terminale sau, mai bine, trei tab-uri de terminal. Pentru a deschide un nou tab de terminal folosim combinația de taste ''Ctrl+Shift+t''. Cele trei tab-uri de terminal îndeplinesc următoarele roluri: | Pentru dezvoltarea laboratorului, este recomandat să folosim trei terminale sau, mai bine, trei tab-uri de terminal. Pentru a deschide un nou tab de terminal folosim combinația de taste ''Ctrl+Shift+t''. Cele trei tab-uri de terminal îndeplinesc următoarele roluri: | ||
- | - În primul tab de terminal dezvoltăm modulul de kernel: editare, compilare, copiere în directorul dedicat pentru mașina virtuală QEMU. Lucrăm în directorul aferent rezultat în urma decomprimării arhivei de sarcini a laboratorului. | + | - În primul tab de terminal dezvoltăm modulul de kernel: editare, compilare, copiere în directorul dedicat pentru mașina virtuală QEMU. Lucrăm în directorul aferent rezultat în urma generării scheletului de laborator, din ''~/so2/linux/tools/labs/skels''. |
- | - În al doilea tab de terminal pornim mașina virtuală QEMU și apoi testăm modulul de kernel: încărcare/descărcare modul, rulare teste. Lucrăm în directorul aferent mașinii virtuale: ''~/so2/qemu-so2/''. | + | - În al doilea tab de terminal pornim mașina virtuală QEMU și apoi testăm modulul de kernel: încărcare/descărcare modul, rulare teste. Lucrăm în directorul aferent mașinii virtuale: ''~/so2/linux/tools/labs''. |
- | - În al treilea tab de terminal pornim un server UDP care să primească [[:so2:laboratoare:lab02#netconsole|mesajele de netconsole]]. Nu contează în ce director ne aflăm. Folosim comanda<code bash> | + | - În al treilea tab de terminal pornim [[:so2:laboratoare:lab02#minicom|minicom]] sau un server UDP care să primească [[:so2:laboratoare:lab02#netconsole|mesajele de netconsole]]. Nu contează în ce director ne aflăm. Folosim comanda<code bash> |
- | student@asgard:~$ netcat -lup 6666 | + | student@asgard:~$ nc -l -p 6000 -u |
</code> | </code> | ||
</note> | </note> | ||
Line 47: | Line 102: | ||
* Variabila ''ignore_loglevel'' este folosită pentru a ignora configurațiile de afișare a mesajelor de logging ale nucleului. În mod normal se poate stabili un prag peste care mesajele sunt afișate la terminal. Folosirea ''ignore_loglevel'' duce la ignorarea acelui prag. | * Variabila ''ignore_loglevel'' este folosită pentru a ignora configurațiile de afișare a mesajelor de logging ale nucleului. În mod normal se poate stabili un prag peste care mesajele sunt afișate la terminal. Folosirea ''ignore_loglevel'' duce la ignorarea acelui prag. | ||
</hidden> | </hidden> | ||
- | |||
- | <note tip> | ||
- | Pentru ''cscope'' parcurgeți [[:so2:laboratoare:lab01#cscope|secțiunea cscope din primul laborator]]. | ||
- | </note> | ||
<note warning> | <note warning> | ||
Line 59: | Line 110: | ||
<note tip> | <note tip> | ||
- | Atunci când folosiți ''cscope'', va trebui să vă aflați în directorul ''so2/linux-4.9.11/'' din directorul home al utilizatorului ''student''. | + | Atunci când folosiți ''cscope'', va trebui să vă aflați în directorul ''so2/linux/'' din directorul home al utilizatorului ''student''. |
</note> | </note> | ||
Line 79: | Line 130: | ||
La fel, dacă ați găsit mai multe match-uri și dacă ai deschis o subfereastră cu toate match-urile (folosind '':copen'') și dacă sunteți în căutarea locului de definiție a unui macro, este indicat să căutați în subfereastră (folosind ''/'' -- //slash//) după șirul ''define'' (șirul care indică locul de definiție a unui macro). | La fel, dacă ați găsit mai multe match-uri și dacă ai deschis o subfereastră cu toate match-urile (folosind '':copen'') și dacă sunteți în căutarea locului de definiție a unui macro, este indicat să căutați în subfereastră (folosind ''/'' -- //slash//) după șirul ''define'' (șirul care indică locul de definiție a unui macro). | ||
+ | </note> | ||
+ | |||
+ | <note tip> | ||
+ | Pentru mai multe detalii despre ''cscope'' parcurgeți [[:so2:laboratoare:lab01#cscope|secțiunea cscope din primul laborator]]. | ||
</note> | </note> | ||
==== 1. [1p] Module ==== | ==== 1. [1p] Module ==== | ||
Pentru a putea lucra cu modulele de kernel, vom realiza următorii pași, descriși și [[:so2:laboratoare:lab02:exercitii|mai sus în pagină]]: | Pentru a putea lucra cu modulele de kernel, vom realiza următorii pași, descriși și [[:so2:laboratoare:lab02:exercitii|mai sus în pagină]]: | ||
- | - Vom compila modulul de kernel. Adică vom rula, în directorul în care se găsesc sursele și fișierele de tip ''Makefile'' și ''Kbuild'' aferente modulului, comanda:<code> | + | - Vom genera scheletul de laborator, rulând comanda <code bash>LABS=kernel_modules make skels</code> în directorul ''tools/labs''. Această comandă copiază fișierele necesare laboratorului în directorul ''tools/labs/skels''. |
- | make | + | - Vom compila modulele de kernel. |
- | </code> | + | |
- | - Vom copia modulul în directorul din care va fi generat sistemul de fișiere al mașinii virtuale. Adică vom folosi comanda ''cp <nume-modul>.ko ~/so2/qemu-so2/fsimg/root/modules/''. | + | |
- | - Vom porni mașina virtuală. Adică vom rula, din cadrul directorului aferent mașinii virtuale (adică ''~/so2/qemu-so2/'') comanda<code> | + | |
- | make | + | |
- | </code> | + | |
- | Realizați pașii de mai sus pentru modulul din subdirectorul ''1-2-test-mod/'' din arhiva laboratorului. Urmăriți fișierele din subdirector. Apoi urmați pașii de mai sus pentru a porni mașina virtuală cu fișierul modul ''hello_mod.ko'' în sistemul de fișiere al mașinii virtuale. În cadrul mașinii virtuale, fișierul modul se găsește în directorul ''/root/modules/''. | + | <note important> |
- | + | Până la rezolvarea exercițiului 3, o să primiți o eroare de compilare la modului ''3-error-mod''. Puteți evita problema ștergând directorul ''skels/kernel_modules/3-error-mod/''. | |
- | <note tip> | + | |
- | Parcurgeți secțiunea [[:so2:laboratoare:lab02#Compilarea modulelor de kernel|Compilarea modulelor de kernel]] din laborator. | + | |
</note> | </note> | ||
- | Apoi urmați pașii uzuali în foosirea unui modul de kernel: | + | Vom rula, în directorul ''tools/labs'', comanda <code bash>make build</code>. Această comandă compilează modulele din toate exercițiile din laborator. |
+ | - Vom copia modulele compilate în mașina virtuală. Adică vom folosi comanda ''make copy''. | ||
+ | - Vom porni mașina virtuală. Adică vom rula, din cadrul directorului aferent mașinii virtuale (adică ''~/so2/linux/tools/labs/'') comanda<code> | ||
+ | make boot | ||
+ | </code> | ||
+ | |||
+ | Ne propunem să testăm pe mașina virtuală modulul din directorul ''1-2-test-mod/'' din scheletul laboratorului. Urmăriți fișierele din subdirector. | ||
+ | Urmați pașii de mai sus pentru a compila și copia modulele pe mașina virtuală, apoi testați modulul ''hello_mod.ko'' din directorul ''/home/root/skels/kernel_modules/1-2-test-mod''. | ||
+ | |||
+ | Apoi urmați **pașii uzuali** în folosirea unui modul de kernel: | ||
- Încărcați modulul în kernel. | - Încărcați modulul în kernel. | ||
- Listați modulele din kernel și verificați existența modulului curent. | - Listați modulele din kernel și verificați existența modulului curent. | ||
Line 104: | Line 161: | ||
<note tip> | <note tip> | ||
- | Parcurgeți secțiunea [[:so2:laboratoare:lab02#Încărcarea/descarcarea unui modul de kernel|Încărcarea/descarcarea unui modul de kernel]] din laborator. | + | Parcurgeți secțiunea [[:so2:laboratoare:lab02:exercitii#Testarea modulelor|Testarea modulelor]]. |
La descărcarea unui modul din kernel poate fi precizat doar numele modulului (fără extensie). | La descărcarea unui modul din kernel poate fi precizat doar numele modulului (fără extensie). | ||
</note> | </note> | ||
- | |||
- | Este indicat să facem curat în locul în care am lucrat. Pentru aceasta, pe mașina fizică, în subdirectorul ''1-2-test-mod/'' în care ați compilat sursele modulului, pentru a curăța directorul rulați comanda<code> | ||
- | make clean | ||
- | </code> | ||
==== 2. [1p] Printk ==== | ==== 2. [1p] Printk ==== | ||
Line 122: | Line 175: | ||
Citiți secțiunea [[:so2:laboratoare:lab02#Printk Debugging|Printk Debugging]] din laborator și urmăriți precizările referitoare la folosirea funcției ''printk''. | Citiți secțiunea [[:so2:laboratoare:lab02#Printk Debugging|Printk Debugging]] din laborator și urmăriți precizările referitoare la folosirea funcției ''printk''. | ||
- | Pentru aceasta va trebui să editați opțiunile de bootare din fișierul ''/home/student/so2/qemu-so2/Makefile'', și să adăugați opțiunea de boot ''ignore_loglevel'' pe linia care începe cu ''%%append root...%%'' | + | Pentru aceasta va trebui să editați opțiunile de bootare din fișierul ''tools/labs/qemu/Makefile'', și să adăugați opțiunea de boot ''ignore_loglevel'' pe linia care începe cu ''%%append root...%%'' |
</note> | </note> | ||
- | Compilați modulul. Încărcați și apoi descărcați modulul din kernel. Mesajele sunt afișate la consola mașinii virtuale. Dacă ați deschis pseudo-terminalul indicat de qemu (pentru ''char device redirected to /dev/pts/19 (label virtiocon0)'' folosiți ''minicom -D /dev/pts/19'') atunci veti observa mesajele și acolo. | + | Compilați modulul. Încărcați și apoi descărcați modulul din kernel. Mesajele sunt afișate la consola mașinii virtuale. Dacă ați deschis pseudo-terminalul indicat de qemu (pentru ''char device redirected to /dev/pts/19 (label virtiocon0)'' folosiți ''minicom -D /dev/pts/19'') sau, mai simplu, link-ul simbolic ''serial.pts'' (folosiți ''minicom -D serial.pts'') atunci veți observa mesajele și acolo. |
==== 3. [1p] Error ==== | ==== 3. [1p] Error ==== | ||
- | | + | |
+ | <note important> | ||
+ | Dacă ați șters directorul ''3-error-mod/'' pentru a evita eroarea de compilare, puteți genera doar scheletul pentru acest exercițiu folosind urmăroarea comandă: <code bash>LABS=kernel_modules/3-error-mod make skels</code> | ||
+ | </note> | ||
Intrați în directorul ''3-error-mod/''. Obțineți modulul de kernel asociat. De ce au apărut erori de compilare? **Hint**: Cu ce diferă acest modul de modulul precedent? | Intrați în directorul ''3-error-mod/''. Obțineți modulul de kernel asociat. De ce au apărut erori de compilare? **Hint**: Cu ce diferă acest modul de modulul precedent? | ||
Line 136: | Line 193: | ||
Intrați în directorul ''4-multi-mod/''. Inspectați fișierele sursă C: ''mod1.c'' și ''mod2.c''. Exemplul este unul academic (modulul 2 conține doar definiția unei funcții folosite de modulul 1). | Intrați în directorul ''4-multi-mod/''. Inspectați fișierele sursă C: ''mod1.c'' și ''mod2.c''. Exemplul este unul academic (modulul 2 conține doar definiția unei funcții folosite de modulul 1). | ||
- | Creați un fișier Kbuild care să conducă la crearea fișierului-modul ''multi_mod.ko'' pornind de la cele două fișiere sursă C. **Hint**: Citiți secțiunea [[:so2:laboratoare:lab02#Compilarea modulelor de kernel|Compilarea modulelor de kernel]] din laborator. | + | Modificați fișierul ''Kbuild'' astfel încât să conducă la crearea fișierului-modul ''multi_mod.ko'' pornind de la cele două fișiere sursă C. **Hint**: Citiți secțiunea [[:so2:laboratoare:lab02#Compilarea modulelor de kernel|Compilarea modulelor de kernel]] din laborator. |
Compilați, încărcați și descărcați modulul. Mesajele sunt afișate corespunzător la consolă. | Compilați, încărcați și descărcați modulul. Mesajele sunt afișate corespunzător la consolă. | ||
Line 177: | Line 234: | ||
==== 7. [1.5p] Proc Info ==== | ==== 7. [1.5p] Proc Info ==== | ||
- | Intrați în directorul ''7-list-proc/''. Creați un modul care să afișeze informații despre procesul curent. Numele modulului trebuie sa fie ''list_proc.ko''. | + | Intrați în directorul ''7-list-proc/''. Completați modulul astfel încât să afișeze informații despre procesul curent. Numele modulului trebuie rezultat este ''list_proc.ko''. |
- | Afișați process ID-ul (PID-ul procesului) și numele executabilului. Informațiile vor fi afișate atât la încărcarea cât și la descărcarea modulului. | + | Urmăriți comentariile marcate cu ''TODO''. Afișați process ID-ul (PID-ul procesului) și numele executabilului. Informațiile vor fi afișate atât la încărcarea cât și la descărcarea modulului. |
<note tip> | <note tip> | ||
- | Nu începeți de la zero. Copiați fișierele ''Makefile'' și ''Kbuild'' și fișierele sursă C din unul din directoarele anterioare și modificați-le corespnzător. | ||
- | |||
În kernel-ul Linux un proces este descris de structura [[http://lxr.free-electrons.com/source/include/linux/sched.h?v=3.13#L1042|struct task_struct]]. | În kernel-ul Linux un proces este descris de structura [[http://lxr.free-electrons.com/source/include/linux/sched.h?v=3.13#L1042|struct task_struct]]. | ||
- | Folositi [[http://lxr.free-electrons.com/|LXR]] sau ''cscope'' pentru a afla conținutul unei structuri din nucleu (în cazul de față ''struct task_struct''). | + | Folositi [[http://lxr.bootlin.com/|LXR]] sau ''cscope'' pentru a afla conținutul unei structuri din nucleu (în cazul de față ''struct task_struct''). |
Pentru a găsi câmpul structurii ce conține numele executabilului aferent, căutați șirul //executable//. | Pentru a găsi câmpul structurii ce conține numele executabilului aferent, căutați șirul //executable//. | ||
Line 198: | Line 253: | ||
Repetați apoi operația de încărcare/descărcare. Observați că diferă PID-urile proceselor afișate. Acest lucru se întâmplă pentru că la încărcarea modulului se creează un proces pornind de la executabilul ''/sbin/insmod'' iar la descărcarea modulului se creează un proces pornind de la executabilul ''/sbin/rmmod''. Procesele vor fi diferite. | Repetați apoi operația de încărcare/descărcare. Observați că diferă PID-urile proceselor afișate. Acest lucru se întâmplă pentru că la încărcarea modulului se creează un proces pornind de la executabilul ''/sbin/insmod'' iar la descărcarea modulului se creează un proces pornind de la executabilul ''/sbin/rmmod''. Procesele vor fi diferite. | ||
- | ==== 8. [2.5p] Kprobes ==== | ||
- | |||
- | **[0.5p]** Intrați în directorul ''8-kprobes/'' din arhiva de resurse a laboratorului. Urmăriți fișierul sursă ''kprobes.c''. Modulul folosește ''jprobes'' pentru a urmări apelul ''do_execve_common'', aferent apelului de sistem [[http://man7.org/linux/man-pages/man3/exec.3.html|exec]]. | ||
- | |||
- | Compilați și încărcați în mașina virtuală modulul de kernel rezultat (''kprobes.c''). Urmăriți mesajele de debug și comparați cu procesele existente în sistem. | ||
- | |||
- | <note> | ||
- | Este chiar exmplul din laborator din secțiunea [[:so2:laboratoare:lab02#Kprobes|Kprobes]]. | ||
- | </note> | ||
- | |||
- | **[2p]** Creați un modul care analizează valoarea de retur a funcției [[http://lxr.free-electrons.com/source/kernel/fork.c?v=4.9#L1904|_do_fork]]. La întoarcerea din funcție, afișați valoarea de retur, numele și pid-ul procesului părinte și pid-ul procesului curent. | ||
- | |||
- | <note tip> | ||
- | Revedeți secțiunea [[:so2:laboratoare:lab02#Kprobes|Kretprobes]]. | ||
- | |||
- | Puteți urmări și exemplul de cod din sursele nucleului din [[https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/samples/kprobes/kretprobe_example.c?h=v3.13|samples/kprobes/kretprobe_example.c]]. | ||
- | </note> | ||
- | |||
- | <note tip> | ||
- | Urmăriți comentariile marcate cu ''TODO'' din cadrul fișierului cod sursă ''kprobes.c''. | ||
- | </note> | ||
- | |||
- | <note tip> | ||
- | Pentru a afișa adresa de retur în handler-ul de ''kretprobe'' (adică în funcțion ''my_ret_handler'') folosiți funcția [[http://lxr.free-electrons.com/source/arch/x86/include/asm/ptrace.h?v=3.13#L82|regs_return_value]]. | ||
- | </note> | ||
- | |||
- | <note tip> | ||
- | Pentru a obține structura de tip ''struct task_struct *'' aferentă procesului părinte al procesului curent folosiți construcția ''%%current->parent%%''. | ||
- | </note> | ||
- | |||
- | <note> | ||
- | Procesul interceptat de ''kretprobe'' este shell-ul. În mașina virtuală procesul său părinte este procesul ''init''/''busybox'' (cu PID-ul ''1''). Valoarea întoarsă de apelul [[http://lxr.free-electrons.com/source/kernel/fork.c?v=4.9#L1904|_do_fork]] afișată în cadrul handler-ului ''kretprobe'' este PID-ul procesului copil proaspăt creat, așa cum se întâmplă și în user space în cazul apelului [[http://man7.org/linux/man-pages/man2/fork.2.html|fork]] pentru procesul părinte. | ||
- | </note> | ||
- | Puteți folosi comanda ''pstree -p'' pentru a afișa ierarhia de procese a sistemului și pentru a verifica astfel, informațiile afișate de handler-ul de ''kretprobe'' în modulul de kernel. Puteți, deasemenea, confirma acest lucru verificând pid-ul procesului din proba anterioară ( ''do_execveat_common''). | + | ==== Extra ==== |
- | ==== Extra: Pentru acasă ==== | + | |
**1. [1KP] KDB** | **1. [1KP] KDB** | ||
- | Intrați în directorul ''9-kdb/''. Activați KDB peste serială și intrați în modul KDB folosind SysRq. | + | Intrați în directorul ''8-kdb/''. Activați KDB peste serială și intrați în modul KDB folosind SysRq. |
- | Conectațivă la pseudo-terminalul conectat la virtiocon0 folosind minicom, configurați KDB pentru a folosi portul serial hvc0 (''echo hvc0 > /sys/module/kgdboc/parameters/kgdboc'') și activați-l folosind SysRq (Ctrl+O g). Analizați starea curentă a sistemului (''help'' pentru a vedea comenzile KDB disponibile). Continuați execuția kernelului folosind comand ''go''. | + | Conectați-vă la pseudo-terminalul conectat la virtiocon0 folosind minicom, configurați KDB pentru a folosi portul serial hvc0 (''echo hvc0 > /sys/module/kgdboc/parameters/kgdboc'') și activați-l folosind SysRq (Ctrl+O g). Analizați starea curentă a sistemului (''help'' pentru a vedea comenzile KDB disponibile). Continuați execuția kernelului folosind comand ''go''. |
Inserați modulul ''hello_kdb''. Modulul va simula un bug la scrierea în fișierul ''/proc/hello_kdb_bug''. Pentru a simula un bug folosiți comanda de mai jos: <code bash> | Inserați modulul ''hello_kdb''. Modulul va simula un bug la scrierea în fișierul ''/proc/hello_kdb_bug''. Pentru a simula un bug folosiți comanda de mai jos: <code bash> | ||
Line 246: | Line 267: | ||
Analizați stacktrace-ul și determinați codul care a generat bugul. Cum putem afla din KDB adresa la care a fost încărcat modulul? | Analizați stacktrace-ul și determinați codul care a generat bugul. Cum putem afla din KDB adresa la care a fost încărcat modulul? | ||
- | În paralel, folosiți GDB într-o nouă fereastră pentru a vizualiza codul pornind de la informațiile din KDB. ** Hint: ** Încărcați fișierul de simboluri. Folosiți ''info line''. | + | În paralel, folosiți GDB într-o nouă fereastră pentru a vizualiza codul pornind de la informațiile din KDB. |
+ | ** Hint: ** Încărcați fișierul de simboluri. Folosiți ''info line''. | ||
La scrierea în fișierul ''/proc/hello_kdb_break'', modulul va incrementa variabila ''kdb_write_address''. Intrați în KDB și setați un breakpoint pentru fiecare acces de scriere al variabilei ''kdb_write_address''. Reveniți în kernel pentru a declanșa o scriere folosind: <code bash> echo 1 > /proc/hello_kdb_break </code> | La scrierea în fișierul ''/proc/hello_kdb_break'', modulul va incrementa variabila ''kdb_write_address''. Intrați în KDB și setați un breakpoint pentru fiecare acces de scriere al variabilei ''kdb_write_address''. Reveniți în kernel pentru a declanșa o scriere folosind: <code bash> echo 1 > /proc/hello_kdb_break </code> | ||
Line 269: | Line 291: | ||
Porniți de la un modul existent. | Porniți de la un modul existent. | ||
- | Investigați structura [[http://lxr.free-electrons.com/source/include/linux/sched.h?v=3.13#L1042|struct task_struct]], structura [[http://lxr.free-electrons.com/source/include/linux/mm_types.h?v=3.13#L344|struct mm_struct]] și structura [[http://lxr.free-electrons.com/source/include/linux/mm_types.h?v=3.13#L240|struct vm_area_struct]]. O zonă de memorie este indicată de o structură de tipul | + | Investigați structura [[https://elixir.bootlin.com/linux/v4.15.7/source/include/linux/sched.h#L520|struct task_struct]], structura [[https://elixir.bootlin.com/linux/v4.15.7/source/include/linux/mm_types.h#L356|struct mm_struct]] și structura [[https://elixir.bootlin.com/linux/v4.15.7/source/include/linux/mm_types.h#L274|struct vm_area_struct]]. O zonă de memorie este indicată de o structură de tipul [[https://elixir.bootlin.com/linux/v4.15.7/source/include/linux/mm_types.h#L274|struct vm_area_struct]]. |
Să includeți header-ele în care sunt definite structurile necesare. | Să includeți header-ele în care sunt definite structurile necesare. | ||
Line 276: | Line 298: | ||
**4. [2KP] Dynamic Debugging** | **4. [2KP] Dynamic Debugging** | ||
- | Intrați în directorul ''10-dyndbg/'' și compilați modulul ''dyndbg.ko''. | + | Intrați în directorul ''9-dyndbg/'' și compilați modulul ''dyndbg.ko''. |
Familiarizați-vă cu sistemul de fișiere ''debugfs'' montat în ''/debug'' și analizați conținutul fișierului ''/debug/dynamic_debug/control''. Inserați modulul dyndbg.ko și observați noul conținut al fișierului ''dynamic_debug/control''. | Familiarizați-vă cu sistemul de fișiere ''debugfs'' montat în ''/debug'' și analizați conținutul fișierului ''/debug/dynamic_debug/control''. Inserați modulul dyndbg.ko și observați noul conținut al fișierului ''dynamic_debug/control''. |