前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >CVE-2022-23222:Linux 内核 eBPF 本地权限提升

CVE-2022-23222:Linux 内核 eBPF 本地权限提升

作者头像
Khan安全团队
发布2022-07-13 08:36:14
7670
发布2022-07-13 08:36:14
举报
文章被收录于专栏:Khan安全团队

https://github.com/tr3ee/CVE-2022-23222 近期在对Linux eBPF进行代码审计的过程中,发现了一枚权限提升漏洞CVE-2022-23222。 此漏洞影响Linux Kernel 5.8 - 5.16,并在5.10.92 / 5.15.15 / 5.16.1中修复。 完整利用代码详见:https://github.com/tr3ee/CVE-2022-23222 ----[ 1.1 - eBPF verifer 我们在写eBPF程序时,会发现调用bpf_map_lookup_elem()返回的结果,一定要判断是否为NULL,否则就会被拒绝加载。因为,bpf_map_lookup_elem()运行结果的结果,可能是有效的指针,但也可能返回NULL来表示没有查 找到与key相关的值。 在eBPF中有很多类似的用法,那么eBPF verifier是如何跟踪这些值的类型呢? * bpf.h *

代码语言:javascript
复制
/* types of values stored in eBPF registers */
/* Pointer types represent:
 * pointer
 * pointer + imm
 * pointer + (u16) var
 * pointer + (u16) var + imm
 * if (range > 0) then [ptr, ptr + range - off) is safe to access
 * if (id > 0) means that some 'var' was added
 * if (off > 0) means that 'imm' was added
 */
enum bpf_reg_type {
    NOT_INIT = 0,         /* nothing was written into register */
    SCALAR_VALUE,         /* reg doesn't contain a valid pointer */
    PTR_TO_CTX,           /* reg points to bpf_context */
    CONST_PTR_TO_MAP,     /* reg points to struct bpf_map */
    PTR_TO_MAP_VALUE,     /* reg points to map element value */
    PTR_TO_MAP_VALUE_OR_NULL,  /* points to map elem value or NULL */
    PTR_TO_STACK,         /* reg == frame_pointer + offset */
    PTR_TO_PACKET_META,   /* skb->data - meta_len */
    PTR_TO_PACKET,        /* reg points to skb->data */
    PTR_TO_PACKET_END,    /* skb->data + headlen */
    PTR_TO_FLOW_KEYS,     /* reg points to bpf_flow_keys */
    PTR_TO_SOCKET,        /* reg points to struct bpf_sock */
    PTR_TO_SOCKET_OR_NULL,      /* reg points to struct bpf_sock or NULL */
    PTR_TO_SOCK_COMMON,   /* reg points to sock_common */
    PTR_TO_SOCK_COMMON_OR_NULL, /* reg points to sock_common or NULL */
    PTR_TO_TCP_SOCK,      /* reg points to struct tcp_sock */
    PTR_TO_TCP_SOCK_OR_NULL,    /* reg points to struct tcp_sock or NULL */
    PTR_TO_TP_BUFFER,     /* reg points to a writable raw tp's buffer */
    PTR_TO_XDP_SOCK,      /* reg points to struct xdp_sock */
    /* PTR_TO_BTF_ID points to a kernel struct that does not need
     * to be null checked by the BPF program. This does not imply the
     * pointer is _not_ null and in practice this can easily be a null
     * pointer when reading pointer chains. The assumption is program
     * context will handle null pointer dereference typically via fault
     * handling. The verifier must keep this in mind and can make no
     * assumptions about null or non-null when doing branch analysis.
     * Further, when passed into helpers the helpers can not, without
     * additional context, assume the value is non-null.
     */
    PTR_TO_BTF_ID,
    /* PTR_TO_BTF_ID_OR_NULL points to a kernel struct that has not
     * been checked for null. Used primarily to inform the verifier
     * an explicit null check is required for this struct.
     */
    PTR_TO_BTF_ID_OR_NULL,
    PTR_TO_MEM,           /* reg points to valid memory region */
    PTR_TO_MEM_OR_NULL,   /* reg points to valid memory region or NULL */
    PTR_TO_RDONLY_BUF,    /* reg points to a readonly buffer */
    PTR_TO_RDONLY_BUF_OR_NULL,  /* reg points to a readonly buffer or NULL */
    PTR_TO_RDWR_BUF,      /* reg points to a read/write buffer */
    PTR_TO_RDWR_BUF_OR_NULL,    /* reg points to a read/write buffer or NULL */
    PTR_TO_PERCPU_BTF_ID,       /* reg points to a percpu kernel variable */
};

