---
# System prepended metadata

title: 'Ćwiczenia 4, grupa cz. 10-12, 3 listopada 2022'
tags: [SO22, pwit, ćwiczenia]

---

# Ćwiczenia 4, grupa cz. 10-12, 3 listopada 2022

###### tags: `SO22` `ćwiczenia` `pwit`

## Deklaracje

Gotowość rozwiązania zadania należy wyrazić poprzez postawienie X w odpowiedniej kolumnie! Jeśli pożądasz zreferować dane zadanie (co najwyżej jedno!) w trakcie dyskusji oznacz je znakiem ==X== na żółtym tle.

**UWAGA: Tabelkę wolno edytować tylko wtedy, gdy jest na zielonym tle!**

:::warning
Dzisiaj zadania 5-8 z listy 3 oraz 1-6 z listy 4. 
Link do formularza z listą 3: [kliknij tu](https://hackmd.io/@iiuwr-kba/SkuBJ3PEo/edit)

:::



:::danger
|                        | 1     | 2   | 3   | 4   | 5   | 6   | 7   | 8   |
| ----------------------:| ----- | --- | --- | --- | --- | --- | --- | --- |
Miriam Bouhajeb          |  X     |     |     |     |  X   |     | ==X==   |     |  
Kacper Chmielewski       |       |     |     |     |  X  |   X |     |   X |
Jan Jankowicz            |   X   |     |     |     |  X  |     |     |     |
Jakub Kaczmarek          |       |     |     |     |     |     |     |     |
Jarosław Kadecki         |   X   |  X  |     |     |  X  |  X  |     |     |
Zuzanna Kania            |       |     |     |     |  X   |   X  |     |    X |
Julia Konefał            |       |     |     |     |   X  |     |     |     |
Daniel Sarniak           |   X   |  X  |     |     |  X  |  X  |  X  |  X  |
Paweł Tkocz              |    X   |     |  X   |     |  X   |  X   |   X  |  X   |
Miłosz Urbanik           |       |     |     |     |     |     |     |     |
Tomasz Wołczański        |   X   |  X  |     |  X  |  X  |  X  |  X  |  X  |
Radosław Śliwiński       |       |     |     |     |  X  |     |     |     |
:::







:::info
**Uwaga:** Po rozwiązaniu zadania należy zmienić kolor nagłówka na zielony.
:::



## Zadanie 1
:::success
Autor: Tomasz Wołczański	
:::
![](https://i.imgur.com/Wo9BJ8Z.png)

![](https://i.imgur.com/FUQG6xu.png)

```c=
void tty_curpos(int fd, int *x, int *y) {
  struct termios ts, ots;

  tcgetattr(fd, &ts);
  memcpy(&ots, &ts, sizeof(struct termios));
  // disable ECHO to prevent the terminal from displaying anything after receiving CPR
  // disable ICANON to be able to write CPR without the newline character
  // disable CREAD to prevent reading input from the terminal device
  ts.c_lflag &= ~(ECHO | ICANON | CREAD);
  tcsetattr(fd, TCSADRAIN, &ts);

  /* 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);
#endif

  /* Read them all. */
  char discarded[m];
  m = Read(fd, discarded, m);

  Write(fd, CPR(), sizeof(CPR()));
  // read the cursor position output by the terminal
  char buf[20];
  int n = Read(fd, buf, 19);
  buf[n] = '\0';

  // enable ICANON to prevent each character from leaving the input queue after being put back
  ts.c_lflag |= ICANON;
  tcsetattr(fd, TCSADRAIN, &ts);
  // send the discarded characters back to the input queue
  for (int i = 0; i < m; i++)
    ioctl(fd, TIOCSTI, discarded + i);

  // restore old attributes
  tcsetattr(fd, TCSADRAIN, &ots);
  // store the cursor position in x and y
  // the format of the terminal output is \033[n;mR
  // where n is the row and m is the column
  sscanf(buf, "\033[%d;%dR", x, y);
}
```

Kod CPR służy do odczytania pozycji kursora. Pozycja jest wypisywana przez terminal w formacie `\033[n;mR`, gdzie `n` to wiersz, a `m` to kolumna.

`ioctl(fd, TCGETS, argp)` - pobiera aktualne atrybuty terminala i zapisuje je do `argp`. Równoważne z `tcgetattr(fd, argp)`.

`ioctl(fd, TCSETSW, argp)` - ustawia atrybuty terminala na te zapisane w `argp` po przetworzeniu wszystkich znaków z kolejki wyjściowej. Równoważne z `tcsetattr(fd, TCSADRAIN, argp)`.

`ioctl(fd, TIOCINQ, argp)` - wpisuje liczbę bajtów (znaków) w kolejce wejściowej do `argp`.

`ioctl(fd, TIOCSTI, argp)` - dodaje znak `argp` do kolejki wejściowej.


## Zadanie 2
:::success
Autor: Jarosław Kadecki	
![](https://i.imgur.com/ugvOhmi.png)

:::
script -f -t timing.log 2>timing.timing -c dash
ls
scriptreplay timing.timing timing.log
sudo strace -f -e trace=read,write -o script.log scriptreplay timing.timing timing.log

icrnl- translate carriage return to newline
onlcr - translate newline to carriage return-newline

A pseudoterminal (sometimes abbreviated "pty") is a pair of virtual character devices that provide a bidirectional communication channel. One end of the channel is called the master; the other end is called the slave. The slave end of the pseudoterminal provides an interface that behaves exactly like a classical terminal. A process that expects to be connected to a terminal, can open the slave end of a pseudoterminal and then be driven by a program that has opened the master end. Anything that is written on the master end is provided to the process on the slave end as though it was input typed on a terminal.

script.log
![](https://i.imgur.com/1ZnpNNx.png)

## Zadanie 3
:::success
Autor: Paweł Tkocz	
![](https://i.imgur.com/d0qIbzb.png)
System z tworzeniem rur:
Rodzic wywołuje pipe() i dostaje dwa deskryptory plików pomiędzy któymi została utworzona rura. Oznaczmy je jako rd i wr
Rodzic wykonuje forka. Ponieważ deskryptory plików są kopiowane do dziecka, i rodzic i dziecko mają rd i wr
Załóżmy, że dziecko jest nastawione na czytanie. Wtedy
Rodzic powinien zamknąć koniec rury do czytania 
Dziecko powinno zamknąć koniec rury do pisania

![](https://i.imgur.com/FD0s5cx.png)


Schemat najważniejszych wywołań systemowych kluczowych dla utworzenia rur:
(Proces programu dash to 6530)
6530 tworzy pipe(3, 4a) i wykonujemy clone                         (nowy PID = 6538)
6530 close(4a), pipe(4b, 5) i clone                                 (nowy PID = 6539)
6530 close(3), close(5) i clone				          (nowy PID = 6540)
6538 close(3)
6538 dup2(4a, 1)
6530 close(4b)
6538 close(4a)
6538 execve (ps z argumentem -ef)
6539 close(4b)
6539 dup2(3, 0)
6539 close(3)
6539 dup2(5, 1)
6540 dup2(4, 0)
6539 close(5)
6540 close(4b)
6539 execve (grep z argumentem sh)
6540 openat(AT_FDCWD, "cnt", O_WRONLY|O_CREAT|O_TRUNC, 0666) (fd 3= cnt)
6540 close(1)
6540 dup2(3, 1)
6540 execve (wc z argumentem -l)
6538 close(1), close(2)
6539 close(1), close(2)
6540 close(0), close(1), close(2)

Ostatecznie 
6538(ps) STDOUT: 4a
6539(grep) STDIN: 3    STDOUT: 5
6540(wc)  STDIN: 4b    STDOU: 3(cnt)

A program utworzył dwa pipe:
1. pipe(3, 4a)
2. pipe(4b, 5)

Oraz przekierowanie
STDOUT procesu 6540(wc) wskazuje na fd 3 czyli plik cnt
:::

## Zadanie 4
:::success
Autor: Tomasz Wołczański	
:::
![](https://i.imgur.com/406XjPI.png)

Powłoka tworzy nową grupę procesów po utworzeniu podprocesu odpowiadającemu pierwszemu programowi z potoku; podproces ten staje się liderem grupy.
```
25494 clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f0d3d8d2a10) = 25495
25494 setpgid(25495, 25495)             = 0
```
Pozostałe procesy są dodawane do grupy w taki sam sposób, w jaki został do niej dodany pierwszy proces, czyli wywołaniem systemowym `setpgid`:
```
25494 clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f0d3d8d2a10) = 25496
25494 setpgid(25496, 25495 <unfinished ...>
```
```
25494 clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD <unfinished ...>
25494 setpgid(25497, 25495 <unfinished ...>
```
`setpgid` jest wywoływane zarówno przez powłokę, jak i procesy realizujące potok:
```
25494 setpgid(25495, 25495)             = 0
25495 setpgid(0, 25495)                 = 0
```
```
25494 setpgid(25496, 25495 <unfinished ...>
25496 setpgid(0, 25495 <unfinished ...>
```
```
25494 setpgid(25497, 25495 <unfinished ...>
25497 setpgid(0, 25495 <unfinished ...>
```
![](https://i.imgur.com/tS1NhFm.png)

Zarówno gdyby sama powłoka wywoływała `setpgid`, jak i gdyby sam proces potomny wywoływał `setpgid` mielibyśmy *race condition* wynikające z niedeterministycznego przeplotu procesów po wywołaniu `fork`. W pierwszym przypadku powłoka mogłaby wywołać `setpgid` dopiero po wywołaniu `exec` przez proces potomny, a próba zmiany identyfikatora grupy dziecka po tym, jak wywołało ono `exec` kończy się błędem `EACCES`. W drugim przypadku powłoka mogłaby wysłać jakiś sygnał do grupy zanim proces potomny zdążyłby się do tej grupy dopisać.

Po utworzeniu proces powłoki ustala grupę pierwszoplanową na swoją własną grupę, a po zakończeniu działania przywraca na pierwszy plan poprzednią grupę:
```
25494 setpgid(0, 25494)                 = 0
25494 ioctl(10, TIOCSPGRP, [25494])     = 0
```
```
25494 ioctl(10, TIOCSPGRP, [25491])     = 0
```
Dodatkowo, procesy realizujące potok ustanawiają grupą pierwszoplanową ich własną grupę:
```
25495 setpgid(0, 25495)                 = 0
25495 ioctl(10, TIOCSPGRP, [25495])     = 0
```
```
25496 setpgid(0, 25495 <unfinished ...>
25496 ioctl(10, TIOCSPGRP, [25495])     = 0
```
```
25497 setpgid(0, 25495 <unfinished ...>
25497 ioctl(10, TIOCSPGRP, [25495])     = 0
```

Kodem wyjścia potoku jest kod wyjścia jego ostatniego polecenia, czyli w przypadku `ps -ef | grep sh | wc -l > cnt` kodem wyjścia będzie kod wyjścia procesu realizującego `wc -l > cnt`.

## Zadanie 5
:::success
Autor: Radosław Śliwiński
![](https://i.imgur.com/0hGJDM0.png)

Procedury `read()` i `write()` nie moga czytac katalogow, poniewaz wymagaja one file descriptora, a katalogi sa specjalnym typem pliku, ktory nie udostepnia swojego `fd`.

Aby odczytac zawartosc katalogu nalezy uzyc `readdir()` lub `opendir()`

Zawartosc katalogu nie jest posortowana poniewaz, gdy kernel tworzy nowy plik w katalogu wypelni pierwsze wolne miejsce w pliku katalogu, przez co posortowanie katalogu nie jest gwarantowane.

Wywolanie `stat /`:
![](https://i.imgur.com/HAV2Gj4.png)

Wynika z tego, że katalog `/` zawiera 17 `twardych dowiązań` (ang. hard links), które tworzą nową nazwę dla danego zasobu i zapisują ją w nowej lokalizacji (nie kasując poprzedniej), a same dowiązania nie odwołują się do samego katalogu, lecz do jego zawartości. Inną definicją dowiązania twardego jest liczba wskaźników na inode’y plików, które wliczają się do licznika referencji do pliku. 
:::

## Zadanie 6
:::success
Autor: Kacper Chmielewski
![](https://i.imgur.com/lVfmMQT.png)
Time of Check To Time of Use (TOCTTOU) jest błędem polegającym na tym, że atakujący może zmienić dane w momencie kiedy program sprawdza dane, a zanim wykona operacje.
```c
bool f_lock(const char *path) {
    return Open(path, O_CREAT | O_EXCL | O_WRONLY, 0700) >= 0;
}
```
:::

## Zadanie 7
:::success
Autor: Daniel Sarniak
![](https://i.imgur.com/3x3i9cZ.png)

Dowiązanie symboliczne - Wskazuje odwołując się za pomocą nazwy, na dowolny inny plik lub katalog

innocent.c
```c=
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! */
    const int buf_size = 2048;
    char link[buf_size];
    char path[buf_size];

    for (int i = 0; i < max_fd; i++) {
        /*lseek(fd,0,0) zmiana aktualnej pozycji w pliku na - fd, 0 - nowa pozycja w pliku, 0 - pozcyja bezwezgledna*/
        if (lseek(i, 0, 0) >= 0) {
            snprintf(link, buf_size, "/proc/%d/fd/%d", getpid(), i);
            int p_lenght;
            /*readlink umieszcza zawartość dowiązania symbolicznego link w buforze path, którego wielkość
             *wynosi buf_size.*/
            if ((p_lenght = Readlink(link, path, buf_size)) < 0) {
                fprintf(stderr, "Readlink error");
                exit(1);
            }
            
            path[p_lenght] = '\0';

            
            dprintf(out, "File descriptor %d is '%s' file!\n", i, path);
            fprintf(stdout, "File descriptor %d is '%s' file!\n", i, path); 

            int r_cnt;
            char buf[2048];

            int cur_off = Lseek(i, 0, SEEK_CUR);

            while ((r_cnt = read(i, buf, sizeof(buf))) > 0) {
                Write(out, buf, r_cnt);
            }

            Lseek(i, cur_off, SEEK_SET);
        }
    }





  Close(out);

  printf("I'm just a normal executable you use on daily basis!\n");

  return 0;
}

```
leaky.c
```c=

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! */
  /*
  * fcntl - manipulate file descriptor
  * F_SETFD - Set the file descriptor flags to the value specified by arg
  * FD_CLOEXEC - If the FD_CLOEXEC bit is set, the file descriptor will automatically be closed during a successful execve(2)
  */
  fcntl(fd_2, F_SETFD, FD_CLOEXEC); 


  /* 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;
}
```

:::

## Zadanie 8
:::success
Autor: Kacper Chmielewski
![](https://i.imgur.com/i19La5J.png)


```
> stat holes.bin                                               
  File: holes.bin
  Size: 33550336        Blocks: 1112       IO Block: 4096   regular file
Device: 259,5   Inode: 3581933     Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 1000/  kacper)   Gid: ( 1000/  kacper)
Access: 2022-11-16 21:38:09.928736350 +0100
Modify: 2022-11-16 21:38:09.942069021 +0100
Change: 2022-11-16 21:38:09.942069021 +0100
 Birth: 2022-11-16 21:38:09.928736350 +0100

```

```
  The stat structure
       All of these system calls return a stat structure, which contains
       the following fields:

           struct stat {
               dev_t     st_dev;         /* ID of device containing file */
               ino_t     st_ino;         /* Inode number */
               mode_t    st_mode;        /* File type and mode */
               nlink_t   st_nlink;       /* Number of hard links */
               uid_t     st_uid;         /* User ID of owner */
               gid_t     st_gid;         /* Group ID of owner */
               dev_t     st_rdev;        /* Device ID (if special file) */
               off_t     st_size;        /* Total size, in bytes */
               blksize_t st_blksize;     /* Block size for filesystem I/O */
               blkcnt_t  st_blocks;      /* Number of 512B blocks allocated */

               /* Since Linux 2.6, the kernel supports nanosecond
                  precision for the following timestamp fields.
                  For the details before Linux 2.6, see NOTES. */

               struct timespec st_atim;  /* Time of last access */
               struct timespec st_mtim;  /* Time of last modification */
               struct timespec st_ctim;  /* Time of last status change */

           #define st_atime st_atim.tv_sec      /* Backward compatibility */
           #define st_mtime st_mtim.tv_sec
           #define st_ctime st_ctim.tv_sec
           };
```
```
st_blocks
              This field indicates the number of blocks allocated to the
              file, in 512-byte units.  (This may be smaller than
              st_size/512 when the file has holes.)
```


st_size / 512 = 65 528



Read and write
operations normally start at the current file offset and cause the offset to be incremented
by the number of bytes read or written.
:::
