# SO Lista 6 ## Zadanie 1 G ![](https://i.imgur.com/ZAJJVwN.png) ![](https://i.imgur.com/TYbhBsH.png) ![](https://i.imgur.com/3Q8P0Ts.png) Początkowy stan: ``` ruid = 1000 euid = 0 suid = 0 ``` a) setuid(2000) ![](https://i.imgur.com/xXhn4lN.png) ``` ruid = 2000 euid = 2000 suid = 2000 ``` b) setreuid(-1, 2000) ![](https://i.imgur.com/XrAy7jS.png) ``` ruid = 1000 euid = 2000 suid = 2000 ``` c) seteuid(2000) ![](https://i.imgur.com/FKHPhDd.png) ``` ruid = 1000 euid = 2000 suid = 0 ``` d) setresuid(-1, 2000, 3000) ![](https://i.imgur.com/1dzFZXv.png) ``` ruid = 1000 euid = 2000 suid = 3000 ``` Proces ``` ruid = 0 euid = 1000 suid = 1000 ``` nie jest uprzywilejowany, gdyż liczy się tylko effective uid, ale można to zmienić przy pomocy syscall'i. ## Zadanie 2 G ![](https://i.imgur.com/R1MIU5J.png) ![](https://i.imgur.com/fABtreU.png) ![](https://i.imgur.com/dOL67xy.png) > The setgid affects both files as well as directories. When used on a file, it executes with the privileges of the group of the user who owns it instead of executing with those of the group of the user who executed it. > When the bit is set for a directory, the set of files in that directory will have the same group as the group of the parent directory, and not that of the user who created those files. This is used for file sharing since they can be now modified by all the users who are part of the group of the parent directory. > ![](https://i.imgur.com/aA29RQt.png) ![](https://i.imgur.com/qsHXT2D.png) ``` my_access(struct stat *sb, int mode){ uid_t my_uid = getuid(); gid_t my_gid = getgroups(); int file_mask = sb->st_mode; if (sb->st_uid == my_uid){ mode <<= 6; file_mask &= S_IRWXU; } else if (sb->st_gid == my_gid) { mode <<= 3; file_mask &= S_IRWXG; } else file_mask &= S_IRWXO; return ((mode & file_mask)^mode) == 0; } ``` ```c // R - To co chcemy mieć uprawnienie, RF - To co plik ma ustawione dla nas // R = 0, RF = 0 => True // R = 0, RF = 1 => True // R = 1, RF = 0 => False // R = 1, RF = 1 => True // R => RF // !R or RF bool my_access(struct stat *sb, int mode){ uid = getuid() groups = getgroups() R = R_OK & mode W = W_OK & mode X = X_OK & mode fmode = sb.st_mode if uid is 0 return true if uid is sb.st_uid: return (!R or (S_IRUSR & fmode)) and (!W or (S_IWUSR & fmode)) and (!X or (S_IXUSR & fmode)) else if sb.st_gid is in groups: return (!R or (S_IRGRP & fmode)) and (!W or (S_IWGRP & fmode)) and (!X or (S_IXGRP & fmode)) else return (!R or (S_IROTH & fmode)) and (!W or (S_IROTH & fmode)) and (!X or (S_IROTH & fmode)) } ``` ## Zadanie 3 ![](https://i.imgur.com/vRQ9uCC.png) jaką tozsamosc bedzie miał proces ? ruid=bez zmian, euid=0,suid=0 bo binarki z setuid bitem zmieniają effective id, a saved id jest kopiowane z effective id po zmianie potem cos w kodzie pogrzebac ## Zadanie 4 G ![](https://i.imgur.com/TR9sWVy.png) ### Dlaczego programy uprzewilejowane należy projektować w taki sposób by operowały z najmniejszym możliwym zestawem upoważnień? Żeby zminimalizować ryzyko przejęcia ważnych zasobów systemowych i zabezpieczyć się przed ewentualnymi bugami w programach ### Wytyczne 1. Program funckcjonuje w trybie uprzywilejowanym kiedy faktycznie tego potrzebuje 2. Wraca do bycia nieuprzywilejowanym od razu gdy już nie potrzebuje 3. Zrzucamy uprawniena jeśli jest uruchamiany inny program 4. Zamykamy wszystkie file descriptory przed exec ### Czemu standardowy zestaw funkcji systemu uniksowego do implementacji programów uprzywilejowanych jest niewystarczający? Zawsze gdy chcemy coś zrobić z systemem to używamy roota np. do zmiany czasu. Możemy po prostu rozdzielić moc roota na 'podmoc' czyli `capabilities` ### Zdolności 1. `CAP_DAC_READ_SEARCH` -> pozwala na trawersowanie każdego katalogu i czytanie każdego pliku (read na plikach i r,x na dirach) 2. `CAP_KILL` -> nie patrzy na uprawnienia do wysyłania sygnałó do procesów ### Kiedy proces użytkownika może wysłać sygnał do innego procesu? Trzeba mieć `CAP_KILL` albo ruid/euid procesu źródłowego musi być takie same jak ruid/suid procesu docelowego ![](https://i.imgur.com/JoGdJm1.png) ![](https://i.imgur.com/g8ZY9d7.jpg) ![](https://i.imgur.com/5Yc2dyH.png) ## Zadanie 5 G ![](https://i.imgur.com/CK2bm8G.png) ![](https://i.imgur.com/MoS6Lzn.png) ### Jakie zadania pełni procedura exit(3)? 1. Flushuje wszystkie strumienie otwarte w programie i zamyka 2. Zamyka wszytskie tmp files(3) ### Problemy z buforowaniem w przypadku: #### fork(2) Bufor może zostać odziedziczony przez dziecko #### execve(2) Zastępuje cały address space i w efekcie tracimy cały buffer #### _exit(2) Buffer może zostać stracony i nie wysłany do jądra #### Jak zapobiec? Flush przed wywołaniem funkcji ### Jaka jesto domyślna strategia? 1. plik terminala -> line buffered 2. plik zwykły -> fully buffered 3. stderr -> unbuffered ### Jak flushować streamy w handlerach? ![](https://i.imgur.com/Xpm0xm5.png) To flush z flagą `TCIOFLUSH` , nic innego Paweł nie znalazł ![](https://i.imgur.com/5HDdKht.png) ![](https://i.imgur.com/aKMiI6S.png) ## Zadanie 6 G ![](https://i.imgur.com/lbQnqQc.png) ```c buf = malloc(size); setvbuf(stdout,buf,mode,size); if (strcmp(choice, "writev") == 0) { int n = sysconf(_SC_IOV_MAX); struct iovec iov[n]; /* TODO: Write file by filling in iov array and issuing writev. */ int iovcnt = 0; for (int j = 0; j < times; j++){ for (int k = 0; k < length; k++){ iov[iovcnt + k].iov_base = line + k; iov[iovcnt + k].iov_len = length + 1 - k; } iovcnt += length; if (iovcnt + length >= n){ writev(STDOUT_FILENO,iov,iovcnt); iovcnt = 0; } } } ``` ![](https://i.imgur.com/MdfmBC0.png) statystyki z wywołanych funkcji ```c #!/bin/sh strace -o write.stat -c ./writeperf -t 1000 -l 1000 write > /dev/null strace -o fwrite.stat -c ./writeperf -t 1000 -l 1000 fwrite > /dev/null strace -o fwrite-line.stat -c ./writeperf -t 1000 -l 1000 fwrite-line > /dev/null strace -o fwrite-full.stat -c ./writeperf -t 1000 -l 1000 fwrite-full > /dev/null strace -o writev.stat -c ./writeperf -t 1000 -l 1000 writev > /dev/null ``` ## Zadanie 7 ![](https://i.imgur.com/gwpdOcZ.png) ![](https://i.imgur.com/joW2CUB.png) ![](https://i.imgur.com/O2HYYIR.png) ![](https://i.imgur.com/g1xFL3r.png) ```c static const char *uidname(uid_t uid) { /* TODO: Something is missing here! */ struct passwd *pw; pw = getpwuid(uid); return pw->pw_name; } static const char *gidname(gid_t gid) { /* TODO: Something is missing here! */ struct group *grp; grp = getgrgid(gid); return grp->gr_name; } static int getid(uid_t *uid_p, gid_t *gid_p, gid_t **gids_p) { gid_t *gids = NULL; int ngid = 2; int groups; /* TODO: Something is missing here! */ *uid_p = getuid(); *gid_p = getgid(); // groups = getgroups(0,NULL); // gids = (gid_t *)malloc(sizeof(gid_t)*groups); // getgroups(groups,gids); gids = (gid_t *)malloc(sizeof(gid_t)*ngid); while((groups = getgroups(ngid,gids)) < 0){ ngid++; gids = (gid_t *)realloc(gids, sizeof(gid_t)*ngid); } *gids_p = gids; return groups; } ```