内核考试的范围广,难度大,想要在没有网络,仅参考内核代码的情况下写出符和题目要求的程序是极难的。那如何在规则允许的情况下,快速读懂问题,找到关键信息,合理编码解决问题呢?这个问题很大。但是第一步,是对各个模块的基本概念熟悉,不要因为概念的混乱导致做题成一个糊涂蛋!
初级题
题目一
一、开发内核模块,模块名:uos-kernel_test2024-01。实现一个简单数据库,支持CRUD(增查改删)。
1.通过/dev/uosdb设备与用户层通信,使用ioctl实现CRUD功能。
数据库每条记录字段定义如下:
struct uosdb_record {
pid_t pid; // 进程号
int key; // 键
char *val; // 值
unsigned int vlen; // 值的长度,最大为一页
};
ioctl的cmd定义如下:
- cmd=1:新增一条记录。ioctl传5个参数,第3、4、5参数分别传:key、val、vlen,key必须大于0。若key已存在返回返回-EEXIST;
- cmd=2:查询记录。ioctl传6个参数,第3、4参数分别传:key、buffer、 buffer_len、out_len。当key为0时,查询当前进程所有的记录;
- cmd=3: 修改历史记录。 ioctl的第3、4、5参数分别传:key,new_val,new_vlen,修改key对应的val值,若key不存存,返回-ENOENT;
- cmd=4: 删除历史记录。ioctl传3个参数,第3个参数传key,若key不存存,返回-ENOENT;
2.用户态多进程/多线程操作数据库时,确保数据正常和一致
- 答题结果及提交形式:
- 提交的代码需加入必要的注释;
- 提交简要的设计文档以及使用说明;
- 代码编译以及运行过程的录像;
题目二
二、开发一个字符设备驱动,内部最大缓存区为1M,支持O_NONBLOCK标志位,即在进行文件读写时若设置了 O_NONBLOCK 标志位则使用非堵塞访问,即当设备内部缓存区为空时read系统调用立刻返回对应的错误码,当设备内部缓存区满时write系统调用直接立刻返回相应的错误码。不然则使用堵塞访问,即当设备内部缓存区为空时read系统调用应等待缓存区有数据时再读取数据返回,当设备内部缓存区满时write系统调用应等待缓存区有空间时写入数据再返回。
要求:
- 必须开发内核模块实现此功能;
- 字符设备文件名为/dev/my_char_dev;
- O_NONBLOCK标志位可以在系统调用open时设置,也可以在系统调用fcntl时设置;
答题结果及提交形式:
- 提交的代码需加入必要的注释;
- 提交简要的设计文档以及使用说明;
- 代码编译以及运行过程的录像;
中级题
题目三
三、通过增加系统调用接口,实现如下功能 1.增加系统调用,系统调用定义:sys_uos_kernel_test2024-01(int cmd, char __user *buffer, unsigned int buffer_len);
cmd定义如下:
cmd=1:返回当前进程的vma信息。每个vma占一行,每行包括起始虚拟地址,vma的flag,输出如下:
vma1: range=0x0000-0xffff, flag=0x1234
vma2: range=0x10000-0xfffff, flag=0x2345
…
cmd=2:返回当前进程已注册的信号处理器。每个结果占一行,每行包括信号、处理函数地址,输出如下:
signal1:signo=2, handler=0xabde3333
signal2:signo=3, handler=0xabde3333
….
cmd=3:返回当前进程已打开文件信息。每个已打开文件占一行,每行包括fd号、文件名。
file1: fd=1, name=xxxx,
file2: fd=2, name=xxxx,
…
2.增加2个系统调用,在内核里实现为用户空间程序的分配、释放内存。分配、释放的功能与glibc里提供的malloc、free功能类似。
要求:
a分配的内存必须是连续的物理内存,且最大支持16M。
b返回用户可用的虚拟地址,且在内核日志中打印虚拟地址+物理地址。
系统调用定义:
long sys_uos_kernel_test2024_02_malloc(size_t size)
入参:
size 用户期望分配的内存大小,单位:byte
出参:
分配成功,返回虚拟地址
分配失败,返回标准错误码
long sys_uos_kernel_test2024_02_free(long uvaddr);
入参:
uvaddr 用户要释放的虚拟内存地址
出参:
释放成功,返回0
释放失败,返回标准错误码
答题结果及提交形式:
提交的代码需加入必要的注释;
提交简要的设计文档以及使用说明;
代码编译以及运行过程的录像;
第四题
“Use After Free”(UAF)漏洞通常是由于在释放内存后继续使用该内存导致的。以下是一个简单的示例;修改或者替换内存分配/释放(malloc/free)及其相关函数,实现如下功能
#include <stdlib.h>
typedef struct {
int data;
} Object;
int main() {
Object* obj = (Object*)malloc(sizeof(Object));
obj->data = 123;
free(obj); // 释放内存
// 在释放内存后继续使用该内存,这将导致 UAF 漏洞
int data = obj->data;
return 0;
}
1.在应用程序启动时,初始化影子内存自身映射到的地址段,以禁止程序的其他部分访问影子内存。
2.程序使用malloc申请内存时,在影子内存中记录每个字节使用情况。
3.free的时候在影子内存中记录状态。
4.使用mprotect来模拟编译器插装,捕获信号,并打印"Use After Free"信息。
答题结果及提交形式:
- 提交的代码需加入必要的注释;
- 提交简要的设计文档以及使用说明;
- 代码编译以及运行过程的录像;
高级题
第五题
实现一个新的文件系统dtmpfs:
1.启动时预留256M物理内存。
2.修改ramfs,实现dramfs:使用预留的物理内存存放文件数据。(提示:实现一个简单的预留内存分配器;修改read/write路径以使用预留内存;无需实现mmap)
3.实现文件的自动删除。超时时间可以通过挂载参数filetimeout指定,其默认时间可以通过模块参数指定,默认为60s。
4.实现文件名的大小写转换:大小写指向同一文件,可以通过任意大小写文件名索引该文件。文件所有者读取目录内容时,返回大写文件名,其他用户则返回小写文件名。
答题结果及提交形式:
- 提交的代码需加入必要的注释;
- 提交简要的设计文档以及使用说明;
- 代码编译以及运行过程的录像;