Scroll to navigation

Capabilities(7) Miscellaneous Information Manual Capabilities(7)

NAZWA

capabilities - przegląd przywilejów linuksowych

OPIS

Ze względu na sprawdzanie uprawnień, tradycyjna uniksowa implementacja rozróżnia dwie kategorie procesów: procesy uprzywilejowane (których efektywny identyfikator użytkownika wynosi 0, zwane superużytkownikiem lub rootem, rzadziej administratorem), oraz procesy nieuprzywilejowane (z niezerowym efektywnym ID użytkownika). Procesy uprzywilejowane mogą pominąć wszelką kontrolę uprawnień jądra, natomiast procesy nieuprzywilejowane są przedmiotem pełnej kontroli uprawnień w oparciu o referencje procesu (zwykle: efektywne identyfikatory użytkownika oraz grupy, oraz uzupełniającą listę grup).

Począwszy od Linuksa 2.2, Linux dzieli uprawnienia tradycyjnie właściwe superużytkownikowi na odrębne jednostki, zwane przywilejami (ang. capabilities), które można niezależnie włączać i wyłączać. Przywileje są atrybutem przypisanym wątkowi.

Lista przywilejów

Poniżej przedstawiono listę ukazującą przywileje zaimplementowane w Linuksie oraz operacje lub zachowania, na które pozwala każdy z przywilejów:

