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