Zadanie 4: poprawkowe

Data ogłoszenia: 12.06.2018

Termin oddania: 04.09.2018

Materiały dodatkowe

Wprowadzenie

W systemie Linux, dostęp do plików może być ustawiany dla właściciela pliku, grupy pliku lub wszystkich pozostałych. Można też ustawiać uprawnienia dla konkretnego użytkownika lub grupy (ACL), ale wszystkie te operacje dotyczą zawsze całego pliku. Jednak czasem przydałoby się dać użytkownikowi dostęp to części pliku, w szczególności jak ma stałą strukturę.

Zadanie

Napisać patch do jądra, dodający rozbudowane ACL do systemu plików ext4, pozwalające na nadawanie dostępu do części pliku. Mechanizm powinien pozwalać nadać uprawnienie odczytu i/lub zapisu do części pliku (od-do bajtów) dla wskazanych użytkowników lub grup. Plik do którego proces nie ma normalnego prawa odczytu, ale ma prawo odczytu do jego części, powinno dać się otworzyć do odczytu, ale odczyty spoza dozwolonej części powinny zwracać błąd EACCESS. Jeśli odczyt rozpoczyna się w dozwolonej części, ale miałby się skończyć poza nią, należy pozwolić odczytać tylko tyle bajtów ile jest dozwolonych. Analogicznie dla zapisu. Dla mmap() należy pozwolić na mapowania dozwolonych fragmentów (proces ma dostęp do całego zamapowanego obszaru), z odpowiadającymi flagami PROT_READ, PROT_WRITE. Jeśli obszar do zamapowania wykracza poza dozwolony w dowolną stronę, syscall mmap() powinien zakończyć się błędem. Przy decyzji o dostępie do danego fragmentu pliku decydują uprawnienia z momentu otwarcia pliku.

Prawa do wykonywania dla podzbioru pliku nie obsługujemy. Rozbudowane ACL dotyczą wyłącznie zwykłych plików, próba ustawienia na dowolnym innym typie pliku powinna kończyć się błędem EINVAL.

Pliki bez rozbudowanych ACL powinny zachowywać się bez zmian.

Należy również dostarczyć bibliotekę z funkcjami do ustawiania uprawnień. Rozszerzone ACL należy przechowywać jako xattr, w przestrzeni nazw “system.”. Biblioteka może ustawiać uprawnienia bezpośrednio modyfikując te atrybut(y), ale jądro musi weryfikować zawartość i odrzucać nieprawidłowo sformatowane zmiany. Nadawać/odbierać uprawnienia powinien móc (wyłącznie) właściciel pliku oraz procesy posiadające CAP_FOWNER.

Szczegóły

Biblioteka powinna udostępniać następujące funkcje:

struct extacl {
    uint16_t type;
    uint16_t _pad;
    uint32_t uid_gid;
    uint64_t range_start;
    uint64_t range_len;
}

int extacl_set_file(const char *path, struct extacl *extacl, size_t extacl_len);
int extacl_get_file(const char *path, struct extacl *extacl, size_t extacl_len);

Funckcja extacl_get_file pobiera rozbudowany ACL z pliku wskazanego przez path i zapisuje w buforze extacl co najwyżej extacl_len elementów, a następnie zwraca łączną liczbę wpisów połączonych z danym plikiem (w szczególności wynik może być większy niż extacl_len jeśli extacl jest za mały żeby pomieścić wszystkie wpisy; ale należy zadbać aby nie zapisywać poza podany bufor). W przypadku błędu, funkcja zwraca -1 i ustawia errno na odpowiednią wartość. Jeśli rozbudowany ACL nie był ustawiony, funkcja zwraca 0.

Funkcja extacl_set_file ustawia rozbudowany ACL na pliku wskazanym przez path. Pożądane uprawnienia przekazane są w tablicy extacl, długości extacl_len. Jeśli któregokolwiek z wpisów nie udało się ustawić, funkcja powinna zwrócić błąd (-1 i odpowienie errno), pozostawiając ACL bez zmian. W przeciwnym wypadku, funkcja zwraca exact_len.

Pole type może zawierać jedną z wartości:

  • EXTACL_USER_READ (0x1) - prawo do odczytu do zakresu [range_start, range_start+range_len) dla użytkownika wskazanego w polu uid_gid.
  • EXTACL_USER_WRITE (0x2) - prawo do zapisu do zakresu [range_start, range_start+range_len) dla użytkownika wskazanego w polu uid_gid.
  • EXTACL_GROUP_READ (0x3) - prawo do odczytu do zakresu [range_start, range_start+range_len) dla grupy wskazanej w polu uid_gid.
  • EXTACL_GROUP_WRITE (0x4) - prawo do zapisu do zakresu [range_start, range_start+range_len) dla grupy wskazanej w polu uid_gid.

Zasady oceniania

Za zadanie można uzyskać do 10 punktów. Na ocenę zadania składają się dwie części:

  • wynik automatycznych testów (od 0 do 10 punktów)
  • ocena kodu rozwiązania (od 0 do -10 punktów)

Punktacja

Testów było 18, 10/18 punkta za każdy. Link do archiwum na początku treści.

Punkty z oceny kodu:

  1. -0.5 wadliwa obsługa nie-zapatchowanego filesystemu w bibliotece (fsetxattr zwraca EOPNOTSUPP) - SEGV, nieskończona pętla itp
  2. -0 używanie uid zamiast fsuid (ale nie było w treści)
  3. -1 nieprawidłowa obsługa pread()/pwrite() - np ignorowanie ostatniego parametru (offset)
  4. -1 możliwość ustawienia extacl z pominięciem walidacji (np. bezpośredni zapis xattr dopuszczony i omija walidację)
  5. -0.5 extacl_set_file zwraca 0 przy sukcesie
  6. -1 przy obsłudze mmap, mylenie pgoff (strony) z offsetem w bajtach
  7. -0.5 nieprawidłowe kody błędów (np EPERM zamiast EACCES)

Testy były uruchamiane z założeniem że powyższe błędy są naprawione, tzn. powyższa lista ma priorytet nad testami, punkty za ten sam błąd nie są odejmowane dwa razy.

Forma rozwiązania

Jako rozwiązanie należy wysłać paczkę zawierającą:

  • patcha na jądro w wersji 4.9.13, w jednym z następujących formatów:
    • patch wygenerowaniy przez diffa z opcjami -uprN nakładający się przez patch -p1
    • git format-patch
  • plik(i) źródłowy biblioteki, wraz z makefile (lub równoważnym)
  • krótki opis rozwiązania

Rozwiązania prosimy nadsyłać na adres marmarek@mimuw.edu.pl z kopią do mwk@mimuw.edu.pl.

Pytania i odpowiedzi

Pytania należy wysyłać na adres marmarek@mimuw.edu.pl, odpowiedzi (wiążące) będą zamieszczane tutaj.