Do spisu tresci tematu 3

3.3.2 System plikow proc_fs



Spis tresci


Wprowadzenie

proc_fs jest ciekawym systemem plikow, standardowo montowanym w katalogu /proc. Jako, ze tematem calego rozdzialu jest sledzenie procesow, w tym punkcie skoncentruje sie na opisie mozliwosci proc_fs w zakresie dostepu do danych innych procesow, a pomijajac inne aspekty. (W szczegolnosci nie pisze nic o - niewatpliwie ciekawym - sposobie implementacji proc_fs jako systemu plikow bez urzadzenia fizycznego. Bedzie to na pewno opisane w rozdziale dotyczacym systemu plikow, jest rowniez szczegolowe opracowanie w KHG.)

Katalog /proc

Wprawdzie system proc_fs mozna podlaczyc w dowolnym miejscu drzewa katalogow, jednakze polecany jest katalog /proc, glownie ze wzgledu na to, ze wiele programow ma te nazwe zakodowana na stale.

Po zmianie katalogu biezacego na /proc widac wiele katalogow nazwanych liczbami, katalogi net,self i ewentualnie scsi oraz kilka(nascie) plikow. Pliki te zawieraja opis systemu (cpuinfo, devices, dma, filesystems, ioports, pci, version), danych statystycznych (interrupts, loadavg, meminfo, stat) oraz pliku umozliwiajacego dostep do dowolnej komorki pamieci (kcore). Katalog net, jak jego nazwa wskazuje, zawiera statystyczne informacje dotyczace dzialania podsystemu sieci (tzn. interfejsow sieciowych i protokolow) oraz informacje o ich konfiguracji. Katalog scsi jest obecny tylko na komputerach z kontrolerami urzadzen tego standardu, i przechowuje informacje o nich.

Najbardziej interesujace, przynajmniej z punktu widzenia komunikacji miedzyprocesowej, sa katalogi oznaczane liczbami. Liczby te to po prostu numery procesow (istniejacych w momencie przegladania zawartosci katalogu /proc). Ponadto, katalog self odpowiada katalogowi o numerze procesu wywolujacego. W kazdym z takich katalogow znajduja sie nastepujace pliki:

Podkatalog fd zawiera pliki bedace dowiazaniami do otwartych plikow procesu, tzn. np. gdy znajduje sie tam plik 0, to proces ma otwarty plik o deskryptorze 0.

Jak z tego, z koniecznosci skrotowego, opisu widac, proc_fs mozna uzywac do przegladania zawartosci przestrzeni adresowej procesow, co, oczywiscie, jest forma komunikacji miedzyprocesowej. Przy okazji nalezy zauwazyc, ze uzytkownik moze uzyskac dostep tylko do swoich danych - chyba, ze jest nadzorca, wiec systemu proc_fs nie da sie w prosty sposob wykorzystac do wlamania sie do systemu.


Opis (niektorych) funkcji

Na poczatku tego punktu zaznaczylem, ze tu opisuje tylko implementacje funkcji zwiazanych z komunikacja miedzyprocesowa. Oczywiscie, uzytkownik nie wywoluje ich bezposrednio, lecz uzywa do tego celu standardowych funkcji systemu plikow (takich jak open, read etc.), a o wywolanie wlasciwych procedur z proc_fs troszczy sie jadro Linuxa, dokladniej VFS.

Pliki zwiazane z proc_fs znajduja sie w katalogu fs/proc/. Wiekszosc funkcji jest stosunkowo prosta - sprawdzenie praw dostepu odbywa sie w VFS, zanim jeszcze dostana one kontrole, a cala ich praca polega na skopiowaniu danych z odpowiednich struktur systemowych do dostarczonego bufora, ktory jest nastepnie odczytywany przez uzytkownika.

Przykladem takiej funkcji jest get_version, ktora po prostu kopiuje zawartosc zmiennej linux_banner.

Poniewaz zrozumienie tego typu funkcji nie nastrecza zadnych trudnosci, a opis bylby cokolwiek nudny, wiec pomine opis kilkunastu podobnych procedur, przechodzac do rzeczy (moim zdaniem) ciekawszych.

Funkcja mem_read:

DEFINICJA:
static int mem_read(struct inode * inode, struct file * file, char * buf, int count)