Włączanie i wyłączanie audytu jądra; zmiana reguł filtrowania audytu; pobieranie statusu audytu i reguł filtrowania.
Zezwala na odczyt dziennika audytu za pomocą gniazda multicastowego netlink.
Zapisywanie rekordu do dziennika audytu jądra
Włączanie funkcji zdolnych powstrzymać wstrzymanie systemu (EPOLLWAKEUP epoll(7), /proc/sys/wake_lock).
Wykorzystywanie uprzywilejowanych operacji BPF (filtrowania pakietów Berkeley - przyp. tłum.), zob. bpf(2) i bpf-helpers(7).
Ten przywilej dodano w Linuksie 5.8, aby wydzielić funkcjonalność BPF z przeładowanego przywileju CAP_SYS_ADMIN.
Aktualizowanie /proc/sys/kernel/ns_last_pid (zob. pid_namespaces(7));
wykorzystywanie funkcji set_tid clone3(2);
odczytywanie zawartości dowiązań symbolicznych /proc/pid/map_files w przypadku innych procesów.
Ten przywilej dodano w Linuksie 5.9, aby wydzielić funkcjonalność punktów kontrolnych/przywracania z przeładowanego przywileju CAP_SYS_ADMIN.
Czynienie dowolnych zmian w stosunku do identyfikatorów użytkownika i grupy (zob. chown(2)).
Pomijanie sprawdzeń uprawnień odczytu, zapisu i wykonania. (DAC jest skrótem od ang. „discretionary access control” - tj. uznaniowa kontrola dostępu.)
Pomijanie sprawdzenia uprawnień odczytu pliku oraz sprawdzenia uprawnień odczytu i wykonania (a właściwie przeszukania - przyp. tłum.) katalogu;
wywoływanie open_by_handle_at(2);
używanie znacznika AT_EMPTY_PATH linkat(2) do utworzenia linku do pliku opisanego deskryptorem pliku.
Pomijanie sprawdzenia uprawnień w przypadku operacji wymagających zwykle, aby identyfikator użytkownika procesu pasował do identyfikatora użytkownika pliku (np. chmod(2), utime(2)), z wyłączeniem operacji objętych przywilejami CAP_DAC_OVERRIDE i CAP_DAC_READ_SEARCH;
ustawianie znaczników i-węzłów (zob. ioctl_iflags(2)) dla dowolnych plików;
ustawianie list kontroli dostępu do plików (ang. Access Control Lists - ACL) dla dowolnych plików;
ignorowanie bitu lepkości katalogu przy usuwaniu pliku;
modyfikowanie atrybutów rozszerzonych użytkownika w przypadku katalogu z bitem lepkości, będącego własnością dowolnego użytkownika;
określanie O_NOATIME do dowolnych plików w open(2) i fcntl(2).
Brak czyszczenia bitów: ustawiania ID użytkownika lub ID grupy podczas wykonania (suid/sgid), w momencie modyfikowania pliku;
ustawianie bitu ustawiania ID grupy podczas wykonania (sgid) w przypadku plików, dla których identyfikator grupy nie pasuje do systemu plików lub do jakiegokolwiek z dodatkowych identyfikatorów grupy procesu wywołującego.
Blokowanie pamięci (mlock(2), mlockall(2), mmap(2), shmctl(2));
Przydzielanie pamięci za pomocą dużych (ang. huge) stron (memfd_create(2), mmap(2), shmctl(2)).
Pomijanie sprawdzania uprawnień w przypadku operacji na obiektach IPC Systemu V
Pominięcie sprawdzenia uprawnień przy wysyłaniu sygnałów (zob. kill(2)). Obejmuje to operację KDSIGACCEPT ioctl(2).
Dokonywanie dzierżaw na dowolnych plikach (zob. fcntl(2)).
Ustawianie znaczników i-węzłów FS_APPEND_FL i FS_IMMUTABLE_FL (zob. ioctl_iflags(2)).
Zezwala na zmianę statusu lub konfiguracji MAC. Zaimplementowane do modułu Smack Linux Security Module (LSM).
Przesłanianie obowiązkowej kontroli dostępu (ang. Mandatory Access Control - MAC). Zaimplementowane do modułu Smack LSM.
Tworzenie plików specjalnych za pomocą mknod(2).
Przeprowadzanie wielu operacji związanych z siecią:
konfigurowanie interfejsu;
administrowanie zaporą sieciową IP, maskaradowaniem oraz rozliczeniami;
modyfikowanie tabel trasowania
przypisywanie do dowolnego adresu w celu uzyskania przezroczystego proxy
ustawianie typu usługi (ang. type-of-service - TOS);
czyszczenie statystyk sterownika
ustawianie trybu nasłuchiwania;
włączanie multicastingu;
używanie setsockopt(2) do ustawiania następujących opcji gniazd: SO_DEBUG, SO_MARK, SO_PRIORITY (na priorytet spoza zakresu od 0 do 6), SO_RCVBUFFORCE i SO_SNDBUFFORCE.
Kojarzenie gniazda z portami z uprzywilejowanej domeny internetowej (porty o numerach poniżej 1024).
(Nieużywane) Tworzenie gniazd rozgłoszeniowych oraz nasłuchiwanie multicastu.
Używanie gniazd RAW i PACKET
przypisywanie do dowolnego adresu w celu uzyskania przezroczystego proxy.
Używanie wielu mechanizmów monitorowania wydajności, w tym:
wywoływanie perf_event_open(2);
wykonywanie wielu operacji BPF (filtrowania pakietów Berkeley - przyp. tłum.), które wpływają na wydajność.
Ten przywilej dodano w Linuksie 5.8, aby wydzielić funkcjonalność monitorowania z przeładowanego przywileju CAP_SYS_ADMIN. Więcej szczegółów w pliku źródeł jądra Documentation/admin-guide/perf-security.rst.
Czynienie dowolnych zmian wobec identyfikatora grupy procesu oraz listy uzupełniających identyfikatorów grup;
fałszowanie identyfikatora grupy przy przekazywaniu referencji gniazd za pomocą gniazd domeny uniksowej;
zapisywanie przypisania identyfikatora grupy w przestrzeni nazw użytkownika (zob. user_namespaces(7)).
Ustawianie dowolnych przywilejów na pliku.
Od Linuksa 5.12 przywilej ten jest konieczny do przypisania identyfikatora użytkownika 0 w nowej przestrzeni nazw; więcej szczegółów w podręczniku user_namespaces(7).
Jeśli obsługiwane są przywileje pliku (tj. od Linuksa 2.6.24): dodawanie dowolnych przywilejów ze zbioru ograniczonego wywołującego wątku do jego zbioru dziedzicznego; porzucanie przywilejów ze zbioru ograniczonego (za pomocą PR_CAPBSET_DROP prctl(2)); dokonywanie zmian w znacznikach securebits.
Jeśli przywileje pliku nie są obsługiwane (tj. przed Linuksem 2.6.24): przyznawanie lub usuwanie dowolnych przywilejów w zbiorze przywilejów dozwolonych wywołującego lub z dowolnych innych procesów (ta własność CAP_SETPCAP jest niedostępna gdy jądro skonfigurowano w celu obsługi przywilejów pliku, ponieważ CAP_SETPCAP ma dla takich jąder zupełnie odmienną semantykę).
Czynienie dowolnych zmian wobec identyfikatorów użytkownika procesów (setuid(2), setreuid(2), setresuid(2), setfsuid(2));
fałszowanie identyfikatora użytkownika przy przekazywaniu referencji gniazd za pomocą gniazd domeny uniksowej;
zapisywanie przypisania identyfikatora użytkownika w przestrzeni nazw użytkownika (zob. user_namespaces(7)).
Uwaga: niniejszy przywilej jest przeładowany, zob. Uwagi do deweloperów jądra poniżej.
Wykonywanie wielu operacji z zakresu administracji systemem, w tym: quotactl(2), mount(2), umount(2), pivot_root(2), swapon(2), swapoff(2), sethostname(2) i setdomainname(2);
wykonywanie uprzywilejowanych operacji syslog(2) (od Linuksa 2.6.37 do zezwolenia na takie operacje powinno się używać CAP_SYSLOG);
wykonywanie polecenia vm86(2) VM86_REQUEST_IRQ;
dostęp do takiej samej funkcjonalności punktów kontrolnych/przywracania jak ta zarządzana przywilejem CAP_CHECKPOINT_RESTORE (jednak ten ostatni jest preferowany do uzyskiwania dostępu do tej funkcjonalności, ponieważ jest bardziej ograniczony).
przeprowadzanie takich samych operacji BPF (filtrowania pakietów Berkeley - przyp. tłum.) jak te zarządzane przywilejem CAP_BPF (jednak ten ostatni jest preferowany do uzyskiwania dostępu do tej funkcjonalności, ponieważ jest bardziej ograniczony).
korzystanie z takich samych mechanizmów monitorowania wydajności, jak te zarządzane przywilejem CAP_PERFMON (jednak ten ostatni jest preferowany do uzyskiwania dostępu do tej funkcjonalności, ponieważ jest bardziej ograniczony).
przeprowadzanie operacji IPC_SET i IPC_RMID na dowolnych obiektach IPC Systemu V;
przesłanianie limitu zasobów RLIMIT_NPROC;
przeprowadzanie operacji na atrybutach rozszerzonych: zaufanych i bezpieczeństwa (zob. xattr(7));
używanie lookup_dcookie(2);
używanie ioprio_set(2) do przypisania klas harmonogramu wejścia/wyjścia IOPRIO_CLASS_RT i (przed Linuksem 2.6.25) IOPRIO_CLASS_IDLE;
fałszowanie identyfikatora procesu przy przekazywaniu referencji gniazd za pomocą gniazd domeny uniksowej;
wykraczanie poza określony w /proc/sys/fs/file-max systemowy limit otwartych plików, w wywołaniach systemowych otwierających pliki (np. accept(2), execve(2), open(2), pipe(2));
używanie znaczników CLONE_* tworzących nowe przestrzenie nazw za pomocą clone(2) i unshare(2) (lecz, od Linuksa 3.8, tworzenie przestrzeni nazw użytkownika nie wymaga jakiegokolwiek przywileju);
dostęp do uprzywilejowanych informacji o zdarzeniach perf;
wywoływanie setns(2) (wymaga CAP_SYS_ADMIN w docelowej przestrzeni nazw);
wywoływanie fanotify_init(2);
przeprowadzanie uprzywilejowanych operacji KEYCTL_CHOWN i KEYCTL_SETPERM keyctl(2);
przeprowadzanie operacji MADV_HWPOISON madvise(2);
wykorzystywanie TIOCSTI ioctl(2) do umieszczania znaków w kolejce wejściowej terminala innego, niż terminal kontrolujący wywołującego;
wykorzystywanie przestarzałego wywołania systemowego nfsservctl(2);
wykorzystywanie przestarzałego wywołania systemowego bdflush(2);
wykonywanie różnych operacji uprzywilejowanych ioctl(2) na urządzeniu blokowym;
wykonywanie różnych operacji uprzywilejowanych ioctl(2) na systemie plików;
wykonywanie operacji uprzywilejowanych ioctl(2) na urządzeniu /dev/random (zob. random(4));
instalowanie filtru seccomp(2) bez uprzedniej konieczności ustawienia atrybutu wątku no_new_privs;
modyfikowanie reguł zezwalających/zabraniających w grupach kontroli urządzenia;
wykorzystywanie operacji PTRACE_SECCOMP_GET_FILTER ptrace(2) do zrzucania filtrów seccomp śledzącego;
wykorzystywanie operacji PTRACE_SETOPTIONS ptrace(2) do zawieszania zabezpieczeń seccomp śledzącego (np. znacznik PTRACE_O_SUSPEND_SECCOMP);
dokonywanie operacji administracyjnych na wielu sterownikach urządzeń;
modyfikacja wartości priorytetów nice autogrupy, za pomocą zapisu do /proc/pid/autogroup (zob. sched(7)).
Używanie reboot(2) i kexec_load(2).
Używanie chroot(2);
zmienianie przestrzeni nazw montowań za pomocą setns(2)
Ładowanie i usuwanie modułów jądra (zob. init_module(2) i delete_module(2));
przed Linuksem 2.6.25: porzucanie przywilejów z systemowego, ograniczonego zbioru przywilejów.
Zmniejszanie wartości nice procesu (nice(2), setpriority(2)) oraz zmienianie wartości nice dowolnych procesów;
ustawianie zasad planowania czasu rzeczywistego procesu wywołującego oraz ustawianie zasad planowania i priorytetów dowolnych procesów (sched_setscheduler(2), sched_setparam(2), sched_setattr(2));
ustawianie koligacji procesorów (ang. affinity) dla dowolnych procesów (sched_setaffinity(2));
ustawianie klasy i priorytetu planowania wejścia/wyjścia dowolnych procesów (ioprio_set(2));
stosowanie migrate_pages(2) do dowolnych procesów oraz możliwość migrowania procesów do dowolnych węzłów;
stosowanie move_pages(2) do dowolnych procesów;
używanie znaczniku MPOL_MF_MOVE_ALL z mbind(2) i move_pages(2).
Używanie acct(2).
Śledzenie dowolnych procesów za pomocą ptrace(2);
stosowanie get_robust_list(2) do dowolnych procesów;
transferowanie danych do i z pamięci, w przypadku dowolnych procesów, za pomocą process_vm_readv(2) i process_vm_writev(2);
dokonywanie inspekcji procesów za pomocą kcmp(2).
Dokonywanie operacji wejścia/wyjścia na portach (iopl(2) i ioperm(2));
uzyskiwanie dostępu do /proc/kcore;
wykonywanie operacji FIBMAP ioctl(2);
otwieranie urządzeń w celu dostępu do rejestrów charakterystycznych dla danego modelu x86 (ang. model-specific register - MSR, zob. msr(4));
aktualizowanie /proc/sys/vm/mmap_min_addr;
tworzenie przypisań pamięci do adresów poniżej wartości określonej przez /proc/sys/vm/mmap_min_addr;
przypisywanie plików w /proc/bus/pci;
otwieranie /dev/mem i /dev/kmem;
wykonywanie rożnych poleceń w stosunku do urządzeń SCSI;
wykonywanie określonych operacji na urządzeniach hpsa(4) i cciss(4);
wykonywanie wielu charakterystycznych dla urządzenia operacji na innych urządzeniach.
Używanie zarezerwowanej przestrzeni w systemach plików ext2;
tworzenie wywołań ioctl(2) kontrolujących działanie dziennika ext3;
przesłanianie limitów przydziałów dyskowych;
zwiększanie limitów zasobów (zob. setrlimit(2));
przesłanianie limitu zasobów RLIMIT_NPROC;
przesłanianie maksymalnej liczby konsol, przy przydzielaniu konsol;
przesłanianie maksymalnej liczby mapowań klawiszy;
zezwalanie na więcej niż 64hz przerwań z zegara czasu rzeczywistego;
podnoszenie limitu msg_qbytes kolejki komunikatów Systemu V ponad limit określony w /proc/sys/kernel/msgmnb (zob. msgop(2) i msgctl(2));
możliwość pominięcia limitu zasobów RLIMIT_NOFILE, dotyczącego deskryptorów plików „w locie”, przy przekazywaniu deskryptorów pliku do innego procesu za pomocą gniazd domeny uniksowej (zob. unix(7));
przesłanianie limitu /proc/sys/fs/pipe-size-max przy ustawianiu pojemności potoku za pomocą polecenia F_SETPIPE_SZ fcntl(2);
korzystanie z F_SETPIPE_SZ do zwiększania pojemności potoku ponad limit określony w /proc/sys/fs/pipe-max-size;
przesłanianie limitów /proc/sys/fs/mqueue/queues_max, /proc/sys/fs/mqueue/msg_max, i /proc/sys/fs/mqueue/msgsize_max przy tworzeniu kolejek komunikatów POSIX (zob. mq_overview(7));
korzystanie z operacji PR_SET_MM prctl(2);
ustawianie /proc/pid/oom_score_adj na wartość niższą niż ostatnio ustawioną przez proces z przywilejem CAP_SYS_RESOURCE.
Ustawianie zegara systemowego (settimeofday(2), stime(2), adjtimex(2)); ustawianie zegara czasu rzeczywistego (sprzętowego).
Używanie vhangup(2); korzystanie z wielu uprzywilejowanych operacji ioctl(2) na terminalach wirtualnych.
Wykonywanie uprzywilejowanych operacji syslog(2). Opis operacji wymagających uprzywilejowania zawiera podręcznik systemowy syslog(2).
Przeglądanie adresów ujawnionych w /proc i innych interfejsach, gdy /proc/sys/kernel/kptr_restrict ma wartość 1 (zob. opis kptr_restrict w proc(5)).
Wyzwalanie czegoś, co wybudzi system (ustawienie budzików CLOCK_REALTIME_ALARM i CLOCK_BOOTTIME_ALARM).

