Differences

This shows you the differences between two versions of the page.

Link to this comparison view

so2:laboratoare:lab02:exercitii [2018/02/26 18:03]
ionel.ghita [Laborator 2: Exerciții]
so2:laboratoare:lab02:exercitii [2019/02/25 15:18] (current)
ionel.ghita [Extra]
Line 102: 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 114: 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 134: 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 laboratorrulâ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/​''​. +<note important>​ 
-  - Vom porni mașina virtuală. Adică vom rula, din cadrul directorului aferent mașinii virtuale (adică ''​~/​so2/​qemu-so2/''​) comanda<​code>​ +Până la rezolvarea exercițiului 3, o să primiți o eroare de compilare la modului ​''​3-error-mod''​. Putețevita problema ștergând directorul ​''​skels/​kernel_modules/​3-error-mod/''​. 
-make+</​note>​ 
 + 
 +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>​ </​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/''​. +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''​.
-<note tip> +
-Parcurgeți secțiunea [[:​so2:​laboratoare:​lab02#​Compilarea modulelor de kernel|Compilarea modulelor de kernel]] din laborator. +
-</​note>​+
  
-Apoi urmați pașii uzuali în foosirea ​unui modul de kernel:+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 159: 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 177: 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 191: 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 232: 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 253: 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 301: 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 324: 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 331: 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''​.
so2/laboratoare/lab02/exercitii.1519661032.txt.gz · Last modified: 2018/02/26 18:03 by ionel.ghita
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0