WYNIK: liczba odczytanych bajtow gdy wszystko ok
       -EINVAL - zly parametr count
       -ESRCH - nie istniejacy proces
       -EACCES - nie istniejaca pamiec
Jak nazwa wskazuje, funkcja ta sluzy do odczytu "pliku" /proc/<pid>/mem. Algorytm jest stosunkowo prosty: numer procesu jest zakodowany w numerze i-wezla (to jeden ze szczegolow zwiazanych z systemem plikow, ktorego opis pominalem). Funkcja sprawdza, czy proces zadajacy dostepu ma do tego prawo (funkcja get_task) oraz czy mozna uzyskac dostep do danego miejsca w pamieci (funkcja check_range, ktora ewentualnie modyfikuje parametr count). Pozniej, w petli, wykonywane sa nastepujace czynnosci:
{
   while(sa dane do skopiowania) do
   {
      if(nadeszly sygnaly) exit;
      znajdz wlasciwa strone w procesie, ktorego dane chcemy odczytac
         (do tego celu uzywane sa funkcje/makra pgd_offset, pmd_offset,
         pte_offset, pte_page);
      kopiuj jedna "porcje" danych (porcja nie moze znajdowac sie na
         dwoch stronach, czyli jej koniec jest wyznaczony albo przez koniec
         danych do kopiowania, albo koniec strony;
	 kopiowanie funkcja memcpy_tofs);
      uaktualnij wartosci zmiennych roboczych (adresow zrodlowego i
         docelowego, ilosci danych do skopiowania);
   }
}

Funkcja mem_write, mimo, ze jej kod znajduje sie w pliku [fs/proc/mem.h], nie jest, niestety, dostepna, ze wzgledu na bledy w jej implementacji. (Patrz komentarz na poczatku tego pliku.) Podobnie, pomijam funkcje mem_mmap, o ktorej mozna przeczytac, ze nie mozna na niej polegac.

Funkcja mem_lseek:

DEFINICJA:
static int mem_lseek(struct inode * inode, struct file * file, off_t offset, int orig)

WYNIK: pozycja w pliku gdy wszystko ok
       -EINVAL gdy blad
Po prostu ustawia pole f_pos w strukturze file, w zaleznosci od wartosci parametru orig: gdy orig == 0 na offset, gdy orig == 1 na f_pos+offset.

Funkcja get_task:

DEFINICJA:
static struct task_struct * get_task(int pid)

WYNIK: wskaznik na strukture procesu o numerze pid gdy ok
       NULL w przypadku bledu
Przeszukuje tablice procesow (task[]), az znajdzie proces o numerze pid. W przypadku procesow innych niz wywolujacy zwraca NULL gdy:

Funkcja check_range:

DEFINICJA:
static int check_range(struct task_struct * tsk, unsigned long addr, int count)

WYNIK: liczba bajtow mozliwych do odczytania gdy ok
       -EACCES gdy nie mozna czytac pamieci
Przeszukuje liste pamieci procesu, sprawdzajac, czy spod adresu addr da sie przeczytac count bajtow. Najpierw, z pomoca funkcji find_vma, znajduje pierwszy obszar pamieci, ktory moze zawierac adres addr. Gdy addr jest w tym obszarze, i obszar mozna czytac wykonuje sie petla (dopoki nie sprawdzimy, ze mozna odczytac count bajtow): - znajdz nastepny obszar pamieci; jezeli go nie ma, to koniec - sprawdz, czy jego poczatek sasiaduje z koncem obecnego obszaru; jezeli nie, to koniec - sprawdz, czy ten obszar mozna czytac, jezeli nie, to koniec Oczywiscie, blad wystepuje tylko jezeli nie da sie odczytac poczatkowego obszaru, w innych wypadkach zwrocona liczba bajtow jest mniejsza od count, ale nie jest to blad.

Bibliografia:


Pytania:

  1. Czemu ten opis jest tak krotki i nieszczegolowy?

    Glownie poniewaz tego tematu nie bylo na oficjalnej liscie, i opracowalem go z wlasnej i nieprzymuszonej woli, a nie mialem czasu wglebiac sie we wszystkie niuanse zwiazane z obsluga pamieci i proc_fs jako systemem plikow. Rzecz jasna, jezeli ktos bedzie mial jakies pytania, to sprobuje na nie odpowiedziec.


Autor: Lukasz Sznuk