系列文章 : [6.1810] 跟著 MIT 6.1810 學習基礎作業系統觀念
大綱
- Sandbox a command(moderate)
- Sandbox with allowed pathnames(easy)
- Attack xv6 (moderate)
Sandbox a command(moderate)
作業要求
- In this assignment you will "sandbox" a process to restrict the system calls it can make.
- For example, one might sandbox a process to disallow opening files. You'll create a new
interpose system call that will specify which system calls the kernel should reject from the calling process.
- interpose should take two arguments
- an integer mask and a path.
- The mask's bits specify which system calls to reject.
- The second argument you will use in the next assignment and in this assignment it is always "-".
- For example, in order for a process to prevent itself from using the open system call, it should call
interpose(1 << SYS_open, "-"), where SYS_open is a syscall number from kernel/syscall.h.
- Your implementation should
cause the mask to be inherited by children of fork, so that children inherit the parent's restrictions.
- We've provided you with a user/sandbox.c user program that forks, calls interpose() in the child, and then execs a program in the child. When you're done implementing interpose(), you should see output like this:
$ sandbox 32768 - cat README
cat: cannot open README
$
- 可以用
grade-lab-syscall sandbox_mask 來檢查作業有沒有寫錯
$ ./grade-lab-syscall sandbox_mask
== Test sandbox_mask == sandbox_mask: OK (1.5s)
作業提示
- Add $U/_sandbox to UPROGS in Makefile
- Run make qemu and you will see that the compiler cannot compile user/sandbox.c, because the user-space stubs for the interpose system call don't exist yet
- add a prototype for interpose to user/user.h
- a stub to user/usys.pl
- and a syscall number to kernel/syscall.h.
- The Makefile invokes the perl script user/usys.pl, which produces user/usys.S, the actual system call stubs, which use the RISC-V ecall instruction to transition to the kernel.
- Once you fix the compilation issues, run sandbox 32768 - cat README in the xv6 shell; it will fail because you haven't implemented the system call in the kernel yet.
- Add a sys_interpose() function in kernel/sysproc.c that implements the new system call by recording the mask argument in a new field in the proc structure (see kernel/proc.h).
- The functions to retrieve system call arguments from user space are in kernel/syscall.c, and you can see examples of their use in kernel/sysproc.c. Add your new sys_interpose to the syscalls array in kernel/syscall.c.
- Modify kfork() (see kernel/proc.c) to copy the mask from the parent to the child process.
- Modify the syscall() function in kernel/syscall.c to check if the system call must be rejected.
作業內容
- 把 sandbox 加進 Makefile,這樣 build system 才會去 build sandbox。
- 在 user/user.h 裡面新增一個
interpose 的 protocol type
void interpose(int, char *);
- 在 usys.pl 裡面新增一項
interpose
entry("interpose");
- 在 kernel/syscall.h 為
interpose 新增一個 syscall number。
#define SYS_interpose 22
- Makefile 會仰賴
usys.pl 來建立 usys.S。現在我們預期可以成功 build 好所有的 binary,並 boot xv6-riscv to prompt。
- 在 kernel/proc.h/struct proc 裡面新增 interpose_mask
- 在
kernel/sysproc.c 裡面實作 sys_interpose()
- 在 kernel/syscall.c 裡面,將
sys_interpose 加進 syscalls array 裡面
- 修改
kernel/proc.c/kfork()
- 修改
kernel/syscall.c/syscall()
- 使用
grade-lab-syscall sandbox_mask 檢查作業有沒有正確
make: 'kernel/kernel' is up to date.
== Test sandbox_mask == sandbox_mask: OK (1.6s)
Sandbox with allowed pathnames(easy)
作業要求
- In this assignment you will extend the sandbox to allow masked open and exec system calls based on the pathname they use.
- The second argument of sys_interpose is the pathname allowed.
- If
open or exec is masked but the pathname matches the allowed pathname, then these system calls should be allowed.
作業提示
- Modify sys_interpose() to remember the allowed pathname. argstr will be handy to retrieve the pathname. You can declare a buffer of size MAXPATH in the proc struct.
- If
open or exec are masked, check if the pathname matches the allowed pathname. If so, allow the execution of those system calls.
作業內容
- 在 sys_interpose 裡面,去保存 path
- 在 kernel/proc.h/struct proc 裡面新增 char interpose_path[MAXPATH]
- 在 kernel/syscall.c/syscall() 一開始,不論如何都讓 sys_open, sys_exec 可以執行
- 在 sys_open 裡面去檢查 path
- 在 sys_exec 裡面去檢查 path
Attack xv6 (moderate)
作業要求
-
The xv6 kernel isolates user programs from each other and isolates the kernel from user programs.
- As you saw in the above assignments, an application cannot directly call a function in the kernel or in another user program; instead, interactions occur only through system calls.
- However, if there is a bug in the kernel's implementation of a system call, an attacker may be able to exploit that bug to break the isolation boundaries.
- To get a sense for how bugs can be exploited, we have introduced a bug into xv6 and your goal is to exploit that bug to steal a secret from another process.
-
The bug is that the call to memset(mem, 0, sz) in uvmalloc() in kernel/vm.c to clear a newly-allocated page is omitted when compiling this lab.
- Similarly, when compiling
kernel/kalloc.c for this lab the two lines that use memset to put garbage into free pages are omitted.
- The net effect of omitting these 3 lines (all marked by ifndef LAB_SYSCALL) is that newly allocated memory retains the contents from its previous use.
- Thus an application that calls sbrk() to allocate memory may receive pages that have data in them from previous uses. Despite the 3 deleted lines, xv6 mostly works correctly; it even passes most of usertests.
-
user/secret.c writes a secret string in its memory and then exits (which frees its memory).
- Your goal is to add a few lines of code to user/attack.c to find the secret that a previous execution of secret.c wrote to memory, and to print the secret on a line by itself.
-
Your attack.c must work with unmodified xv6 and unmodified secret.c.
- You can change anything to help you experiment and debug, but must revert those changes before final testing and submitting.
作業內容
- 依作業要求,先把
kernel/vm.c/uvmalloc() 的 memset(mem, 0, sz) 拿掉。
- 依作業要求,把
kernel/kalloc.c 的 memset 也拿掉。
- 實作 attack.c
- 使用
./grade-lab-syscall attack 來驗證實作
make: 'kernel/kernel' is up to date.
== Test attack == attack: OK (0.7s)
- Q: 為什麼我的攻擊,總要等到第二次 attack 才會成功呢 ?? 可能需要研究看看第一次就能成功的方法
Reference