CVE-2023-31436 Linux 内核数组越界漏洞分析与利用
字数 1137 2025-08-18 11:36:36
CVE-2023-31436 Linux内核数组越界漏洞分析与利用教学文档
1. 漏洞概述
CVE-2023-31436是Linux内核网络调度器QFQ(Quick Fair Queueing)中的一个数组越界漏洞,存在于net/sched/sch_qfq.c文件中。该漏洞允许本地攻击者通过精心构造的网络数据包实现权限提升。
2. 漏洞分析
2.1 漏洞根源
漏洞位于qfq_change_class()函数中,当用户态没有提供TCA_QFQ_LMAX参数时,会直接使用网卡的MTU作为lmax值,且未进行适当校验:
if (tb[TCA_QFQ_LMAX]) {
lmax = nla_get_u32(tb[TCA_QFQ_LMAX]);
if (lmax < QFQ_MIN_LMAX || lmax > (1UL << QFQ_MTU_SHIFT)) {
pr_notice("qfq: invalid max length %u\n", lmax);
return -EINVAL;
}
} else
lmax = psched_mtu(qdisc_dev(sch)); // [1] 漏洞点
特别地,loopback网卡的MTU可以被设置为2^31-1,这会导致后续计算出现问题。
2.2 漏洞触发路径
qfq_change_class()中未校验的lmax被传递给qfq_init_agg()- 在
qfq_update_agg()中,使用lmax计算索引i:int i = qfq_calc_index(agg->inv_w, agg->budgetmax, q->min_slot_shift); agg->grp = &q->groups[i]; // [4] 越界访问点 q->groups数组大小仅为25(QFQ_MAX_INDEX + 1),当i超过25时会导致越界访问
3. 漏洞利用
3.1 利用原语
漏洞提供了两种利用原语:
-
qfq_slot_insert原语:
- 通过
hlist_add_head()实现越界指针写入 - 通过
__set_bit()实现越界位设置
- 通过
-
qfq_schedule_agg原语:
- 通过控制
grp->index实现__set_bit()的越界写
- 通过控制
3.2 利用策略
-
堆布局:
- 使用
dyn-kmalloc-8192堆喷qdisc_size_table对象 - 使用
kmalloc-128堆喷xdp_umem对象
- 使用
-
类型混淆:
- 通过越界写修改相邻
qdisc->filter_list指针 - 使其指向
xdp_umem对象,利用xdp_umem->addrs与tcf_proto->next重叠的特性
- 通过越界写修改相邻
-
控制流劫持:
- 用户态控制共享内存中的
next指针指向伪造的tcf_proto结构 - 通过
tp->classify函数指针实现ROP
- 用户态控制共享内存中的
3.3 关键数据结构
struct qfq_sched {
struct tcf_proto __rcu *filter_list;
struct tcf_block *block;
struct Qdisc_class_hash clhash;
u64 oldV, V;
struct qfq_aggregate *in_serv_agg;
u32 wsum;
u32 iwsum;
unsigned long bitmaps[QFQ_MAX_STATE];
struct qfq_group groups[QFQ_MAX_INDEX + 1]; // 大小25
u32 min_slot_shift;
u32 max_agg_classes;
struct hlist_head nonfull_aggs;
};
4. 补丁分析
补丁将lmax的校验移到了所有获取路径之后:
if (tb[TCA_QFQ_LMAX])
lmax = nla_get_u32(tb[TCA_QFQ_LMAX]);
else
lmax = psched_mtu(qdisc_dev(sch));
+if (lmax < QFQ_MIN_LMAX || lmax > (1UL << QFQ_MTU_SHIFT)) {
+ pr_notice("qfq: invalid max length %u\n", lmax);
+ return -EINVAL;
+}
5. 防御与缓解
- 及时更新内核补丁
- 限制非特权用户设置网络设备参数的能力
- 启用内核地址空间布局随机化(KASLR)
- 启用SMAP/SMEP保护
6. 变体分析与审计建议
- 审计所有从设备属性获取参数的代码路径
- 特别注意loopback等特殊设备的属性设置
- 检查所有数组索引计算前的边界校验
- 关注网络子系统中类似QFQ的调度器实现