Przeszła i obecna implementacja

Pełna implementacja przywilejów wymaga aby:

W przypadku wszystkich operacji uprzywilejowanych jądro sprawdzało, czy wątek ma odpowiedni przywilej w swoim zbiorze efektywnym.
Jądro zapewniało wywołania systemowe pozwalające na zmianę i pobranie przywilejów wątku.
System plików obsługiwał dołączanie przywilejów do pliku wykonywalnego, aby proces mógł zyskiwać te przywileje przy wykonywaniu pliku.

Przed Linuksem 2.6.24 jedynie dwa pierwsze warunki były spełnione, Linux od wersji 2.6.24 wypełnia wszystkie trzy wymagania.

Uwagi do deweloperów jądra

Przy dodawaniu nowej funkcji, która powinna być zarządzania przywilejami, należy rozważyć poniższe punkty.

Celem przywilejów jest podzielenie uprawnień superużytkownika na fragmenty, dzięki czemu program, którego jeden lub kilka przywilejów zostało przejętych, ma mniejsze możliwości uczynienia szkód w systemie, niż ten sam program działający z uprawnieniami roota.
Deweloper ma wybór: utworzyć nowy przywilej dla swojej nowej funkcji lub przypisanie funkcji do jednego z istniejących. Aby zestaw przywilejów miał rozsądny rozmiar, zaleca się to drugie podejście, chyba że istnieją przekonujące powody do tworzenia nowego przywileju (istnieje również limit techniczny: zestaw przywilejów jest obecnie ograniczony do 64 bitów).
Aby dowiedzieć się, który przywilej będzie najlepiej pasował do opracowywanej nowej funkcji, należy sprawdzić powyższą listę przywilejów w kolejności, aby znaleźć „koszyk”, w którym nowa funkcja najlepiej się odnajdzie. Jednym ze sposobów jest sprawdzenie, czy inne funkcje wymagające jakiegoś przywileju będą zawsze używane z nową funkcją. Jeśli nowa funkcja jest bezużyteczna bez tych innych funkcji, należy użyć tego samego przywileju jak one.
Nie należy wybierać CAP_SYS_ADMIN, jeśli tylko uda się tego uniknąć! Wiele istniejących sprawdzeń przywilejów jest z nim związanych (zob. częściową listę powyżej). Można go już przekonująco nazwać „nowym rootem”, jako że, z jednej strony obejmuje cały szereg uprawnień, a z drugiej ze względu na szerokie spektrum wymagany jest również przez wiele uprzywilejowanych programów. Nie należy pogłębiać tego problemu. Jedynymi funkcjami, które należy wiązać z CAP_SYS_ADMIN są te ściśle pasujące do istniejących funkcji tego koszyka.
Jeśli okaże się, że istnieje jednak konieczność utworzenia nowego przywileju dla opracowywanej funkcji, nie należy tworzyć go lub nazywać jako przywileju „jednorazowego”. Z tego względu na przykład, dodanie bardzo specjalistycznego przywileju CAP_SYS_PACCT było najprawdopodobniej błędne. Zamiast tego należy zidentyfikować i nazwać swój nowy przywilej jako szerszy koszyk, do którego pasować mogą w przyszłości inne związane funkcje.

Zbiory przywilejów wątku

Każdy wątek ma następujący zbiór przywilejów zawierający zero lub więcej z przywilejów opisanych wyżej:

