Skip to content
Runtime
Go back

Lab 2: system calls

Edit page

Lab地址

Using gdb (easy)


Sandbox a command(moderate)

1. 任务全景:系统调用是如何被“沙盒化”的?

在 xv6 中,所有的系统调用最终都会流经 kernel/syscall.c 中的 syscall() 函数。我们要做的就是在执行真正的功能函数之前,插一个“安检口”。

执行流程图: 用户程序调用 interpose(mask, "-") -> 触发 ecall -> 进入内核 syscall() -> 执行 sys_interpose 保存掩码 -> 之后该进程再次执行其他系统调用 -> syscall() 检查掩码 -> 若命中则拒绝。

2. 详细实现步骤

第一阶段:打通用户态与内核态的“隧道”

你需要让内核识别 interpose 这个名字和对应的编号。

  1. 定义编号:在 kernel/syscall.h 中添加 #define SYS_interpose 22
  2. 用户态声明:在 user/user.h 中添加 int interpose(int, char*);,让 C 编译器知道这个函数的存在。
  3. 生成存根:在 user/usys.pl 末尾添加 entry("interpose");。这样 make 时会自动生成汇编代码,负责将 SYS_interpose 放入 a7 寄存器并执行 ecall
  4. Makefile 配置:在 UPROGS 中添加 $U/_sandbox\,确保 sandbox.c 会被编译进磁盘镜像。

第二阶段:在内核中建立“记忆”

内核需要为每个进程单独存储一份“禁止名单”。

  1. 修改 PCB:在 kernel/proc.hstruct proc 结构体中添加 int interpose_mask;
  2. 实现功能函数:在 kernel/sysproc.c 中编写 sys_interpose
  1. 内核映射:在 kernel/syscall.c 中,使用 extern 声明 sys_interpose,并在 syscalls[] 数组中建立映射。

第三阶段:权限拦截与继承

这是沙盒真正起作用的地方。

  1. 拦截逻辑:修改 kernel/syscall.csyscall() 函数。
  1. 实现继承:修改 kernel/proc.c 中的 kfork()

3. Q&A


Sandbox with allowed pathnames(easy)

1. 核心区别:从“行为控制”到“资源控制”

2. 开发要点(核心修改逻辑)

要在代码中实现这种区别,需要关注以下四个环节:

A. 状态存储的扩展 (Storage)

B. 数据拷贝的安全性 (Data Copying)

C. 子进程的完整继承 (Inheritance)

D. 特殊系统调用的拦截处理 (Special Casing)

  1. 检查掩码是否命中。
  2. 如果命中,且是 openexec,则提取该调用的第一个参数(路径名)。
  3. 使用 strncmp 比较提取出的路径与 p->allowed_path
  4. 如果匹配,放行(By-pass);如果不匹配,拒绝


Edit page
Share this post on:

Next Post
线性基