PB173 Linux 05 Procesy Roman Lacko xlacko1@fi.muni.cz 2022-10-14 1 Systémové volania Systémové volania Kernel supervisor user init mdadm xterm i3 ls 2 Systémové volania • Služba jadra • Nutné prepnutie do privilegovaného režimu • Prerušenie, call gate, špeciálne inštrukcie, … • man 2 intro • man 2 syscalls 3 Systémové volania: Manuál Rozdiely v manuálových stránkach: man 2 open Dokumentácia systémového volania1 . man 3 open Dokumentácia funkcie v knižnici (libc). man 3p open Dokumentácia funkcie podľa POSIXu. 1 Presnejšie, obaľujúcej funkcie v štandardnej knižnici 4 Systémové volania: Chyby Návratové kódy systémových volaní: • ≥ 0: Úspech, prípadne nejaká hodnota • < 0: Chyba vrátane kódu Chybový kód Obaľujúce funkcie chybový návratový kód zmenia na -1 a kód chyby uložia do errno. 5 Systémové volania: Hlásenie chýb Chyby systémových volaní sú očakávateľné chyby. Viď patterns/01-defensive-offensive-programming. #include extern int errno; errno Pri vláknach si ukážeme, že errno je v skutočnosti trochu zložitejší objekt. #include char *strerror(int number); 6 errno • (Niektoré) funkcie nastavujú errno pri chybe. • Žiadne funkcie errno pri úspechu nenastavujú. Kontrolujte najprv návratový kód funkcie! • Ak funkcia zlyhala, (väčšinou) nastaví errno. • Ak je errno nastavené, funkcia ešte nemusela zlyhať. Nulovanie errno Chybu niektorých funkcií (napr. strtol()) je občas možné zistiť len z errno. Pred nimi je preto vhodnejšie errno vynulovať. 7 Systémové volania: Hlásenie chýb #include void perror(const char *s); perror(s) je zhruba ekvivalentné fprintf(stderr, "%s: %s\n", s, strerror(errno)); #include void err(int eval, const char *fmt, ...); void errx(int eval, const char *fmt, ...); void warn(const char *fmt, ...); void warnx(const char *fmt, ...); 8 Systémové volania: Hlásenie chýb (GNU) #define _GNU_SOURCE #include extern char *program_invocation_name; extern char *program_invocation_name_short; #define _GNU_SOURCE #include int error(int status, int errnum, const char *format, ...); 9 Procesy Procesy Program • abstraktný alebo konkrétny popis nejakej úlohy • obvykle uložený v súbore Proces • inštancia programu • vlastné prostriedky (pamäť, registre, …) • usporiadané v stromovej štruktúre 10 Procesy: PID Process Identifier • jednoznačná identifikácia procesu v systéme • procfs (/proc/$pid), ps • koreň má PID 1 #include pid_t getpid(void); pid_t getppid(void); 11 Procesy: Životný cyklus new ready running í sleeping stopped zombie swap-Sswap-R fork() 12 Procesy: Subproces #include int system(const char *command); • Spustenie programu ako sh -c "COMMAND" • Problémy s prenositeľnosťou • Problémy s bezpečnosťou Ak nemusíte, radšej nepoužívajte. 13 Procesy: Vznik #include pid_t fork(void); [PID 15] if ((child_pid = fork()) == 0) child(); else parent(child_pid); [PID 15] if ((child_pid = fork()) == 0) child(); else parent(child_pid); [PID 27] if ((child_pid = fork()) == 0) child(); else parent(child_pid); 14 Procesy: Nahradenie #include int execv (const char *path, char *const argv[]); int execve (const char *path, char *const argv[], char *const env[]); int execvp (const char *file, char *const argv[]); int execvpe(const char *file, char *const argv[], char *const env[]); int execl (const char *path, const char *arg, ..., /* NULL */); int execlp (const char *file, const char *arg, ..., /* NULL */); int execle (const char *path, const char *arg, ..., /* NULL */, char *const env[]); Z týchto volaní je len execve() skutočné systémové volanie. 15 Procesy: Nahradenie exec[vl](pe)(): v Parametry sú v poli argv[], posledný prvok NULL. l Parametry sú v elipse, posledný prvok NULL. p Namiesto celej cesty berie názov programu a hľadá ho v PATH. e Prostredie ako samostatný parameter. 16 Procesy: Nahradenie (Linux) #define int execveat(int dirfd, const char *path, char *const argv[], char *const env[], int flags); #define AT_FDCWD /* implementation-specific (probably -100) */ int fexecve(int fd, char *const argv[], char *const envp[]); 17 Procesy: Čakanie #include pid_t wait(int *wstatus); pid_t waitpid(pid_t pid, int *wstatus, int options); pid_t waitid(idtype_t idtype, id_t id, siginfo_t *sig, int options); #define WNOHANG /* ... */ #define WIFEXITED(STATUS) /* ... */ #define WEXITSTATUS(STATUS) /* ... */ #define WIFSIGNALED(STATUS) /* ... */ #define WTERMSIG(STATUS) /* ... */ 18 Procesy: Čakanie (BSD) #define _DEFAULT_SOURCE #include pid_t wait3(int *wstatus, int options, struct rusage *rusage); pid_t wait4(pid_t pid, /* wstatus, options, rusage */); 19 Procesy: Ukončenie #include void exit(int status); #include int atexit(void (*f)(void)); #define _DEFAULT_SOURCE #include int on_exit(void (*f)(int, void *), void *arg); 20 Procesy: Ukončenie Pozor, nepoužívajte _exit() ani _Exit() (ak nemusíte)! #include void _exit(int status); #include void _Exit(int status); 21 Vlastnosti Vlastnosti: Poverenia Poverenia (credentials) Vlastnosti, ktoré jadro používa na kontrolu práv procesu. • PID, PPID • PGID, SID • používateľké ID (RUID, EUID, Saved-UID) • skupinové ID (RGID, EGID, Saved-GID, Supplementary GID) • schopnosti (capabilities) Rôzne systémy môžu mať iné ďalšie poverenia. man 7 credentials 22 Vlastnosti: Identifikácie EUID, EGID (Effective …) • Zdedené pri fork(), môže sa zmeniť pri execve(): • EUID na UID programu, ak má nastavený Set-UID bit • EGID na GID programu, ak má nastavený Set-GID bit • ďalšie obmedzenia viď man 2 execve • Používajú sa na vyhodnocovanie práv • Bežný proces môže meniť na Real alebo Saved 23 Vlastnosti: Identifikácie RUID, RGID (Real User ID, Real Group ID) • Zdedené pri fork() • ID, ktoré identifikuje vlastníka procesu Saved-UID, Saved-GID • Kópia EUID resp. EGID pri execve() Supplementary GID • Zoznam ďalších skupín procesu • Prístup k súborom a zdrojom 24 Vlastnosti: Proces vs. používateľ Pozor na rozdiel Práva procesu a práva používateľov sú všeobecne nezávislé! Práva používateľa sa berú do úvahy (väčšinou) len pri • prihlásení do systému, • spustení su USER a sudo -u USER. 25 Vlastnosti: Proces vs. program Program na disku (ako súbor) má UID a GID. Na práva spusteného procesu majú efekt: • pri kontrole prístupu k súboru (napr. pri execve()), • ak majú Set-UID alebo Set-GID bit. Neexistujúce ID UID a GID programu na disku nemusí odkazovať na skutočného používateľa či skupinu v systéme. Prečo? 26 Proces: User ID #include uid_t getuid(void); int setuid(uid_t uid); uid_t geteuid(void); int seteuid(uid_t euid); int setreuid(uid_t uid, uid_t euid); Rozšírenie (GNU) #define _GNU_SOURCE #include int getresuid(uid_t *uid, uid_t *euid, uid_t *suid); int setresuid(uid_t uid, uid_t euid, uid_t suid); 27 Proces: Group ID #include gid_t getgid(void); int setgid(gid_t gid); gid_t getegid(void); int setegid(gid_t egid); int setregid(gid_t gid, gid_t egid); Rozšírenie (GNU) #define _GNU_SOURCE #include int getresgid(gid_t *gid, gid_t *egid, gid_t *sgid); int setresgid(gid_t gid, gid_t egid, gid_t sgid); 28 Proces: Zmeny v ID Proces, ktorý má EUID rovné 0 alebo CAP_SETUID schopnosť, môže robiť ľubovoľné zmeny vo svojich User ID2 . Ostatné procesy môžu nastaviť svoje EUID na RUID alebo Saved-UID. • Proces sa môže „ponížiť” nastavením všetkých svojich ID na nenulové číslo a zrušením schopností. • Bežný proces sa nikdy nemôže „povýšiť“. 2 Pre Group ID analogicky 29 Proces: Zmeny v ID setreuid() root setuid() seteuid() RUID EUID SUID user setreuid() setreuid() setuid(), seteuid() setuid(), seteuid() Analogicky pre Group ID. 30 Proces: Doplnkové skupiny #include int getgroups(int size, gid_t list[]); #include int setgroups(size_t size, const git_t list[]); Zmeny v pomocných skupinách môže robiť len proces s EGID rovné 0 alebo so schopnosťou CAP_SETGID. 31 Používatelia a skupiny Používatelia v systéme obvykle majú • Login • UID a GID (primárna skupina) • Môžu mať doplnkové skupiny • Domovský adresár Užitočné programy: • id • getent passwd, getent group • newgrp 32 Používatelia a skupiny Databáza používateľov a skupín /etc/passwd Zoznam používateľov /etc/shadow Heslá používateľov (hashe) /etc/group Zoznam skupín /etc/gshadow Heslá skupín (hashe) Vzdialená databáza Záznamy o používateľoch môžu pochádzať aj z iného systému napr. LDAP, SSSD, NSS, … 33 Používatelia a skupiny #include struct passwd { char *pw_name; char pw_uid, pw_gid; char *pw_dir; ... }; struct passwd *getpwnam(const char *name); struct passwd *getpwuid(uid_t uid); /* getpwnam_r(), getpwuid_r() */ struct passwd *getpwent(void); void setpwent(void); void endpwent(void); 34 Používatelia a skupiny #include struct group { char *gr_name; char gr_gid; char **gr_mem; ... }; struct group *getgrnam(const char *name); struct group *getgrgid(gid_t gid); /* getgrnam_r(), getgrgid_r() */ struct passwd *getgrent(void); void setgrent(void); void endgrent(void); 35 Používatelia a skupiny Suplementárne skupiny (BSD) #define _DEFAULT_SOURCE #include int getgrouplist(const char *user, gid_t group, gid_t *groups, int *ngroups); 36 Záver Záver Procesy • The Linux Process Model Poverenia • Set-UID Demystified • Revising “Set-UID Demystified” 37