-
-
[原创] CVE-2017-16995 的一些追加分析
-
发表于: 2018-5-24 22:39 4351
-
最近把在研究BPF,看到了关于CVE-2017-16995的一些分析报告。[2]和[3]上面对这个CVE的成因分析已经很详细了,主要就是32位无符号数被强制转化为64位无符号数的时候会产生符号拓展, 进而导致了在do_check和bpf_prog_run这两个程序中,ebpf程序的执行流程并不一致。具体细节可以参看[2]和[3], 我在我自己博客[4]里面也有分析, 欢迎围观。
这里我想讲讲在[2]和[3]中所漏掉的一些细节。首先上图证明我也重现出来了
在[1]和[2]中, 两文的作者都认为这个eBPF程序有41条指令, 但实际上在执行过程中,实际上只解析了40条指令。因为在bpf_prog_run[5]里对于opcode 0x18 (LD_IMM_DW) 是用如下代码进行的处理。可以发现是由两条insn合并成了一条指令
LD_IMM_DW: DST = (u64) (u32) insn[0].imm | ((u64) (u32) insn[1].imm) << 32; insn++; CONT;
LD_IMM_DW: DST = (u64) (u32) insn[0].imm | ((u64) (u32) insn[1].imm) << 32; insn++; CONT;
我也编写了一个小程序把ebpf程序转换成了可读代码如下。
程序源代码我已经放在了github[6]上,这个版本是用C写的,有一些corner case并没有包含在里面。之后可能回去写一个python版本的,感觉写起来更友好一些。
在[2]和[3]中似乎都没有讲明为何第五个指令(opcode 0x18)在执行过程中,就把一个指向bpf_map的pointer载入到了R[9]里。
这其实还是跟第五个指令的特殊性有关。
在调用do_check之前,bpf_check会调用一个特殊的函数 replace_map_fd_with_map_ptr
// https://elixir.bootlin.com/linux/v4.4.33/source/kernel/bpf/verifier.c#L2241 ret = replace_map_fd_with_map_ptr(env); if (ret < 0) goto skip_full_check; env->explored_states = kcalloc(env->prog->len, sizeof(struct verifier_state_list *), GFP_USER); ret = -ENOMEM; if (!env->explored_states) goto skip_full_check; ret = check_cfg(env); if (ret < 0) goto skip_full_check; env->allow_ptr_leaks = capable(CAP_SYS_ADMIN); ret = do_check(env);
这个函数会对opcode 0x18做一些特殊的处理
// https://elixir.bootlin.com/linux/v4.4.33/source/kernel/bpf/verifier.c#L2241 ret = replace_map_fd_with_map_ptr(env); if (ret < 0) goto skip_full_check; env->explored_states = kcalloc(env->prog->len, sizeof(struct verifier_state_list *), GFP_USER); ret = -ENOMEM; if (!env->explored_states) goto skip_full_check; ret = check_cfg(env); if (ret < 0) goto skip_full_check; env->allow_ptr_leaks = capable(CAP_SYS_ADMIN); ret = do_check(env);
这个函数会对opcode 0x18做一些特殊的处理
//https://elixir.bootlin.com/linux/v4.4.33/source/kernel/bpf/verifier.c#L2021 /* store map pointer inside BPF_LD_IMM64 instruction */ insn[0].imm = (u32) (unsigned long) map; insn[1].imm = ((u64) (unsigned long) map) >> 32;
之前由bpf_create_map所创建的bpf_map会被拆分成2个32bit数,并被load进内存中。
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
赞赏
看原图
赞赏
雪币:
留言: