--- tags: Unix --- # Midterm example ## 2018 midterm #### 1. What is the difference between a character device and a block device? How to determine if a descriptor is opened for a character device or a block device? (CH4 p.51-52) - 針對 block device 一個 Block 只能處理一到多個完整 Block 的 I/O 操作,Character devices 可以被當作 A stream of bytes 來被 Accessed,就像 File 一樣。 - 實做上可以先藉由 stat funciton 得到 stat 的 buffer 並使用 S_ISCHR(buffer.st_mode), S_ISBLK(buffer.st_mode) 去確認 - /dev/tty0 是一種 character device ; /dev/sda2 是一種 block device #### 2. In the output of size command, why there is not any size given for heap and stack - stack 跟 heap 是動態才會 allocated ,故執行前無法得知大小 #### 3. Why do we need a salt when generating a hashed or encrypted password in UNIX system? - 使 hash 或 encrypt 的密碼經過額外幾個 byte 的 salt 的指定來加密會更為安全 #### 4. We have demonstrated how to setup M_MMAP_THRESHOLD using mallopt() function. What is the impact of M_MMAP_THRESHOLD? - int mallopt(int param,int value) 位控制記憶體分配的函數,而其中 M_MMAP_THRESHOLD 指的是,若小於這個值則記憶體配置會使用 sbrk (改變 heap 的上限)來配置,反之則用 mmap 來配置 - sbrk 來配置記憶體 free之後不會還給kernel mmap的才會 :::info 動態配置記憶體有兩種 - 1. malloc -> 實際上是使用 sbrk 改變 heap 區塊頂端的大小來配置 - 2. mmap -> 在一個未被配置的區塊配置記憶體 (heap & stack 之間) 當通過malloc/new申請的記憶體小於m_mmap_threshold(預設128k)時,glic呼叫brk來申請記憶體,當要申請的記憶體大於m_mmap_threshold時,glic呼叫mmap來申請記憶體 ::: #### 5. We have demonstrated the following code in the class that the output of the following code contains two "hello world" messages if the output is redirected to a file, Please revise the code to ensure that there is always only one "hello, world" message in the output ```diff #include <unistd.h> #include <stdio.h> #include <stdlib.h> int main() { pid_t pid; printf("hello, world!\n"); + fflush(stdout); pid = fork(); if (pid < 0) { printf("error\n"); exit(0); } else if (pid == 0) { printf("I am child\n"); } else { printf("I am parent\n"); } return 0; } ``` #### 6. Many UNIX-like Oses have `lchown()` function for changing the downership of symbolic link, but they do not have `lchmod()` function for changing the mode bits for a symbolic link, What would be the design consideration for this choice? If we plan to changes the mode bits for a symbolic link, what function can we use? - symbolic link做讀寫執行操作的時候 都會解析到真正的path ,所以symbolic link本身的mod就不是那麼重要,但針對symbolic link本身的操作就會需要吃操作者的權限,所以有提供lchown這個功能 - symbolic link 可以用fchmodat 來change mode #### 7. Given the following codes running by root. What would be the output of the program? ``` 0 0 1000 1000 ``` #### 8. Suppose the administrator would like to grant root permmision to a program P. The program can be only launched by root and users belong to a group of gid 3000. How to properly configure the ownership and mode bits for P? Write down the commands to perform the setups. ``` $ ls -l p -rwxrwxr-x 1 chialiang86 chialiang86 16920 四 17 22:15 P $ sudo chmod 0770 P # -rwxrwxr-x -> -rwxrwx--- $ sudo chown 0:3000 P # chialiang86 chialiang86 -> root 3000 $ ls -l p -rwxrwx--- 1 root 3000 16920 四 17 22:15 P ``` #### 9. Given the below source codes for program P. What would be the output on the console if we run the command 'P>/dev/null'? ```c #include <unistd.h> #include <stdio.h> int main() { setvbuf(stdout, NULL, _IOFBF, 0); fprintf(stdout, "aaaa\n"); fprintf(stderr, "bbbb\n"); // out bbbb dup2(1, 0); // 0:out 1:out 2:err dup2(2, 1); // 0:out 1:err 2:err dup2(0, 2); // 0:out 1:err 2:out fprintf(stdout, "cccc\n"); fprintf(stderr, "dddd\n"); // out dddd (eaten when out to /dev/null) return 0; // out aaaa // out cccc } ``` ``` bbbb aaaa cccc ``` #### Working with symbols loaded from a shared object (or dynamic library) requires the knowledge of function pointers. Suppose we plan to load a function `test` from a shared object `libtest.so` 1. function pointer pt to get int test(int val); ```c int (*pt)(int); ``` 2. implement the code to open libtest.so ```c void* handle = dlopen("/path/to/libtest.so", RTLD_LAZY); pt = (int (*)(int))dlsym(handle, "test"); ``` 3. call the function pointer pt ```c int ret = pt(0xbeef); ``` ## 2019 midterm #### 1. 同 2018 - 3 #### 2. Given the following codes, please explain what could be the actual disk spaces allocated for output.bin file ```c #include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <stdlib.h> int main() { int fd = open("output.bin", O_CREAT | O_WRONLY | O_TRUNC, 0644); if (fd < 0) return -1; for (int i = 0; i < 100; i++) { lseek(fd, 16384*(1+rand()%3) - sizeof(i), SEEK_SET); write(fd, (char*) &i, sizeof(i)); } close(fd); return 0; } ``` - 12 K-Byte (3 個 block size) #### 3. 同 2018 - 5 #### 4. Given the source codes of a suid program owned by root, please add more codes to ensure that it can be only used to delete files owned by the user launches the program ```diff char *user = getenv("USER"); char *dir = getenv("DIRNAME"); if (user && dir) { snprintf(cmd, sizeof(cmd), "rm -rf /home/%s/%s", user, dir); } ++ char path[1024]; ++ sprintf(path, "/home/%s/%s", user, dir); ++ if (access(path, W_OK) == 0) system(cmd); ``` #### 5. Write a small C program named `z2k` that create exactly 20000 zombie processes left in the system. To test tour program, you should be able to launch `z2k` and then use ps command to list all the created zombie process using prompts of the same shell ```c #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <sys/wait.h> int main() { pid_t pid; int status; for (int i = 0; i < 2000; i++) { pid = fork(); if (pid == 0) exit(0); } sleep(5); pid = wait(&status); if (WIFEXITED(status)) fprintf(stderr, "\n\t[%d]\tProcess %d exited with status %d.\n", (int) getpid(), pid, WEXITSTATUS(status)); return 0; } ``` #### How to prevent an executable from being hijacked by using LD_PRELOAD ? - 加上 static ``` $ gcc -o 2019-6 2019-6.c -static ``` ## example question - helloworld.c ```c #include <stdlib.h> #include <unistd.h> #include <string.h> #include <signal.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/wait.h> #define errquit(x) { perror(x); _exit(-1); } static char msg[] = "hello, world!\n"; int main(int argc, char *argv[]) { int pid, fd[2]; if(argc < 2) { fprintf(stderr,"usage: helloworld /path/to/your/program\n"); return -1; } signal(SIGALRM, _exit); if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0) errquit("socketpair"); if((pid = fork()) < 0) { perror("fork"); exit(-1); } if(pid == 0) { dup2(fd[1], 0); dup2(fd[1], 1); close(fd[0]); close(fd[1]); execl(argv[1], argv[1], NULL); _exit(-1); } else { char buf[256]; FILE *fp = NULL; if((fp = fdopen(fd[0], "r+")) == NULL) errquit("fdopen"); alarm(2); if(fgets(buf, sizeof(buf), fp) == NULL) goto err; if(strcmp(buf, msg) != 0) goto err; printf("Bingo!\n"); do { int st, pid; if((pid = fork()) < 0) { perror("fork"); break; } if(pid == 0) { execl(getenv("READFLAG"), "FLAG", NULL); perror("exec"); _exit(0); } waitpid(pid, &st, 0); } while(0); } return 0; err: fprintf(stderr, "No no no ...\n"); return -1; } ```