Featured image of post 内核考试题

内核考试题

内核考试的范围广,难度大,想要在没有网络,仅参考内核代码的情况下写出符和题目要求的程序是极难的。那如何在规则允许的情况下,快速读懂问题,找到关键信息,合理编码解决问题呢?这个问题很大。但是第一步,是对各个模块的基本概念熟悉,不要因为概念的混乱导致做题成一个糊涂蛋!

初级题

题目一

一、开发内核模块,模块名: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.实现文件名的大小写转换:大小写指向同一文件,可以通过任意大小写文件名索引该文件。文件所有者读取目录内容时,返回大写文件名,其他用户则返回小写文件名。

答题结果及提交形式:

  • 提交的代码需加入必要的注释;
  • 提交简要的设计文档以及使用说明;
  • 代码编译以及运行过程的录像;