Jest to ograniczający nadzbiór przywilejów efektywnych, jakie może przyjąć wątek. Jest to również ograniczający nadzbiór przywilejów, jakie można dodać do zbioru dziedzicznego, w przypadku przywilejów które można dodać do zbioru dziedzicznego przez wątek nieposiadający przywileju CAP_SETPCAP w swoim zbiorze efektywnym.
Jeśli wątek porzuci przywilej ze swojego zbioru dozwolonego, nigdy nie może pozyskać tego przywileju ponownie (chyba że execve(2) wykona program z set-user-ID-root lub program, którego powiązane przywileje pliku dają taki przywilej).
Jest to zbiór przywilejów zachowywany na przestrzeni całego execve(2). Przywileje dziedziczne pozostają dziedziczone przy wykonywaniu dowolnego programu oraz są dodawane do zbioru dozwolonego przy wykonywaniu programu, który ma ustawione odpowiadające bity w zbiorze dziedzicznym pliku.
Ze względu na to, że przywileje dziedziczne nie są zwykle zachowywane na przestrzeni execve(2) przy działaniu jako użytkownik nieuprzywilejowany (nie root), programy które chciałyby wykonać swoje programy pomocnicze z podniesionymi przywilejami, powinny rozważyć korzystanie z przywilejów tła, opisanych poniżej.
Jest to zbiór przywilejów używany przez jądro do sprawdzenia uprawnień wątku.
Zbiór przywilejów ograniczających jest mechanizmem używanym do ograniczenia przywilejów pozyskiwanych w trakcie execve(2).
Od Linuksa 2.6.25, jest to zbiór przywilejów przypisywany do wątku. W starszych jądrach, zbiór przywilejów ograniczających był systemowy i dzielony przez wszystkie wątki systemu.
Więcej szczegółów opisano w rozdziale Zbiór przywilejów ograniczających poniżej.
Jest to zbiór przywilejów zachowywany na przestrzeni execve(2) nieuprzywilejowanego programu. Przywileje tła przestrzegają zasady, że żaden przywilej nie może zostać przywilejem tła, jeśli nie jest zarówno dozwolony jak i dziedziczny.
Zbiór przywilejów tła można modyfikować bezpośrednio za pomocą prctl(2). Przywileje tła są automatycznie zmniejszane, jeśli zmniejszony zostanie odpowiadający przywilej dozwolony lub dziedziczny.
Wykonanie programu zmieniającego identyfikator użytkownika lub grupy ze względu na bity ustawienia ID użytkownika lub grupy podczas wykonania (suid/sgid) albo programu, który ma jakiekolwiek przywileje plikowe, wyczyści zbiór przywilejów tła. Przywileje tła są dodawane do zbioru dozwolonego i przypisywane do zbioru efektywnego przy wywołaniu execve(2). Jeśli przywilej tła spowoduje zwiększenie przywilejów dozwolonych i efektywnych procesu podczas execve(2), nie wyzwoli to trybu bezpiecznego wykonania opisanego w ld.so(8).

Wątek potomny utworzony za pomocą fork(2) dziedziczy kopie zbioru przywilejów swojego rodzica. Szczegóły wpływu execve(2) na przywileje opisano w rozdziale Transformacja przywilejów podczas execve() poniżej.

Za pomocą capset(2), wątek może zmieniać swój zbiór przywilejów, zob. rozdział Programowe dostosowywanie zbioru przywilejów poniżej.

Od Linuksa 3.2, plik /proc/sys/kernel/cap_last_cap ujawnia wartość numeryczną najwyższego przywileju obsługiwanego przez działające jądro; można to wykorzystać do określenia najwyższego bitu, jaki można ustawić w zbiorze przywilejów.

Przywileje pliku

Od Linuksa 2.6.24 jądro obsługuje powiązanie zbioru przywilejów z plikiem wykonywalnym za pomocą setcap(8). Zbiory przywilejów pliku są przechowywane w atrybucie rozszerzonym (zob. setxattr(2) i xattr(7)) o nazwie security.capability. Zapis do tego atrybutu rozszerzonego wymaga przywileju CAP_SETFCAP. Zbiory przywilejów pliku, razem ze zbiorem przywilejów wątku, określają przywileje wątku po execve(2).

Istnieją trzy zbiory przywilejów pliku:

Te przywileje są automatycznie dozwolone dla wątku, niezależnie od przywilejów dziedzicznych wątku.
Na tym zbiorze wykonywana jest operacja AND ze zbiorem dziedzicznym wątku, w celu określenia które przywileje dziedziczne są włączone w zbiorze dozwolonym wątku, po execve(2).
Nie jest to zbiór, lecz pojedynczy bit. Jeśli jest ustawiony, to podczas execve(2) wszystkie nowo dozwolone przywileje wątku są również podnoszone w zbiorze efektywnym. Jeśli bit jest nieustawiony, to po execve(2), żaden z nowo dozwolonych przywilejów nie trafia do nowego zbioru efektywnego.
Włączenie efektywnego bitu przywilejów pliku wymusza sytuację, że przywilej dozwolony lub dziedziczny dowolnego pliku, który powoduje pozyskanie przez wątek odpowiadającego przywileju podczas execve(2) (zob. Transformacja przywilejów podczas execve() poniżej) pozyska również ten przywilej w swoim zbiorze efektywnym. Z tego względu przy przypisywaniu przywilejów do pliku (cap_set_file(3), cap_set_fd(3), setcap(8)), jeśli poda się znacznik przywileju efektywnego, jako mającą być włączoną dla dowolnego przywileju, to znacznik efektywny musi być również podany jako włączony dla wszystkich innych przywilejów, dla których odpowiadający znacznik dozwolony lub dziedziczny jest włączony.

Wersjonowanie atrybutu rozszerzonego przywilejów pliku

W celu zachowania przyszłej rozszerzalności, jądro obsługuje sposób kodowania numeru wersji wewnątrz atrybutu rozszerzonego security.capability, który jest używany do implementacji przywilejów pliku. Poniższe numery wersji są wewnętrzne i niewidoczne wprost dla aplikacji w przestrzeni użytkownika. Do tej pory obsługiwane są następujące wersje:

Była to oryginalna implementacja przywilejów pliku, obsługująca 32-bitowe maski przywilejów pliku.
Ta wersja pozwalała na maski przywilejów pliku o rozmiarze 64 bitów oraz była konieczna wobec przekroczenia przez przywileje liczby 32. Jądro kontynuuje obsługę plików, które mają 32-bitową maskę przywilejów w wersji 1, w sposób przezroczysty, lecz przy dodawaniu przywilejów do plików, które uprzednio ich nie posiadały oraz przy modyfikacji przywilejów istniejących plików, automatycznie użyje wersji 2 (lub wersji 3, zgodnie z opisem poniżej).
Wersja 3 przywilejów plików zapewnia przywileje przestrzeni nazw plików (opisanych niżej).
Podobnie jak w wersji 2 przywilejów pliku, maski przywilejów w wersji 3 mają rozmiar 64 bitów. Jednak oprócz tego, w atrybucie rozszerzonym security.capability zakodowano przestrzeń nazw identyfikatora użytkownika root (jest to wartość, którą użytkownik o identyfikatorze 0 wewnątrz tej przestrzeni nazw przypisuje początkowej przestrzeni nazw użytkownika).
Przywileje pliku w wersji 3 są zaprojektowane do wspólnej egzystencji z przywilejami pliku w wersji 2 tj. we współczesnym systemie Linux część plików może mieć przywileje w wersji 2, a inne w wersji 3.

Przed Linuksem 4.14, jedynym rodzajem atrybutu rozszerzonego przywileju pliku, jaki mógł być dołączony do pliku, był atrybut VFS_CAP_REVISION_2. Od jądra Linux 4.14, wersja atrybutu rozszerzonego security.capability dołączonego do pliku zależy od okoliczności, w jakich utworzono atrybut.

Od Linuksa 4.14, atrybut rozszerzony security.capability jest tworzony (lub przekształcany) automatycznie na atrybut w wersji 3 (VFS_CAP_REVISION_3) jeśli spełnione są oba poniższe warunki:

Wątek zapisujący do atrybutu rezyduje w niepierwotnej przestrzeni nazw użytkownika (ściślej mówiąc: wątek rezydujący w przestrzeni nazw użytkownika innej niż ta, z której zamontowano zasadniczy system plików.)
Wątek ma przywilej CAP_SETFCAP wobec i-węzła pliku, co oznacza, że (a) wątek ma przywilej CAP_SETFCAP wobec swojej przestrzeni nazw użytkownika oraz (b) identyfikatory użytkownika i grupy i-węzła pliku mają przypisania w przestrzeni nazw użytkownika zapisującego.

Gdy tworzony jest atrybut rozszerzony security.capability VFS_CAP_REVISION_3, identyfikator użytkownika root tworzącego wątku w przestrzeni nazw użytkownika jest zapisywany w atrybucie rozszerzonym.

Odmiennie, przy tworzeniu lub modyfikacji atrybutu rozszerzonego security.capability z uprzywilejowanego (CAP_SETFCAP) wątku rezydującego w przestrzeni nazw, w której zamontowano zasadniczy system plików (zwykle oznacza to pierwotną przestrzeń nazw użytkownika), atrybut zostanie automatycznie utworzony w wersji 2 (VFS_CAP_REVISION_2).

Proszę zauważyć, że utworzenie wersji 3 atrybutu rozszerzonego security.capability jest automatyczne. Oznacza to, że jeśli program w przestrzeni użytkownika dokonuje zapisu (setxattr(2)) atrybutu security.capability w wersji 2, jądro automatycznie utworzy atrybut w wersji 3, jeśli atrybut jest utworzony w okolicznościach opisach powyżej. Odpowiednio, gdy pobierany jest atrybut security.capability w wersji 3 (getxattr(2)) przez proces rezydujący w przestrzeni nazw użytkownika, który został utworzony przez identyfikator użytkownika roota (lub potomek tej przestrzeni nazw użytkownika), zwracany atrybut jest (automatycznie) upraszczany, aby wyglądał na atrybut w wersji 2 (tzn. wartość zwracana ma rozmiar atrybutu w wersji 2 oraz nie zawiera identyfikatora użytkownika root). To tłumaczenie w locie oznacza, że w narzędziach przestrzeni użytkownika (np. setcap(1) i getcap(1)) nie są konieczne zmiany aby używać tych narzędzi do tworzenia i pobierania atrybutów security.capability w wersji 3.

Proszę zwrócić uwagę, że plik może posiadać powiązany z nim atrybut rozszerzony security.capability w wersji 2 albo w wersji 3, ale nie obu: utworzenie albo modyfikacja atrybutu rozszerzonego security.capability automatycznie zmodyfikuje wersję, w zależności od okoliczności, w jakich utworzono lub zmodyfikowano atrybut rozszerzony.

Transformacja przywilejów podczas execve()

Podczas execve(2), jądro oblicza nowe przywileje procesu za pomocą poniższego algorytmu:


P'(tła)     = (plik jest uprzywilejowany) ? 0 : P(tła)
P'(dozwolony)   = (P(dziedziczny) & F(dziedziczny)) |

(F(dozwolony) & P(ograniczający)) | P'(tła) P'(efektywny) = F(efektywny) ? P'(dozwolony) : P'(tła) P'(dziedziczny) = P(dziedziczny) [tzn. bez zmian] P'(ograniczający) = P(ograniczający) [tzn. bez zmian]

gdzie:

oznacza wartość zbioru przywilejów wątku przed execve(2)
oznacza wartość zbioru przywilejów wątku po execve(2)
oznacza zbiór przywilejów pliku

Proszę zwrócić uwagę na detale odnoszące się do powyższych reguł transformacji przywilejów:

Zbiór przywilejów tła jest obecny jedynie od Linuksa 4.3. Przy określaniu transformacji zbioru tła podczas execve(2), plikiem uprzywilejowanym jest plik posiadający przywileje lub ustawiony bit ustawienia ID użytkownika lub grupy podczas wykonania (suid/sgid).
Przed Linuksem 2.6.25, zbiór ograniczający był atrybutem systemowym dzielonym przez wszystkie wątki. Ta wartość systemowa była używana do obliczania podczas execve(2) nowego zbioru dozwolonego w ten sam sposób jak pokazano powyżej dla P(ograniczającego).

Uwaga: podczas przekształceń przywilejów opisanych powyżej, przywileje plików mogą zostać zignorowane (potraktowane jako puste) z tych samych powodów jak ignorowane są bity ustawienia ID użytkownika lub grupy podczas wykonania (suid/sgid); zob. execve(2). Przywileje pliku są ignorowane w podobny sposób, jeśli rozruch jądra nastąpił z opcją no_file_caps.

Uwaga: zgodnie z powyższymi regułami, jeśli proces z niezerowym identyfikatorem użytkownika wykona execve(2), to wszystkie przywileje obecne w jego zbiorze dozwolonym i efektywnym zostaną wyczyszczone. Sposób traktowania przywilejów, gdy proces z identyfikatorem użytkownika równym zero wykonuje execve(2), opisano w rozdziale Przywileje i wykonanie programów przez roota poniżej.

Kontrola bezpieczeństwa plików binarnych ślepych na przywileje

Plikiem binarnym ślepym na przywileje (ang. capability-dumb) jest program oznaczony jako posiadający przywileje pliku, ale który nie został zmieniony w celu używania API libcap(3) do modyfikacji swoich przywilejów (innymi słowy jest to program korzystający z tradycyjnego bitu ustawienia ID roota podczas wykonania (suid), który został przełączony do korzystania z przywilejów pliku, ale którego kodu nie zmodyfikowano w celu rozumienia przywilejów). W przypadku takich programów bit przywilejów efektywnych jest ustawiany na pliku, dzięki czemu przywileje dozwolone pliku są automatycznie włączone w zbiorze efektywnym procesu, gdy plik jest wykonywany. Jądro rozpoznaje plik, który posiada ustawiony bit efektywnych przywilejów, jako ślepego na przywileje, do celu opisywanej tu kontroli.

Przy wykonywaniu pliku binarnego ślepego na przywileje, jądro sprawdza, czy proces pozyskał wszelkie przywileje dozwolone, które zostały podane w zbiorze dozwolonym pliku, po transformacji przywilejów opisanej wyżej (typowym powodem, dla którego może to nie nastąpić, jest zamaskowanie przez zbiór ograniczający przywilejów niektórych przywilejów ze zbioru dozwolonego pliku). Jeśli proces nie pobierze pełnego zbioru przywilejów dozwolonych, to execve(2) nie powiedzie się z błędem EPERM. Zapobiega się w ten sposób potencjalnemu zagrożeniu bezpieczeństwa, które mogłoby wystąpić, gdyby aplikacja ślepa na przywileje została wykonana z mniejszymi przywilejami niż jest to wymagane. Proszę zauważyć, że z definicji, aplikacja nie może sama rozpoznać tego problemu, ponieważ nie korzysta z API libcap(3).

Przywileje i wykonanie programów przez roota

Aby odtworzyć tradycyjną semantykę uniksową, jądro w sposób specjalny traktuje przywileje pliku, gdy program jest wykonywany przez proces z UID 0 (tj. roota) lub gdy wykonywany jest program z bitem ustawienia ID roota (suid).

Po przeprowadzeniu zmian wobec efektywnego identyfikatora procesu wyzwolonych przez bit ustawienia ID użytkownika (suid) pliku binarnego — jak np. przełączenie efektywnego identyfikatora użytkownika na 0 (tj. root), ponieważ wykonano program z ustawieniem ID użytkownika (suid) — jądro oblicza zbiór przywilejów pliku zgodnie z poniższymi zasadami:

(1)
Jeśli rzeczywistym lub efektywnym identyfikatorem użytkownika jest 0 (tj. root), to zbiory dziedziczne i dozwolone pliku są ignorowane; zamiast tego są one rozważane jako wszystkie (tzn. wszystkie przywileje włączone). Wobec tego zachowania istnieje jeden wyjątek, opisany poniżej w rozdziale Programy z ustawieniem ID użytkownika (suid), które posiadają przywileje pliku.
(2)
Jeśli proces ma identyfikator efektywny użytkownika równy 0 (tj. root) lub włączono bit efektywny pliku, to rozważany jest bit efektywny pliku (jako włączony).

