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.
Poniżej przedstawiono listę ukazującą
przywileje zaimplementowane w Linuksie oraz operacje lub zachowania, na
które pozwala każdy z przywilejów:
- CAP_AUDIT_CONTROL
(od Linuksa 2.6.11)
- Włączanie i wyłączanie audytu jądra;
zmiana reguł filtrowania audytu; pobieranie statusu audytu i
reguł filtrowania.
- CAP_AUDIT_READ
(od Linuksa 3.16)
- Zezwala na odczyt dziennika audytu za pomocą gniazda multicastowego
netlink.
- CAP_AUDIT_WRITE
(od Linuksa 2.6.11)
- Zapisywanie rekordu do dziennika audytu jądra
- CAP_BLOCK_SUSPEND
(od Linuksa 3.5)
- Włączanie funkcji zdolnych powstrzymać wstrzymanie
systemu (EPOLLWAKEUP epoll(7),
/proc/sys/wake_lock).
- CAP_BPF (od
Linuksa 5.8)
- 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.
- CAP_CHECKPOINT_RESTORE
(od Linuksa 5.9)
- •
- 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.
- CAP_CHOWN
- Czynienie dowolnych zmian w stosunku do identyfikatorów
użytkownika i grupy (zob. chown(2)).
- CAP_DAC_OVERRIDE
- Pomijanie sprawdzeń uprawnień odczytu, zapisu i wykonania.
(DAC jest skrótem od ang. „discretionary access
control” - tj. uznaniowa kontrola dostępu.)
- CAP_DAC_READ_SEARCH
- •
- 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.
- CAP_FOWNER
- •
- 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.
FS_IOC_SETFLAGS(2const)) 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).
- CAP_FSETID
- •
- 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.
- CAP_IPC_LOCK
- CAP_IPC_OWNER
- Pomijanie sprawdzania uprawnień w przypadku operacji na obiektach
IPC Systemu V
- CAP_KILL
- Pominięcie sprawdzenia uprawnień przy wysyłaniu
sygnałów (zob. kill(2)). Obejmuje to operację
KDSIGACCEPT ioctl(2).
- CAP_LEASE (od
Linuksa 2.4)
- Dokonywanie dzierżaw na dowolnych plikach (zob.
fcntl(2)).
- CAP_LINUX_IMMUTABLE
- Ustawianie znaczników i-węzłów
FS_APPEND_FL i FS_IMMUTABLE_FL (zob.
FS_IOC_SETFLAGS(2const)).
- CAP_MAC_ADMIN
(od Linuksa 2.6.25)
- Zezwala na zmianę statusu lub konfiguracji MAC. Zaimplementowane do
modułu Smack Linux Security Module (LSM).
- CAP_MAC_OVERRIDE
(od Linuksa 2.6.25)
- Przesłanianie obowiązkowej kontroli dostępu (ang.
Mandatory Access Control - MAC). Zaimplementowane do modułu Smack
LSM.
- CAP_MKNOD (od
Linuksa 2.4)
- Tworzenie plików specjalnych za pomocą mknod(2).
- CAP_NET_ADMIN
- 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.
- CAP_NET_BIND_SERVICE
- Kojarzenie gniazda z portami z uprzywilejowanej domeny internetowej (porty
o numerach poniżej 1024).
- CAP_NET_BROADCAST
- (Nieużywane) Tworzenie gniazd rozgłoszeniowych oraz
nasłuchiwanie multicastu.
- CAP_NET_RAW
- •
- Używanie gniazd RAW i PACKET
- •
- przypisywanie do dowolnego adresu w celu uzyskania przezroczystego
proxy.
- CAP_PERFMON
(od Linuksa 5.8)
- 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.
- CAP_SETGID
- •
- 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)).
- CAP_SETFCAP
(od Linuksa 2.6.24)
- 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).
- CAP_SETPCAP
- 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ę).
- CAP_SETUID
- •
- 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)).
- CAP_SYS_ADMIN
- 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)).
- CAP_SYS_BOOT
- Używanie reboot(2) i kexec_load(2).
- CAP_SYS_CHROOT
- CAP_SYS_MODULE
- •
- Ł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.
- CAP_SYS_NICE
- CAP_SYS_PACCT
- Używanie acct(2).
- CAP_SYS_PTRACE
- CAP_SYS_RAWIO
- •
- 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.
- CAP_SYS_RESOURCE
- •
- 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.
- CAP_SYS_TIME
- Ustawianie zegara systemowego (settimeofday(2), stime(2),
adjtimex(2)); ustawianie zegara czasu rzeczywistego
(sprzętowego).
- CAP_SYS_TTY_CONFIG
- Używanie vhangup(2); korzystanie z wielu uprzywilejowanych
operacji ioctl(2) na terminalach wirtualnych.
- CAP_SYSLOG
(od Linuksa 2.6.37)
- •
- 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)).
- CAP_WAKE_ALARM
(od Linuksa 3.0)
- Wyzwalanie czegoś, co wybudzi system (ustawienie budzików
CLOCK_REALTIME_ALARM i CLOCK_BOOTTIME_ALARM).
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.
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.
Każdy wątek ma następujący
zbiór przywilejów zawierający zero lub więcej z
przywilejów opisanych wyżej:
- Dozwolony
(ang. permitted)
- 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).
- Dziedziczny
(ang. inheritable)
- 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.
- Efektywny
(ang. effective)
- Jest to zbiór przywilejów używany przez jądro
do sprawdzenia uprawnień wątku.
- Ograniczający
(ang. bounding; na wątek od Linuksa 2.6.25)
- 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.
- Tła (ang. ambient; od
Linuksa 4.3)
- 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.
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:
- Dozwolone
(ang. permitted; wcześniej znane jako wymuszone - ang.
forced):
- Te przywileje są automatycznie dozwolone dla wątku,
niezależnie od przywilejów dziedzicznych wątku.
- Dziedziczne
(ang. inheritable; wcześniej znane jako dozwolone - ang.
allowed):
- 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).
- Efektywne
(ang. effective)
- 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.
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:
- VFS_CAP_REVISION_1
- Była to oryginalna implementacja przywilejów pliku,
obsługująca 32-bitowe maski przywilejów pliku.
- VFS_CAP_REVISION_2
(od Linuksa 2.6.25)
- 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).
- VFS_CAP_REVISION_3
(od Linuksa 4.14)
- 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.
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:
- P()
- oznacza wartość zbioru przywilejów wątku przed
execve(2)
- P'()
- oznacza wartość zbioru przywilejów wątku po
execve(2)
- F()
- 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.
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).
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.
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 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.
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.
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.
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:
- SECBIT_KEEP_CAPS
- 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).
- SECBIT_NO_SETUID_FIXUP
- 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.
- SECBIT_NOROOT
- 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.)
- SECBIT_NO_CAP_AMBIENT_RAISE
- 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 (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.
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.
Więcej informacji o interakcji przywilejów i
przestrzeni nazw użytkownika znajduje się w podręczniku
user_namespaces(7).