# Lista 4 ###### tags: `SO2022` ![](https://i.imgur.com/XGwcJLH.png) :::spoiler ![](https://i.imgur.com/db7ZqNd.png) ::: ## Deklaracja :::spoiler | Zadanie | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |-----------|---|---|---|---|---|---|---|---| |Deklaracja |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:| ::: ## Zadanie 1 ![](https://i.imgur.com/smff57z.png) ```c= // terminal.h #ifndef _TERMINAL_H_ #define _TERMINAL_H_ int tty_open(void); void tty_curpos(int fd, int *x, int *y); /* https://en.wikipedia.org/wiki/ANSI_escape_code#CSI_(Control_Sequence_Introducer)_sequences */ #define ESC "\033" #define CSI ESC "[" #define CUU(n) CSI #n "A" /* Cursor Up */ #define CUD(n) CSI #n "B" /* Cursor Down */ #define CUF(n) CSI #n "C" /* Cursor Forward */ #define CUB(n) CSI #n "D" /* Cursor Back */ #define CNL(n) CSI #n "E" /* Cursor Next Line */ #define CPL(n) CSI #n "F" /* Cursor Previous Line */ #define CHA(n) CSI #n "G" /* Cursor Horizontal Absolute */ #define CUP(n, m) CSI #n ";" #m "H" /* Cursor Position */ #define ED(n) CSI #n "J" /* Erase in Display */ #define EL(n) CSI #n "K" /* Erase in Line */ #define SU(n) CSI #n "S" /* Scroll Up Scroll */ #define SD(n) CSI #n "T" /* Scroll Down Scroll */ #define CPR() CSI "6n" /* Cursor Position Report */ #define SGR(x) CSI x "m" #endif /* !_ANSICODES_H_ */ ``` * ### Zreferuj działanie procedury `tty_curpos` odczytującej pozycję kursora terminala. ```c= // terminal.c #include <termios.h> #include <sys/ioctl.h> #include "csapp.h" #include "terminal.h" int tty_open(void) { const char *dev = ttyname(STDIN_FILENO); if (!dev) { errno = ENOTTY; unix_error("tty_open error"); } return Open(dev, O_RDWR | O_NOCTTY, 0); } void tty_curpos(int fd, int *x, int *y) { struct termios ts, ots; tcgetattr(fd, &ts); // pobieramy bierzący stan sterownika terminala memcpy(&ots, &ts, sizeof(struct termios)); // robimy backup ts.c_lflag &= ~(ECHO | ICANON); // wyłączomy ECHO i tryb kanoniczny ts.c_cflag &= ~CREAD; // wyłączmy odbieranie znaków tcsetattr(fd, TCSADRAIN, &ts); // ustawiamy atrybuty /* How many characters in the input queue. */ int m = 0; /* TODO: Need to figure out some other way to do it on MacOS / FreeBSD. */ #ifdef LINUX ioctl(fd, TIOCINQ, &m); // Gpobieramy liczbę bajtów w input buffer. #endif /* Read them all. */ //ten komentarz mówi wszystko char discarded[m]; m = Read(fd, discarded, m); Write(fd, CPR(), sizeof(CPR())); // wywołujemy kod CSI 6n char buf[20]; int n = Read(fd, buf, 19); //odczytujemy pozycję kursora buf[n] = '\0'; ts.c_lflag |= ICANON; //przywracamy tryb kanoniczny tcsetattr(fd, TCSADRAIN, &ts); //przywracamy tryb kanoniczny for (int i = 0; i < m; i++) ioctl(fd, TIOCSTI, discarded + i); //przywracamy bufor tcsetattr(fd, TCSADRAIN, &ots); //przywracamy ustawienia terminala sscanf(buf, "\033[%d;%dR", x, y); //zczytujemy pozycję kursora } ``` * ### Do czego służy kod sterujący `CPR`? jest to kod `CSI 6n` zwraca pozycję kursora w formacie `\033[n;mR` (n - wiersz, m - kolumna) * ### Wytłumacz semantykę rozkazów wykorzystywanych odpowiednio przez `tcgetattr(3)` i `tcsetattr(3)`: * `tcgetattr(3)`: pobiera aktualne ustawienia terminala * 'ioctl(fd, TCGETS, struct termios *argp)' * `tcsetattr(3)`: ustawia nowe ustawienia terminala * 'ioctl(fd, TCSETSW, struct termios *argp)' * `TIOCINQ`: zwraca informację ile jest bajtów w input buffer * `TIOCSTI`: kopiuje dany bajt do input buffer * ### Wyjaśnij jak na działanie sterownika terminala wpływają flagi: * `ECHO`: włącza echo * `ICANON`: tryb kanoniczny * `CREAD`: odbieranie znaków ## Zadanie 2 ![](https://i.imgur.com/QKueXxx.png) * ### Wyjaśnij działanie programu `script(1)`. ![](https://i.imgur.com/BKxj2W2.png) ![](https://i.imgur.com/v915ie7.png) * #### Nagraj interaktywną sesję z powłoką `dash` przy pomocy polecenia `script -T timing -c dash`. ``` terminal1: script -T timing -c dash echo test > test.txt exit ``` * #### Wykonaj kilka poleceń i zakończ powłokę przy pomocy polecenia `exit 42`, po czym odtwórz sesję przy pomocy polecenia `scriptreplay -t timing`. ``` terminal1: scriptreplay timing ``` * #### Następnie uruchom polecenie powyższe polecenie przy pomocy `strace -f -e read,write -o script.log` i na podstawie zawartości pliku `script.log`pokaż jak `script` używa pseudoterminala do komunikacji z programami działającymi pod kontrolą powłoki `dash` ``` terminal1: strace -f -e read,write -o script.log script -T timing -c dash echo test exit ``` * #### Pokaż, że sterownik terminala przepisuje znaki zgodnie z flagami `ICRNL` i `ONLCR` opisanymi w `termios(4)`. * `ICRNL`: przerabia `\r` na `\n` * `ONLCR`: przerabia `\n` na` \r\n` ## Zadanie 3 ![](https://i.imgur.com/gAXTncj.png) * #### Uruchom potok (ang. pipeline) `ps -ef | grep sh | wc -l > cnt` w powłoce utworzonej przy pomocy polecenia `strace -o pipeline.log -f dash`. ``` terminal1: strace -o pipeline.log -f dash ps -ef | grep sh | wc -l > cnt exit ``` :::spoiler **pipeline.log** ```= 89226 read(0, "ps -ef | grep sh | wc -l > cnt\n", 8192) = 31 89226 newfstatat(AT_FDCWD, "/home/bartosz/.local/bin/ps", 0x7ffd91d9e510, 0) = -1 ENOENT (Nie ma takiego pliku ani katalogu) 89226 newfstatat(AT_FDCWD, "/home/bartosz/bin/ps", 0x7ffd91d9e510, 0) = -1 ENOENT (Nie ma takiego pliku ani katalogu) 89226 newfstatat(AT_FDCWD, "/home/bartosz/.cargo/bin/ps", 0x7ffd91d9e510, 0) = -1 ENOENT (Nie ma takiego pliku ani katalogu) 89226 newfstatat(AT_FDCWD, "/usr/local/bin/ps", 0x7ffd91d9e510, 0) = -1 ENOENT (Nie ma takiego pliku ani katalogu) 89226 newfstatat(AT_FDCWD, "/usr/local/sbin/ps", 0x7ffd91d9e510, 0) = -1 ENOENT (Nie ma takiego pliku ani katalogu) 89226 newfstatat(AT_FDCWD, "/usr/bin/ps", {st_mode=S_IFREG|0755, st_size=141080, ...}, 0) = 0 89226 pipe2([3, 4], 0) = 0 89226 clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f275197aa10) = 89228 89226 setpgid(89228, 89228) = 0 89226 close(4 <unfinished ...> 89228 set_robust_list(0x7f275197aa20, 24 <unfinished ...> 89226 <... close resumed>) = 0 89226 newfstatat(AT_FDCWD, "/home/bartosz/.local/bin/grep", <unfinished ...> 89228 <... set_robust_list resumed>) = 0 89226 <... newfstatat resumed>0x7ffd91d9e510, 0) = -1 ENOENT (Nie ma takiego pliku ani katalogu) 89226 newfstatat(AT_FDCWD, "/home/bartosz/bin/grep", 0x7ffd91d9e510, 0) = -1 ENOENT (Nie ma takiego pliku ani katalogu) 89228 getpid( <unfinished ...> 89226 newfstatat(AT_FDCWD, "/home/bartosz/.cargo/bin/grep", <unfinished ...> 89228 <... getpid resumed>) = 89228 89226 <... newfstatat resumed>0x7ffd91d9e510, 0) = -1 ENOENT (Nie ma takiego pliku ani katalogu) 89228 setpgid(0, 89228 <unfinished ...> 89226 newfstatat(AT_FDCWD, "/usr/local/bin/grep", <unfinished ...> 89228 <... setpgid resumed>) = 0 89226 <... newfstatat resumed>0x7ffd91d9e510, 0) = -1 ENOENT (Nie ma takiego pliku ani katalogu) 89228 ioctl(10, TIOCSPGRP, [89228] <unfinished ...> 89226 newfstatat(AT_FDCWD, "/usr/local/sbin/grep", <unfinished ...> 89228 <... ioctl resumed>) = 0 89226 <... newfstatat resumed>0x7ffd91d9e510, 0) = -1 ENOENT (Nie ma takiego pliku ani katalogu) 89228 rt_sigaction(SIGTSTP, {sa_handler=SIG_DFL, sa_mask=~[RTMIN RT_1], sa_flags=SA_RESTORER, sa_restorer=0x7f27519b9b50}, <unfinished ...> 89226 newfstatat(AT_FDCWD, "/usr/bin/grep", <unfinished ...> 89228 <... rt_sigaction resumed>NULL, 8) = 0 89226 <... newfstatat resumed>{st_mode=S_IFREG|0755, st_size=162488, ...}, 0) = 0 89228 rt_sigaction(SIGTTOU, {sa_handler=SIG_DFL, sa_mask=~[RTMIN RT_1], sa_flags=SA_RESTORER, sa_restorer=0x7f27519b9b50}, <unfinished ...> 89226 pipe2( <unfinished ...> 89228 <... rt_sigaction resumed>NULL, 8) = 0 89226 <... pipe2 resumed>[4, 5], 0) = 0 89228 rt_sigaction(SIGINT, {sa_handler=SIG_DFL, sa_mask=~[RTMIN RT_1], sa_flags=SA_RESTORER, sa_restorer=0x7f27519b9b50}, <unfinished ...> 89226 clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD <unfinished ...> 89228 <... rt_sigaction resumed>NULL, 8) = 0 89228 rt_sigaction(SIGQUIT, {sa_handler=SIG_DFL, sa_mask=~[RTMIN RT_1], sa_flags=SA_RESTORER, sa_restorer=0x7f27519b9b50}, NULL, 8) = 0 89228 rt_sigaction(SIGTERM, {sa_handler=SIG_DFL, sa_mask=~[RTMIN RT_1], sa_flags=SA_RESTORER, sa_restorer=0x7f27519b9b50}, NULL, 8) = 0 89226 <... clone resumed>, child_tidptr=0x7f275197aa10) = 89229 89228 close(3 <unfinished ...> 89226 setpgid(89229, 89228 <unfinished ...> 89229 set_robust_list(0x7f275197aa20, 24 <unfinished ...> 89228 <... close resumed>) = 0 89226 <... setpgid resumed>) = 0 89228 dup2(4, 1) = 1 89229 <... set_robust_list resumed>) = 0 89226 close(3 <unfinished ...> 89228 close(4 <unfinished ...> 89226 <... close resumed>) = 0 89228 <... close resumed>) = 0 89226 close(5) = 0 89229 setpgid(0, 89228 <unfinished ...> 89228 execve("/usr/bin/ps", ["ps", "-ef"], 0x5565dcf6d088 /* 54 vars */ <unfinished ...> 89226 newfstatat(AT_FDCWD, "/home/bartosz/.local/bin/wc", <unfinished ...> 89229 <... setpgid resumed>) = 0 89226 <... newfstatat resumed>0x7ffd91d9e510, 0) = -1 ENOENT (Nie ma takiego pliku ani katalogu) 89229 ioctl(10, TIOCSPGRP, [89228] <unfinished ...> 89226 newfstatat(AT_FDCWD, "/home/bartosz/bin/wc", <unfinished ...> 89229 <... ioctl resumed>) = 0 89226 <... newfstatat resumed>0x7ffd91d9e510, 0) = -1 ENOENT (Nie ma takiego pliku ani katalogu) 89226 newfstatat(AT_FDCWD, "/home/bartosz/.cargo/bin/wc", <unfinished ...> 89229 rt_sigaction(SIGTSTP, {sa_handler=SIG_DFL, sa_mask=~[RTMIN RT_1], sa_flags=SA_RESTORER, sa_restorer=0x7f27519b9b50}, <unfinished ...> 89226 <... newfstatat resumed>0x7ffd91d9e510, 0) = -1 ENOENT (Nie ma takiego pliku ani katalogu) 89229 <... rt_sigaction resumed>NULL, 8) = 0 89226 newfstatat(AT_FDCWD, "/usr/local/bin/wc", <unfinished ...> 89229 rt_sigaction(SIGTTOU, {sa_handler=SIG_DFL, sa_mask=~[RTMIN RT_1], sa_flags=SA_RESTORER, sa_restorer=0x7f27519b9b50}, <unfinished ...> 89226 <... newfstatat resumed>0x7ffd91d9e510, 0) = -1 ENOENT (Nie ma takiego pliku ani katalogu) 89229 <... rt_sigaction resumed>NULL, 8) = 0 89226 newfstatat(AT_FDCWD, "/usr/local/sbin/wc", <unfinished ...> 89229 rt_sigaction(SIGINT, {sa_handler=SIG_DFL, sa_mask=~[RTMIN RT_1], sa_flags=SA_RESTORER, sa_restorer=0x7f27519b9b50}, <unfinished ...> 89226 <... newfstatat resumed>0x7ffd91d9e510, 0) = -1 ENOENT (Nie ma takiego pliku ani katalogu) 89229 <... rt_sigaction resumed>NULL, 8) = 0 89226 newfstatat(AT_FDCWD, "/usr/bin/wc", <unfinished ...> 89228 <... execve resumed>) = 0 89226 <... newfstatat resumed>{st_mode=S_IFREG|0755, st_size=45864, ...}, 0) = 0 89229 rt_sigaction(SIGQUIT, {sa_handler=SIG_DFL, sa_mask=~[RTMIN RT_1], sa_flags=SA_RESTORER, sa_restorer=0x7f27519b9b50}, <unfinished ...> 89226 clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD <unfinished ...> 89229 <... rt_sigaction resumed>NULL, 8) = 0 89228 brk(NULL <unfinished ...> 89229 rt_sigaction(SIGTERM, {sa_handler=SIG_DFL, sa_mask=~[RTMIN RT_1], sa_flags=SA_RESTORER, sa_restorer=0x7f27519b9b50}, <unfinished ...> 89228 <... brk resumed>) = 0x55f7cede6000 89229 <... rt_sigaction resumed>NULL, 8) = 0 89226 <... clone resumed>, child_tidptr=0x7f275197aa10) = 89230 89229 close(4 <unfinished ...> 89226 setpgid(89230, 89228 <unfinished ...> 89230 set_robust_list(0x7f275197aa20, 24 <unfinished ...> 89229 <... close resumed>) = 0 89226 <... setpgid resumed>) = 0 89230 <... set_robust_list resumed>) = 0 89229 dup2(3, 0 <unfinished ...> 89226 close(4 <unfinished ...> 89229 <... dup2 resumed>) = 0 89226 <... close resumed>) = 0 89230 setpgid(0, 89228 <unfinished ...> 89228 arch_prctl(0x3001 /* ARCH_??? */, 0x7ffdf69b8370 <unfinished ...> 89229 close(3 <unfinished ...> 89226 close(-1 <unfinished ...> 89230 <... setpgid resumed>) = 0 89228 <... arch_prctl resumed>) = -1 EINVAL (Zły argument) 89229 <... close resumed>) = 0 89226 <... close resumed>) = -1 EBADF (Błędny deskryptor pliku) 89230 ioctl(10, TIOCSPGRP, [89228] <unfinished ...> 89226 wait4(-1, <unfinished ...> 89229 dup2(5, 1 <unfinished ...> 89228 mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0 <unfinished ...> 89230 <... ioctl resumed>) = 0 89229 <... dup2 resumed>) = 1 89228 <... mmap resumed>) = 0x7f33b4085000 89230 rt_sigaction(SIGTSTP, {sa_handler=SIG_DFL, sa_mask=~[RTMIN RT_1], sa_flags=SA_RESTORER, sa_restorer=0x7f27519b9b50}, <unfinished ...> 89229 close(5 <unfinished ...> 89230 <... rt_sigaction resumed>NULL, 8) = 0 89228 access("/etc/ld.so.preload", R_OK <unfinished ...> 89230 rt_sigaction(SIGTTOU, {sa_handler=SIG_DFL, sa_mask=~[RTMIN RT_1], sa_flags=SA_RESTORER, sa_restorer=0x7f27519b9b50}, <unfinished ...> 89229 <... close resumed>) = 0 89230 <... rt_sigaction resumed>NULL, 8) = 0 89228 <... access resumed>) = -1 ENOENT (Nie ma takiego pliku ani katalogu) 89230 rt_sigaction(SIGINT, {sa_handler=SIG_DFL, sa_mask=~[RTMIN RT_1], sa_flags=SA_RESTORER, sa_restorer=0x7f27519b9b50}, <unfinished ...> 89229 execve("/usr/bin/grep", ["grep", "sh"], 0x5565dcf6d0b8 /* 54 vars */ <unfinished ...> 89228 openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC <unfinished ...> 89230 <... rt_sigaction resumed>NULL, 8) = 0 89230 rt_sigaction(SIGQUIT, {sa_handler=SIG_DFL, sa_mask=~[RTMIN RT_1], sa_flags=SA_RESTORER, sa_restorer=0x7f27519b9b50}, <unfinished ...> 89228 <... openat resumed>) = 3 89230 <... rt_sigaction resumed>NULL, 8) = 0 89228 newfstatat(3, "", <unfinished ...> 89230 rt_sigaction(SIGTERM, {sa_handler=SIG_DFL, sa_mask=~[RTMIN RT_1], sa_flags=SA_RESTORER, sa_restorer=0x7f27519b9b50}, <unfinished ...> 89228 <... newfstatat resumed>{st_mode=S_IFREG|0644, st_size=85203, ...}, AT_EMPTY_PATH) = 0 89230 <... rt_sigaction resumed>NULL, 8) = 0 89228 mmap(NULL, 85203, PROT_READ, MAP_PRIVATE, 3, 0 <unfinished ...> 89230 dup2(4, 0 <unfinished ...> 89228 <... mmap resumed>) = 0x7f33b4070000 89230 <... dup2 resumed>) = 0 89228 close(3 <unfinished ...> 89230 close(4 <unfinished ...> 89228 <... close resumed>) = 0 89230 <... close resumed>) = 0 89229 <... execve resumed>) = 0 89228 openat(AT_FDCWD, "/lib64/libprocps.so.8", O_RDONLY|O_CLOEXEC <unfinished ...> 89230 openat(AT_FDCWD, "cnt", O_WRONLY|O_CREAT|O_TRUNC, 0666 <unfinished ...> 89229 brk(NULL) = 0x55c27c78e000 89228 <... openat resumed>) = 3 89230 <... openat resumed>) = 3 89229 arch_prctl(0x3001 /* ARCH_??? */, 0x7ffd9d112280 <unfinished ...> 89228 read(3, <unfinished ...> 89230 fcntl(1, F_DUPFD, 10 <unfinished ...> 89229 <... arch_prctl resumed>) = -1 EINVAL (Zły argument) 89230 <... fcntl resumed>) = 11 89228 <... read resumed>"\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\0\0\0\0\0\0\0"..., 832) = 832 89230 close(1 <unfinished ...> 89229 mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0 <unfinished ...> 89228 newfstatat(3, "", <unfinished ...> 89230 <... close resumed>) = 0 89229 <... mmap resumed>) = 0x7f2885e9b000 89230 fcntl(11, F_SETFD, FD_CLOEXEC <unfinished ...> 89228 <... newfstatat resumed>{st_mode=S_IFREG|0755, st_size=86744, ...}, AT_EMPTY_PATH) = 0 89230 <... fcntl resumed>) = 0 89229 access("/etc/ld.so.preload", R_OK <unfinished ...> 89230 dup2(3, 1 <unfinished ...> 89228 mmap(NULL, 229416, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0 <unfinished ...> 89230 <... dup2 resumed>) = 1 89229 <... access resumed>) = -1 ENOENT (Nie ma takiego pliku ani katalogu) 89230 close(3 <unfinished ...> 89228 <... mmap resumed>) = 0x7f33b4037000 89230 <... close resumed>) = 0 89229 openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC <unfinished ...> 89228 mmap(0x7f33b403c000, 40960, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x5000 <unfinished ...> 89230 execve("/usr/bin/wc", ["wc", "-l"], 0x5565dcf6d108 /* 54 vars */ <unfinished ...> 89229 <... openat resumed>) = 3 89228 <... mmap resumed>) = 0x7f33b403c000 89229 newfstatat(3, "", <unfinished ...> 89228 mmap(0x7f33b4046000, 16384, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0xf000 <unfinished ...> 89229 <... newfstatat resumed>{st_mode=S_IFREG|0644, st_size=85203, ...}, AT_EMPTY_PATH) = 0 89228 <... mmap resumed>) = 0x7f33b4046000 89229 mmap(NULL, 85203, PROT_READ, MAP_PRIVATE, 3, 0 <unfinished ...> 89228 mmap(0x7f33b404a000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x12000 <unfinished ...> 89229 <... mmap resumed>) = 0x7f2885e86000 89228 <... mmap resumed>) = 0x7f33b404a000 89229 close(3) = 0 89228 mmap(0x7f33b404d000, 139304, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0 <unfinished ...> 89229 openat(AT_FDCWD, "/lib64/libpcre.so.1", O_RDONLY|O_CLOEXEC <unfinished ...> 89228 <... mmap resumed>) = 0x7f33b404d000 89229 <... openat resumed>) = 3 89230 <... execve resumed>) = 0 ``` ::: * #### Na podstawie zawartości pliku `pipeline.log` opisz jak powłoka realizuje funkcje łączenia procesów rurami (ang. pipe) i wykonuje przekierowanie standardowego wyjścia do pliku. Wskaż które procesy i w jakiej kolejności będą wołały następujące wywołania systemowe. Powłoka w przypadku `dash` działa następująco: ```= Wywołujemy polecenie 89226 read(0, "ps -ef | grep sh | wc -l > cnt\n", 8192) = 31 Tworzymy pierwszy pipe z najmniejszymi wolnymi deskryptorami 89226 pipe2([3, 4], 0) = 0 Tworzymy pierwszy program w potoku `prog-ps` 89226 clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f275197aa10) = 89228 Powłoka ustawia pgid dla `prog-ps` 89226 setpgid(89228, 89228) = 0 Powłoka zamyka niepotrzebny jej deskryptor wejścia do pipe'a 89226 close(4) = 0 `prog-ps` ustala sam swój pgid 89228 getpid() = 89228 89228 setpgid(0, 89228) = 0 Ustalenie grupy pierwszoplanowej 89228 ioctl(10, TIOCSPGRP, [89228]) = 0 Tworzymy drugiego pipe'a 89226 pipe2([4, 5], 0) = 0 Tworzymy drugi program w potoku `prog-grep` 89226 clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f275197aa10) = 89229 `prog-ps` zamyka niepotrzebny deskryptor wyjścia z rury 89228 close(3) = 0 Powłoka ustawia pgid dla `prog-grep` 89226 setpgid(89229, 89228) = 0 `prog-ps` mapuje deskryptor pipe'a na standardowe wyjscie następnie zamyka niepotrzebny deskryptor 89228 dup2(4, 1) = 1 89228 close(4) = 0 Powłoka zamyka niepotrzebne deskryptory wyjścia z pierwszego pipe'a oraz wejscia do drugiego pipe'a przekazał je już do `prog-grep` 89226 close(3) = 0 89226 close(5) = 0 `prog-grep` ustala swój pgid 89229 setpgid(0, 89228) = 0 Ustalenie grupy pierwszoplanowej 89229 ioctl(10, TIOCSPGRP, [89228]) = 0 `prog-ps` staje się prawdzwym `ps` 89228 execve("/usr/bin/ps", ["ps", "-ef"], 0x5565dcf6d088 /* 54 vars */) = 0 Tworzymy trzeci program w potoku `prog-wc` 89226 clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f275197aa10) = 89230 `prog-grep` zamyka niepotrzebny deskryptor wyjścia drugiego z pipe'a 89229 close(4) = 0 Powłoka ustawia pgid dla `prog-wc` 89226 setpgid(89230, 89228) = 0 `prog-grep` mapuje deskryptor pierwszego pipe'a na standardowe wejscie następnie zamyka niepotrzebny deskryptor 89228 dup2(3, 0) = 0 89228 close(3) = 0 Powłoka zamyka niepotrzebne deskryptory pipe'a, utworzyła już dzieci więc nie są one potrzebne 89226 close(4) = 0 `prog-wc` ustala swój pgid 89230 setpgid(0, 89228) = 0 Ustalenie grupy pierwszoplanowej 89230 ioctl(10, TIOCSPGRP, [89228]) = 0 `prog-grep` mapuje deskryptor drugiego pipe'a na standardowe wyjscie następnie zamyka niepotrzebny deskryptor 89228 dup2(5, 1) = 1 89228 close(5) = 0 `prog-grep` staje się prawdziwym `grep` 89229 execve("/usr/bin/grep", ["grep", "sh"], 0x5565dcf6d0b8 /* 54 vars */) = 0 `prog-wc` mapuje deskryptor pipe'a na standardowe wejscie następnie zamyka niepotrzebny deskryptor 89230 dup2(4, 0) = 0 89230 close(4) = 0 `prog-wc` otwiera plik cnt 89230 openat(AT_FDCWD, "cnt", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3 `prog-wc` otweira plik do którego ustwiliśmy przekierowanie mapuje deskryptor na standarwowe wyjście i zamyka niepotrzebny już deskryptor 89230 close(1) = 0 89230 dup2(3, 1) = 1 89230 close(3) = 0 `prog-wc` staje się prawdziwym `wc` 89230 execve("/usr/bin/wc", ["wc", "-l"], 0x5565dcf6d108 /* 54 vars */) = 0 ``` ## Zadanie 4 ![](https://i.imgur.com/vuzOwCZ.png) * ### Wskaż kiedy powłoka tworzy nową grupę procesów i jak umieszcza tam procesy realizujące potok. Na grupę procesów wybierany jest pid pierwszego procesu w pipe'e * ### Wyjaśnij czemu dla każdego podprocesu wywołanie `setpgid(2)` jest robione zarówno w procesie powłoki jak i w procesie potomnym? * Zabezpieczamy się przed sytuacją gdy w dziecku zrobimy `execve` a rodzic jeszcze nie ustali grupy * Zabezpieczamy się przed systuacją gdy rodzic wyśle sygał a dziecko jeszcze nie ustali grupy * ### Kiedy powłoka ustala grupę pierwszoplanową przy pomocy `ioctl(2)` (realizuje `tcsetpgrp(3)`)? Dzieje się to na początku życia programu, zaraz po wykonaniu przypisania pgida ![](https://i.imgur.com/TPubLay.png) ![](https://i.imgur.com/stQcn5x.png) * ### Na jakiej podstawie powłoka wyznacza kod wyjścia potoku? Kod wyjścia brany jest z ostatniego programu pipe'a ## Zadanie 5 ![](https://i.imgur.com/JaZDo0R.png) * ### Czemu nie można czytać i modyfikować katalogów przy pomocy wywołań `read(2)` i `write(2)`? ![](https://i.imgur.com/WQWQiqw.png) Nie checmy dawać programiscie dostępu do wewnętrznej implementacji katalogu, która róźnić się będzie w zależności od użytego systemu plików. * ### Jakim wywołaniem systemowym można wczytać rekord katalogu (ang. directory entry)? `getdents(2)`, `getdents64(2)` - wczytaj zawartości katalogu żeby wczytać dany rekord katalogu, na wyniku `getdents` można użyć `readdir(3)` - read a directory (`readdir(2)` nie jest na x86-64) * ### Dlaczego zawartość katalogu nie jest posortowana? ![](https://i.imgur.com/5MlJEZ9.png) * btrfs Zawartość katalogu sortowana jest względem czasu utworzenia wpisu w katalogu. * ext4 Zawartość katalogu jest posortowana względem offsetu * ### Wyświetl metadane katalogu głównego `/` przy pomocy polecenia `stat`. `stat /` * ### Wyjaśnij z czego wynika podana liczba dowiązań (ang. hard link). * btrfs w tym przypadku liczba dowiązań to liczba miejsc które wskazują na ten konkretny inode, z uwagi na budowę systemu w katalogu nie ma potrzebny przechowywać inode na samego siebie oraz na rodzica btrfs jest zbudowany na b-drzewach * ext4 obserwujemy dużą liczbę dowiązań ponieważ każdy podkatalog przechowóje swoje dowiązanie na rodzica ## Zadanie 6 ![](https://i.imgur.com/utDFX8a.png) ![](https://i.imgur.com/sXuw3ST.png) ```c= #include "csapp.h" bool f_lock(const char *path) { if (access(path, F_OK) == 0) return false; (void)Open(path, O_CREAT|O_WRONLY, 0700); return true; } void f_unlock(const char *path) { Unlink(path); } ``` * `O_CREAT|O_EXCL` jeśli plik istnieje dostaniemy error * ### Opowiedz jakie zagrożenia niesie ze sobą taki błąd. For example, sendmail may check for a specific attribute of a mailbox (e.g., it is not a symbolic link) in step one and then append new messages (as root) in step two. Because the two steps are not executed atomically, a local attacker (mailbox owner) can exploit the window of vulnerability between the two steps by deleting his/hermailbox and replacing it with a symbolic link to /etc/passwd. If the replacement is completed within the window and the new messages happen to be syntactically correct /etc/passwd entries with root access, then sendmail may unintentionally give unauthorized root access to a normal user (the attacker) * ### Poprawny kod: ```c= #include "csapp.h" bool f_lock(const char *path) { (void)Open(path, O_CREAT|O_EXCL|O_WRONLY, 0700); return true; } void f_unlock(const char *path) { Unlink(path); } ``` ## Zadanie 7 ![](https://i.imgur.com/XldYB7V.png) ```c= //leaky.c #include "csapp.h" int main(int argc, char **argv) { long max_fd = sysconf(_SC_OPEN_MAX); /* Initialize PRNG seed. */ struct timeval tv; gettimeofday(&tv, NULL); srandom(tv.tv_usec); /* This opens a file with password that is checked later. */ int fd_1 = Open("mypasswd", O_RDONLY, 0); int fd_2 = 3 + random() % (max_fd - 3); (void)Dup2(fd_1, fd_2); Close(fd_1); Lseek(fd_2, 0, SEEK_END); /* TODO: Something is missing here to fix the issue! */ // F_SETFD - ustawia flagi na te przekzane w następnym argumencie // FD_CLOEXEC - zamyka deskrtyptor przy execve fcntl(fd_2, F_SETFD, FD_CLOEXEC); /* TODO: End */ /* Let's suppose a user typed in correct password and was allowed to execute * a command and they choose to run our program. */ int rc = system("./innocent"); if (rc < 0) unix_error("System error"); /* At this point we may finally close the file. */ Close(fd_2); return rc; } ``` ```c= //innocent.c #include "csapp.h" #include <dirent.h> #include <unistd.h> #define BUFF_SIZE 4096 int main(void) { long max_fd = sysconf(_SC_OPEN_MAX); int out = Open("/tmp/hacker", O_CREAT | O_APPEND | O_WRONLY, 0666); /* TODO: Something is missing here! */ char buff[BUFF_SIZE]; char path[BUFF_SIZE]; int read_len; for (int i = 4; i < max_fd; i++) { snprintf(path, BUFF_SIZE, "/proc/self/fd/%d", i); read_len = readlinkat(i, path, buff, BUFF_SIZE); if(read_len > 0) { dprintf(out, "File descriptor %d is '%s' file!\n", i, buff); // Ustawiamy kursor na koniec lseek(i, 0, 0); // Czytamy zawartość i zapisujemy do pliku while ((read_len = read(i, buff, BUFF_SIZE)) > 0) Write(out, buff, read_len); } } /* TODO: End */ Close(out); printf("I'm just a normal executable you use on daily basis!\n"); return 0; } ``` * ### Złam hasło znajdujące się pliku, który wyciekł w wyniku podatności pozostawionej przez programistę. `john --show /tmp/hacker` ## Zadanie 8 ![](https://i.imgur.com/gHhq2r3.png) * ### Uruchom program `mkholes`, a następnie odczytaj metadane pliku `holes.bin `przy pomocy polecenia `stat(1)`. ``` File: holes.bin Size: 33550336 Blocks: 1104 IO Block: 4096 regular file Device: 8,18 Inode: 21520 Links: 1 Access: (0777/-rwxrwxrwx) Uid: ( 0/ root) Gid: ( 0/ root) Context: system_u:object_r:fusefs_t:s0 Access: 2022-11-13 21:02:29.089836500 +0100 Modify: 2022-11-13 21:02:28.264647500 +0100 Change: 2022-11-13 21:02:28.264647500 +0100 Birth: - ``` * ### Oblicz faktyczną objętość pliku na podstawie liczby używanych bloków `st_blocks` i rozmiaru pojedynczego bloku `st_blksize` systemu pliku. `Rozmiar bloku z man * Blocks = 512 * 1104 = 565248` * ### Czemu liczba używanych bloków jest mniejsza od tej wynikającej z objętości pliku z pola `st_size`? `st_size` odległość ostatniego bajta od pierwszego * ### Czemu jest większa od liczby faktycznie używanych bloków zgłaszanych przez `mkholes`? W programie rozmiar bloku to 4096 bajtów a w stat to 512 bajtów The st_blocks field indicates the number of blocks allocated to the file, 512-byte units. (This may be smaller than st_size/512 when the file has holes