Te rozważane wartości zbioru przywilejów pliku są następnie używane zgodnie z opisem powyżej, do obliczenia transformacji przywilejów procesu podczas execve(2).

Dlatego, gdy proces z niezerowym UID wykonuje execve(2) na programie z ustawieniem ID roota podczas wykonania (suid), który nie posiada dołączonych przywilejów albo gdy proces, którego rzeczywiste i efektywne identyfikatory użytkownika wynoszą 0 i wykonuje execve(2) na programie, obliczenie nowych dozwolonych przywilejów procesu upraszcza się do:


P'(dozwolony)   = P(dziedziczny) | P(ograniczający)
P'(efektywny)   = P'(dozwolony)

W efekcie, proces zyskuje wszystkie przywileje ze swojego zbioru dozwolonego i efektywnego, z wyjątkiem tych wyłączonych zbiorem przywilejów ograniczających (w obliczeniu P'(dozwolonego), wyrażenie P'(tła) można uprościć i wykreślić, ponieważ jest to z definicji prawidłowy podzbiór P(dziedzicznych)).

Specjalne traktowanie użytkownika o identyfikatorze równym 0 (tj. roota) opisane w niniejszym podrozdziale, można wyłączyć za pomocą mechanizmu securebits opisanego poniżej.

Programy z ustawieniem ID roota podczas wykonania (suid), które posiadają przywileje pliku

Istnieje jeden wyjątek wobec zachowania opisanego powyżej w rozdziale Przywileje i wykonanie programów przez roota. Jeśli (a) wykonywany plik binarny ma dołączone przywileje oraz (b) proces ma rzeczywisty identyfikator użytkownika, który nie jest równy 0 (tj. nie jest rootem) oraz (c) proces ma efektywny identyfikator użytkownika równy 0 (tj. root), to bity przywilejów pliku są honorowane (tzn. nie są rozważane jako wszystkie włączone). Standardową sytuacją, w której może to nastąpić, jest wykonywanie programu z ustawieniem ID roota podczas wykonania (suid), który ma również przywileje pliku. Gdy taki program jest wykonywany, to proces zyskuje wyłącznie przywileje nadane przez program (tzn. nie wszystkie przywileje, jak stałoby się przy wykonaniu programu z ustawieniem ID roota podczas wykonania (suid), który nie ma przypisanych żadnych przywilejów pliku).

Proszę zauważyć, że można przypisać zbiór pusty przywilejów do pliku programu, zatem możliwe jest utworzenie programu z ustawieniem ID roota podczas wykonania (suid), który zmienia efektywny i zapisany suid procesu wykonującego program na 0, ale nie przyznaje mu żadnych przywilejów.

Zbiór przywilejów ograniczających

Zbiór przywilejów ograniczających jest mechanizmem bezpieczeństwa, którego można użyć do ograniczenia przywilejów, które można zyskać podczas execve(2). Zbiór ograniczający jest używany na następujące sposoby:

Podczas execve(2), zbiór przywilejów ograniczających jest sumowany ze zbiorem przywilejów dozwolonych, a wynik tej operacji jest przypisywany do zbioru przywilejów dozwolonych wątku. Zbiór przywilejów ograniczających ogranicza zatem przywileje dozwolone, które mogą być przyznane plikowi wykonywalnemu.
(Od Linuksa 2.6.25) Zbiór przywilejów ograniczających działa jako nadzbiór ograniczający wobec przywilejów, które mogą być dodane przez wątek do swojego zbioru dziedzicznego za pomocą capset(2). Oznacza to, że jeśli przywilej nie występuje w zbiorze ograniczającym, to wątek nie może dodać go do swoich przywilejów dozwolonych, tym samym nie może zachować tego przywileju swoim zbiorze dopuszczalnym, gdy wykona execve(2) na pliku, który posiada ten przywilej w swoim zbiorze dziedzicznym.

Proszę zauważyć, że zbiór ograniczający ogranicza przywileje dozwolone, ale nie ogranicza przywilejów dziedzicznych. Jeśli wątek zachowa przywilej, niebędący w jego zbiorze ograniczającym, w swoim zbiorze dziedzicznym, to może wciąż zyskać ten przywilej w swoim zbiorze dozwolonym, wykonując plik, posiadający ten przywilej w swoim zbiorze dziedzicznym.

W zależności od wersji jądra, zbiór przywilejów ograniczających jest atrybutem albo systemowym, albo przypisanym wątkowi.

Zbiór przywilejów ograniczających od Linuksa 2.6.25

Od Linuksa 2.6.25, zbiór przywilejów ograniczających jest przypisany wątkowi (opisany niżej systemowy zbiór przywilejów ograniczających już nie istnieje).

Zbiór ograniczający jest dziedziczony w momencie wykonania fork(2) od wątku rodzicielskiego i jest zachowywany przy execve(2).

Wątek może usunąć przywileje ze swojego zbioru ograniczającego za pomocą operacji PR_CAPBSET_DROP prctl(2), zakładając że ma przywilej CAP_SETPCAP. Po usunięciu przywileju ze zbioru ograniczającego, nie da się go tam przywrócić. Wątek może sprawdzić czy przywilej znajduje się w jego zbiorze ograniczającym, za pomocą operacji PR_CAPBSET_READ prctl(2).

Usuwanie przywilejów ze zbioru ograniczającego jest obsługiwane wyłącznie, jeśli w jądro wkompilowano przywileje pliku. Przed Linuksem 2.6.33, przywileje pliku były opcjonalne i konfigurowało się je opcją CONFIG_SECURITY_FILE_CAPABILITIES. Od Linuksa 2.6.33 opcję tę usunięto, a przywileje pliku są zawsze częścią jądra. Gdy przywileje pliku wkompilowano w jądro, proces init (przodek wszystkich procesów) zaczyna działanie z pełnym zbiorem ograniczającym. Jeśli przywileje pliku nie są wkompilowane w jądro, to init rozpocznie z pełnym zbiorem ograniczającym minus CAP_SETPCAP, ponieważ przywilej ten zmienia znaczenie, gdy nie występują przywileje pliku.

Usunięcie przywileju ze zbioru ograniczającego nie usuwa go ze zbioru dziedzicznego wątku. Uniemożliwia jednak ponowne dodanie przywileju do zbioru dziedzicznego wątku w przyszłości.

Zbiór przywilejów ograniczających przed Linuksem 2.6.25

Przed Linuksem 2.6.25 zbiór przywilejów ograniczających jest atrybutem systemowym, dotyczącym wszystkich wątków w systemie. Zbiór ograniczający jest dostępny za pośrednictwem pliku /proc/sys/kernel/cap-bound (co mylące, ten parametr maski bitowej jest w /proc/sys/kernel/cap-bound prezentowany jako liczba dziesiętna ze znakiem).

Tylko proces init może ustawić przywileje w zbiorze przywilejów ograniczających, natomiast superużytkownik (precyzyjniej: proces z przywilejem CAP_SYS_MODULE) może jedynie usunąć przywileje z tego zbioru.

W standardowym systemie, maska zbioru przywilejów ograniczających zawsze prowadzi do usunięcia przywileju CAP_SETPCAP. Aby usunąć to ograniczenie (niebezpieczne!), należy zmodyfikować definicję CAP_INIT_EFF_SET w include/linux/capability.h i przebudować jądro.

Funkcję systemowego zbioru przywilejów ograniczających dodano w jądrze Linux 2.2.11.

Wpływ zmian identyfikatora użytkownika na przywileje

Aby zachować tradycyjną semantykę przejścia pomiędzy identyfikatorami użytkowników równymi i różnymi od 0, jądro dokonuje następujących zmian w zbiorach przywilejów wątku przy zmianach następujących identyfikatorów użytkownika (za pomocą setuid(2), setresuid(2) lub podobnych): rzeczywistego, efektywnego, zbioru zapisanego oraz systemu plików:

Jeśli jeden lub kilka z identyfikatorów: rzeczywistego, efektywnego lub zbioru zapisanego wynosił uprzednio 0, a wynikiem zmian identyfikatorów użytkowników jest wartość niezerowa wszystkich tych identyfikatorów, to ze zbioru przywilejów: dozwolonego, efektywnego i tła usuwane są wszystkie przywileje.
Jeśli efektywny identyfikator użytkownika zmienił się z 0 na wartość niezerową, to ze zbioru efektywnego usuwane są wszystkie przywileje.
Jeśli efektywny identyfikator użytkownika zmienił się z wartości niezerowej na 0, to zbiór dozwolony jest kopiowany do zbioru efektywnego.
Jeśli identyfikator użytkownika systemu plików zmienił się z 0 na wartość niezerową (zob. setfsuid(2)), to następujące przywileje są usuwane ze zbioru efektywnego: CAP_CHOWN, CAP_DAC_OVERRIDE, CAP_DAC_READ_SEARCH, CAP_FOWNER, CAP_FSETID, CAP_LINUX_IMMUTABLE (od Linuksa 2.6.30), CAP_MAC_OVERRIDE i CAP_MKNOD (od Linuksa 2.6.30). Jeśli UID systemu plików zmieni się z wartości niezerowej na 0, to przywileje włączone w zbiorze dozwolonym są włączane w zbiorze efektywnym.

Jeśli wątek posiadający wartość równą 0 dla jednego lub kilku swoich identyfikatorów użytkownika chce zapobiec usunięciu swojego zbioru przywilejów dozwolonych przy zresetowaniu wszystkich swoich wartości identyfikatorów użytkownika na wartości niezerowe, może to uczynić za pomocą znacznika securebits SECBIT_KEEP_CAPS opisanego niżej.

Programowe dostosowywanie zbioru przywilejów

Wątek może pobierać i zmieniać swoje zbiory przywilejów: dozwolonych, efektywnych i dziedzicznych za pomocą wywołań systemowych capget(2) i capset(2). Zaleca się jednak stosowanie do tego celu cap_get_proc(3) i cap_set_proc(3) z pakietu libcap. Zmiany zbiorów przywilejów wątku rządzą się następującymi prawami:

Jeśli wywołujący nie posiada przywileju CAP_SETPCAP, to nowy zbiór dziedziczny musi być podzbiorem kombinacji istniejących zbiorów: dziedzicznego i dozwolonego.
(Od Linuksa 2.6.25) Nowy zbiór dziedziczny musi być podzbiorem kombinacji istniejących zbiorów: dziedzicznego i ograniczającego.
Nowy zbiór dozwolony musi być podzbiorem istniejącego zbioru dozwolonego (tzn. nie da się zyskać nowych przywilejów dozwolonych, których wątek nie miał do tej pory).
Nowy zbiór efektywny musi być podzbiorem nowego zbioru dozwolonego.

Znaczniki securebits: tworzenie środowiska korzystającego wyłącznie z przywilejów

Począwszy od Linuksa 2.6.26 i jądra, w którym włączono przywileje pliku, Linux implementuje zbiór znaczników securebits przypisanych wątkowi, które mogą wyłączyć specjalne traktowanie przywilejów identyfikatora użytkownika równego 0 (tj. roota). Występują znaczniki:

Ustawienie tego znacznika pozwala wątkowi posiadającemu jeden lub więcej UID-ów równych 0 na zachowanie przywilejów w swoim zbiorze dozwolonym, po przełączeniu wszystkich swoich UID-ów na wartości niezerowe. Jeśli znacznik ten nie jest ustawiony, to takie przełączenie powoduje utratę przez wątek wszystkich przywilejów dozwolonych. Znacznik ta jest zawsze czyszczony przy wykonaniu execve(2).
Proszę zauważyć, że nawet gdy ustawiony jest znacznik SECBIT_KEEP_CAPS, to przywileje efektywne wątku są usuwane przy przełączeniu swojego efektywnego UID-u na wartość niezerową. Jednak gdy wątek ma ten znacznik ustawiony, jego efektywny UID ma już wartość niezerową, a wątek przełączy następnie wszystkie inne UID-y na wartości niezerowe, to przywileje efektywne wątku nie zostaną usunięte.
Ustawienie znacznika SECBIT_KEEP_CAPS jest ignorowane, gdy ustawiony jest znacznik SECBIT_NO_SETUID_FIXUP (ten ostatnia zapewnia nadzbiór efektów pierwszego znacznika).
Znacznik zapewnia taką samą funkcjonalność, jak starsza operacja PR_SET_KEEPCAPS prctl(2).
Ustawienie tego znacznika powstrzyma jądro przed dostosowywaniem zbiorów przywilejów procesu: dozwolonych, efektywnych i tła, w sytuacji, gdy UID-y wątku: efektywne i systemu plików, są przełączane między wartościami zera i niezerowymi. Więcej informacji w rozdziale Wpływ zmian identyfikatora użytkownika na przywileje powyżej.
Jeśli bit ten jest ustawiony, jądro nie przydziela przywilejów gdy wykonywany jest program z ustawieniem ID roota podczas wykonania (suid), albo gdy proces z efektywnym lub rzeczywistym UID-em równym 0 wywołuje execve(2). (zob. rozdział Przywileje i wykonanie programów przez roota powyżej.)
Ustawienie tego znacznika uniemożliwia podniesienie przywilejów tła za pomocą operacji PR_CAP_AMBIENT_RAISE prctl(2).

Każdy z powyższych znaczników „podstawowych” ma towarzyszący mu znacznik „blokujący”. Ustawienie znacznika „blokującego” jest nieodwracalne i zapobiega dalszym zmianom odpowiadającemu mu znacznikowi „podstawowemu”. Istnieją następujące znaczniki blokujące: SECBIT_KEEP_CAPS_LOCKED, SECBIT_NO_SETUID_FIXUP_LOCKED, SECBIT_NOROOT_LOCKED i SECBIT_NO_CAP_AMBIENT_RAISE_LOCKED.

Znaczniki securebits można zmodyfikować i pobrać za pomocą operacji PR_SET_SECUREBITS i PR_GET_SECUREBITS prctl(2). Do modyfikowania znaczników potrzebny jest przywilej CAP_SETPCAP. Proszę zauważyć, że stałe SECBIT_* są dostępne tylko wówczas, gdy są umieszczone w pliku nagłówkowym <linux/securebits.h>.

Znaczniki securebits są dziedziczone przez procesy potomne. Podczas execve(2) zachowywane są wszystkie znaczniki poza SECBIT_KEEP_CAPS, który jest zawsze usuwany.

Aplikacja może użyć następującego wywołania do zablokowania siebie i wszystkich swoich potomków w środowisku, w którym jedyną metodą zyskania przywilejów, jest wykonanie programu z powiązanymi przywilejami plików:


prctl(PR_SET_SECUREBITS,

/* SECBIT_KEEP_CAPS wyłączone */
SECBIT_KEEP_CAPS_LOCKED |
SECBIT_NO_SETUID_FIXUP |
SECBIT_NO_SETUID_FIXUP_LOCKED |
SECBIT_NOROOT |
SECBIT_NOROOT_LOCKED);
/* Ustawienie/zablokowanie SECBIT_NO_CAP_AMBIENT_RAISE
nie jest wymagane */

