This shows you the differences between two versions of the page.
so2:laboratoare:lab05:exercitii [2018/03/21 09:55] ionel.ghita [4. [2p] Citirea bufferului printr-un apel ''read''] |
so2:laboratoare:lab05:exercitii [2019/03/20 11:49] (current) gabriel.bercaru [1. [2.5p] Alocare de porturi I/O] - fixed typo ('kdb' instead of 'kbd') |
||
---|---|---|---|
Line 104: | Line 104: | ||
Obiectivul exercițiilor următoare este să creați un driver pentru a intercepta tastele apăsate (//keylogger//). Driver-ul va intercepta IRQ-ul destinat controller-ului de tastatură și va inspecta codurile tastelor primite, stocându-le într-un buffer. | Obiectivul exercițiilor următoare este să creați un driver pentru a intercepta tastele apăsate (//keylogger//). Driver-ul va intercepta IRQ-ul destinat controller-ului de tastatură și va inspecta codurile tastelor primite, stocându-le într-un buffer. | ||
- | ==== 1. [1.5p] Alocare de porturi I/O ==== | + | ==== 1. [2.5p] Alocare de porturi I/O ==== |
Pentru început ne propunem să alocăm spații din zona I/O pentru dispozitive hardware. Vom vedea că nu putem să alocăm spațiu pentru tastatură întrucât regiunea aferentă e deja alocată. Apoi vom aloca spațiu I/O pentru porturi care nu sunt folosite. | Pentru început ne propunem să alocăm spații din zona I/O pentru dispozitive hardware. Vom vedea că nu putem să alocăm spațiu pentru tastatură întrucât regiunea aferentă e deja alocată. Apoi vom aloca spațiu I/O pentru porturi care nu sunt folosite. | ||
Line 141: | Line 141: | ||
Descărcați modulul din kernel folosind comanda<code> | Descărcați modulul din kernel folosind comanda<code> | ||
- | rmmod kdb | + | rmmod kbd |
</code> și verificați acum conținutul fișierului ''/proc/ioports''; observți că a dispărut alocarea spațiului I/O pentru cele două porturi. | </code> și verificați acum conținutul fișierului ''/proc/ioports''; observți că a dispărut alocarea spațiului I/O pentru cele două porturi. | ||
Line 148: | Line 148: | ||
</note> | </note> | ||
- | ==== 2. [1.5p] Rutina de tratare a întreruperii ==== | + | ==== 2. [2p] Rutina de tratare a întreruperii ==== |
Urmărim să înregistrăm o rutină de tratare a întreruperii de tastatură. Veți scrie o funcție (rutină) de tratare a înteruperii și o veți înregistra folosind ''[[https://elixir.bootlin.com/linux/v4.15/source/include/linux/interrupt.h#L145|request_irq]]''. | Urmărim să înregistrăm o rutină de tratare a întreruperii de tastatură. Veți scrie o funcție (rutină) de tratare a înteruperii și o veți înregistra folosind ''[[https://elixir.bootlin.com/linux/v4.15/source/include/linux/interrupt.h#L145|request_irq]]''. | ||
Line 207: | Line 207: | ||
<note tip> | <note tip> | ||
Pentru afișare în cadrul handler-ului de întrerupere folosiți o construcție de forma:<code> | Pentru afișare în cadrul handler-ului de întrerupere folosiți o construcție de forma:<code> | ||
- | pr_info("IRQ:% d, scancode = 0x% x (% u,% c) \ n" | + | pr_info("IRQ %d: scancode=0x%x (%u) pressed=%d ch=%c\n", |
- | irq_no, scancode, scancode, scancode); | + | irq_no, scancode, scancode, pressed, ch); |
</code> | </code> | ||
unde ''scancode'' este valoarea registrului citit cu ajutorul funcției ''i8042_read_data()''. | unde ''scancode'' este valoarea registrului citit cu ajutorul funcției ''i8042_read_data()''. | ||
Line 256: | Line 256: | ||
<note tip> | <note tip> | ||
Pentru afișare în cadrul handler-ului de întrerupere folosiți o construcție de forma:<code> | Pentru afișare în cadrul handler-ului de întrerupere folosiți o construcție de forma:<code> | ||
- | printk(LOG_LEVEL "IRQ %d: scancode=0x%x (%u) pressed=%d ch=%c\n", | + | pr_info(LOG_LEVEL "IRQ %d: scancode=0x%x (%u) pressed=%d ch=%c\n", |
irq_no, scancode, scancode, pressed, ch); | irq_no, scancode, scancode, pressed, ch); | ||
</code> | </code> | ||
Line 324: | Line 324: | ||
O să obțineți conținutul bufferului keylogger-ului din kernel space. | O să obțineți conținutul bufferului keylogger-ului din kernel space. | ||
- | ==== 5. [3p] Curățarea buffer-ului dacă este tastată o parolă ==== | + | ==== 5. [1.5p] Curățarea buffer-ului la scriere ==== |
- | Dorim să %%"curățăm"%% buffer-ul dacă este tastată o parolă. În acel moment buffer-ul va fi resetat: conținutul său va fi resetat și dimensiunea va fi ''0''. | + | Dorim să %%"curățăm"%% buffer-ul atunci când se scrie în device node-ul asociat driver-ului. În acel moment buffer-ul va fi resetat: conținutul său va fi resetat și dimensiunea va fi ''0''. |
- | Implementarea o veți face în fișierul ''kbd.c''. În rutina de tratare a întreruperii veți reține în câmpul ''passcnt'' câte caractere din parolă au fost potrivite. Parola este definită de macro-urile ''MAGIC_WORD'' și ''MAGIC_WORD_LEN''. | + | Implementarea o veți face în fișierul ''kbd.c''. Urmăriți comentariile marcate cu ''TODO 5''. Implementați funcția ''reset_buffer'' și adăugați operația ''write'' la ''kbd_fops''. |
- | + | ||
- | Când se detectează întreaga parolă, curătați buffer-ul. Pentru curățare, reinițializați câmpul ''buf_idx'' la valoarea ''0'' și umpleți cu ''0''-uri buffer-ul. | + | |
- | + | ||
- | La primirea unui caracter nou, verificați dacă acesta corespunde cu caracterul de pe poziția curentă din parolă. În caz afirmativ, incrementați contorul; altfel, resetați counterul la 0. | + | |
<note tip> | <note tip> | ||
- | În momentul resetării buffer-ului, în handler-ul de întrerupere va trebui să folosiți spinlock-ul pentru accesul exclusiv la buffer. Este posibil ca rutina de read să fie procesată de pe alt procesor și să acceseze buffer-ul în momentul în care handler-ul de întrerupere îl modifică. Veți folosi funcțiile [[https://elixir.bootlin.com/linux/v4.15/source/include/linux/spinlock.h#L308|spin_lock]] și [[https://elixir.bootlin.com/linux/v4.15/source/include/linux/spinlock.h#L348|spin_unlock]]. | + | În momentul resetării buffer-ului, va trebui să folosiți spinlock-ul cu dezactivarea întreruperilor pentru accesul exclusiv la buffer. |
Parcurgeți secțiunea [[:so2:laboratoare:lab05#utilizare_spinlock-uri|Utilizarea spinlock-uri]]. | Parcurgeți secțiunea [[:so2:laboratoare:lab05#utilizare_spinlock-uri|Utilizarea spinlock-uri]]. | ||
Line 347: | Line 343: | ||
cat /dev/kbd | cat /dev/kbd | ||
</code> | </code> | ||
- | Apăsați pe taste și apoi apăsați conținutul macro-ului ''MAGIC_WORD'' (adică ''root'') și apoi consultați din nou conținutul buffer-ului. Ar trebui să fie resetat. | + | Apăsați pe taste și apoi rulați comanda ''echo "clear" > /dev/kbd'' și apoi consultați din nou conținutul buffer-ului. Ar trebui să fie resetat. |
===== Extra ===== | ===== Extra ===== | ||
- | |||
- | ==== [1 karma] Resetarea buffer-ului în rutina de read ==== | ||
- | |||
- | Implementarea curentă este problematică pentru că rutina de tratare a întreruperii este cea care face resetarea buffer-ului, lucru care este consumator de timp și nerecomandat să fie făcut în context întrerupere. | ||
- | |||
- | O soluție este să actualizăm comportamentul astfel încât resetarea buffer-ului să se producă la apelul funcției ''kbd_read()''. După ce informația este copiată în user space, buffer-ul este resetat. Nu mai resetăm în momentul tastării | ||
- | |||
- | Simplificați implementarea în așa fel încât resetarea buffer-ului să se producă în funcția ''kbd_read()'' imediat după copierea datele în user space. | ||
- | |||
- | <note tip> | ||
- | În momentul în care copiați datele în buffer-ul temporare ''tmp_buf'' resetați buffer-ul principal: adică umpleți buffer-ul ''buf'' cu zero-uri și inițialiați ''buf_idx'' la ''0''. | ||
- | </note> | ||
- | |||
- | Pentru verificarea după citirea din ''/dev/kbd'' veți avea buffer-ul resetat. Citiri ulterioare vor găsi buffer-ul gol. | ||
==== [3 karma] Utilizare kfifo ==== | ==== [3 karma] Utilizare kfifo ==== |