上面是eBPF中寄存器的完整类型列表,可以知道它通过`*_OR_NULL`类型来表示一个未知的指针类型。当寄存器 的类型是`*_OR_NULL`时,它能做的操作是很有限的,一般只能进行NULL比较或者作为参数调用辅助函数。 一个类型为`*_OR_NULL`的寄存器做完!=NULL的比较后,才可能变为`PTR_TO_*`类型,或者`SCALAR_VALUE`也就是数值0。 ----[ 1.2 - 漏洞分析 * C *

代码语言:javascript
复制
/* Handles arithmetic on a pointer and a scalar: computes new min/max and var_off.
 * Caller should also handle BPF_MOV case separately.
 * If we return -EACCES, caller may want to try again treating pointer as a
 * scalar.  So we only emit a diagnostic if !env->allow_ptr_leaks.
 */
static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
                   struct bpf_insn *insn,
                   const struct bpf_reg_state *ptr_reg,
                   const struct bpf_reg_state *off_reg)
{
...
    switch (ptr_reg->type) {
    case PTR_TO_MAP_VALUE_OR_NULL:
        verbose(env, "R%d pointer arithmetic on %s prohibited, null-check it first\n",
            dst, reg_type_str[ptr_reg->type]);
        return -EACCES;
    case CONST_PTR_TO_MAP:
        /* smin_val represents the known value */
        if (known && smin_val == 0 && opcode == BPF_ADD)
            break;
        fallthrough;
    case PTR_TO_PACKET_END:
    case PTR_TO_SOCKET:
    case PTR_TO_SOCKET_OR_NULL:
    case PTR_TO_SOCK_COMMON:
    case PTR_TO_SOCK_COMMON_OR_NULL:
    case PTR_TO_TCP_SOCK:
    case PTR_TO_TCP_SOCK_OR_NULL:
    case PTR_TO_XDP_SOCK:
        verbose(env, "R%d pointer arithmetic on %s prohibited\n",
            dst, reg_type_str[ptr_reg->type]);
        return -EACCES;
    default:
        break;
    }
...
    return 0;
}

上面的代码中adjust_ptr_min_max_vals()是eBPF verifier用于检验指针加减运算的函数。其中的switch分支用于过滤不支持加减运算的指针类型,比如各种OR_NULL类型。但是这个switch分支却少了很多类型的判断,比如`PTR_TO_MEM_OR_NULL`, `PTR_TO_RDONLY_BUF_OR_NULL`,`PTR_TO_RDWR_BUF_OR_NULL`。 这意味着,我们可以对一些OR_NULL类型做加减运算! 参考资料

代码语言:javascript
复制
[1] Advisory: https://www.openwall.com/lists/oss-security/2022/01/13/1
[2] Exploit Overview: https://www.openwall.com/lists/oss-security/2022/01/18/2
[3] Patch: []()
[4] Source: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/kernel/bpf/ver
ifier.c?h=v5.10.83
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-06-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Khan安全攻防实验室 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
代码审计
代码审计(Code Audit,CA)提供通过自动化分析工具和人工审查的组合审计方式,对程序源代码逐条进行检查、分析,发现其中的错误信息、安全隐患和规范性缺陷问题,以及由这些问题引发的安全漏洞,提供代码修订措施和建议。支持脚本类语言源码以及有内存控制类源码。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档