Programy z ustawieniem ID roota podczas wykonania („set-user-ID-root”) na przestrzeń użytkownika

Programy z ustawieniem ID roota podczas wykonania (suid), których identyfikatory użytkownika pasują do identyfikatorów użytkownika, który utworzył przestrzeń nazw użytkownika, będą miały przyznane przywileje w zbiorach procesu: dozwolonym i efektywnym, przy wykonywaniu przez dowolny proces z tej przestrzeni nazw i z każdej potomnej przestrzeni nazw.

Reguły regulujące transformację przywilejów procesu podczas execve(2) są identyczne z opisanymi w Transformacja przywilejów podczas execve() oraz Przywileje i wykonanie programów przez roota powyżej, z jedyną różnicą, że w drugim z podrozdziałów „root” jest identyfikatorem użytkownika tworzącego przestrzeń nazw użytkownika.

Przywileje pliku w przestrzeni nazw

Tradycyjne (tzn. w wersji 2) przywileje pliku wiążą jedynie zbiór masek przywilejów z binarnym plikiem wykonywalnym. Gdy proces wykonuje plik binarny z takimi przywilejami, zyskuje powiązane przywileje (w swojej przestrzeni nazw) według reguł opisanych w rozdziale Transformacja przywilejów podczas execve() powyżej.

Ponieważ przywileje pliku w wersji 2 przyznają przywileje procesowi wykonującemu bez względu na przestrzeń nazw, w której on rezyduje, jedynie procesy uprzywilejowane mogą przypisywać przywileje do pliku. Tu „uprzywilejowany” oznacza proces, który ma przywilej CAP_SETFCAP w przestrzeni nazw użytkownika, w której zamontowano system plików (zwykle pierwotna przestrzeń nazw użytkownika). To ograniczenie czyni przywileje pliku bezużytecznymi w niektórych zastosowaniach. Przykładowo, w kontenerach przestrzeni nazw użytkownika przydatna może się okazać możliwość utworzenia pliku binarnego, który przyznaje przywileje jedynie procesowi wykonywanemu wewnątrz takiego kontenera, ale nie procesom wykonywanym na zewnątrz kontenera.

Linux 4.14 dodał tak zwane przywileje pliku w przestrzeni nazw, w celu obsługi takich przypadków. Są one zapisywane jako atrybuty rozszerzone security.capability wersji 3. (tzn. VFS_CAP_REVISION_3). Takie atrybuty są tworzone automatycznie w okolicznościach opisanych w rozdziale Wersjonowanie atrybutu rozszerzonego przywilejów pliku powyżej. Przy tworzeniu atrybutu rozszerzonego security.capability w wersji 3., w atrybucie rozszerzonym jądro zapisze nie tylko maskę przywileju, lecz także identyfikator użytkownika root w przestrzeni nazw.

Podobnie jak z plikiem binarnym z przywilejami pliku VFS_CAP_REVISION_2, plik binarny z przywilejami pliku VFS_CAP_REVISION_3 przyznaje przywileje procesowi podczas execve(). Jednakże przywileje są przyznawane tylko gdy plik binarny jest wykonywany przez proces rezydujący w przestrzeni nazw użytkownika, którego identyfikator użytkownika 0 jest przypisany do identyfikatora użytkownika root zachowywanego w atrybucie rozszerzonym lub gdy jest wykonywany przez proces rezydujący w potomkach takiej przestrzeni nazw.

Interakcja z przestrzeniami nazw użytkowników

Więcej informacji o interakcji przywilejów i przestrzeni nazw użytkownika znajduje się w podręczniku user_namespaces(7).

STANDARDY

Nie istnieją standardy opisujące przywileje, lecz linuksowa implementacja przywilejów powstała w oparciu o wycofany szkic standardu POSIX.1e.

UWAGI

Przy próbie wykonania strace(1) na plikach binarnych posiadających przywileje (lub plikach binarnych z ustawieniem ID roota podczas wykonania (suid)) przydatna może okazać się opcja -u <nazwa-użytkownika>. Przykład:


$ sudo strace -o trace.log -u użytkownik ./mójprywatnyprogram

W jądrze Linux w wersjach od 2.5.27 do 2.6.26, przywileje były opcjonalną częścią jądra i mogły był włączane i wyłączane opcją konfiguracji jądra CONFIG_SECURITY_CAPABILITIES.

Aby zobaczyć zbiory przywilejów wątku można użyć pliku /proc/pid/task/TID/status. Plik /proc/pid/status pokazuje zbiory przywilejów głównego wątku procesu. Przed Linuksem 3.8 w tych zbiorach pokazywane były jako włączone (1) przywileje nieistniejące. Od Linuksa 3.8, wszystkie nieistniejące przywileje (powyżej CAP_LAST_CAP) są pokazywane jako wyłączone (0).

Pakiet libcap udostępnia zestaw procedur do ustawiania i pobierania przywilejów, który jest bardziej komfortowy i mniej narażony na zmiany niż interfejs udostępniamy przez capset(2) i capget(2). Pakiet ten zawiera również programy setcap(8) i getcap(8). Można go znaleźć na stronie
https://git.kernel.org/pub/scm/libs/libcap/libcap.git/refs/.

Przed Linuksem 2.6.24, oraz w Linuksie 2.6.24 do 2.6.32 - jeśli nie włączono przywilejów, wątek z przywilejem CAP_SETPCAP może zmieniać przywileje innego wątku. Jest to jednak wyłącznie możliwość teoretyczna, ponieważ wątek nigdy nie posiada CAP_SETPCAP w żadnym z dwóch poniższych przypadków:

W implementacji przed wersją 2.6.25 zbiór przywilejów ograniczających na poziomie systemu, /proc/sys/kernel/cap-bound, zawsze maskował przywilej CAP_SETPCAP usuwając go i nie da się zmienić tego zachowania bez modyfikacji źródeł jądra i przebudowania jądra.
Jeśli przywileje pliku są wyłączone (tzn. opcja jądra CONFIG_SECURITY_FILE_CAPABILITIES jest wyłączona), to init uruchomi się z przywilejem CAP_SETPCAP usuniętym ze swojego zbioru ograniczającego przypisanego do procesu, a ten zbiór ograniczający jest następnie dziedziczony przez wszystkie procesy utworzone w systemie.

ZOBACZ TAKŻE

capsh(1), setpriv(1), prctl(2), setfsuid(2), cap_clear(3), cap_copy_ext(3), cap_from_text(3), cap_get_file(3), cap_get_proc(3), cap_init(3), capgetp(3), capsetp(3), libcap(3), proc(5), credentials(7), pthreads(7), user_namespaces(7), captest(8), filecap(8), getcap(8), getpcaps(8), netcap(8), pscap(8), setcap(8)

include/linux/capability.h w drzewie źródeł jądra Linux

TŁUMACZENIE

Autorami polskiego tłumaczenia niniejszej strony podręcznika są: Michał Kułach <michal.kulach@gmail.com>

Niniejsze tłumaczenie jest wolną dokumentacją. Bliższe informacje o warunkach licencji można uzyskać zapoznając się z GNU General Public License w wersji 3 lub nowszej. Nie przyjmuje się ŻADNEJ ODPOWIEDZIALNOŚCI.

Błędy w tłumaczeniu strony podręcznika prosimy zgłaszać na adres listy dyskusyjnej manpages-pl-list@lists.sourceforge.net.

2 maja 2024 r. Linux man-pages (niewydane)