资讯动态

slub check_object

发布时间:2026/10/30 2:30:50 来源:尧图企业网站定制
check_object()是 SLUB 调试一致性检查的核心函数校验单个对象的所有区域红区、poison、padding是否完好发现破坏则报告并尝试恢复。它综合调用前面讲过的多个辅助函数。一、函数签名static int check_object(struct kmem_cache *s, struct slab *slab, void *object, u8 val)参数含义s缓存slab对象所在 slab 页object要校验的对象指针val期望的 poison 值POISON_FREE或POISON_INUSE返回int1 表示对象完好0 表示发现破坏。val的含义val由调用者传入表示该对象当前应处于什么状态POISON_FREE0x6b对象空闲应填0x6b。POISON_INUSE0x5a对象已分配使用中应填0x5a。调用者根据对象是否在 freelist 上判断val test_bit(index, object_map) ? POISON_INUSE : POISON_FREE;二、典型实现static int check_object(struct kmem_cache *s, struct slab *slab, void *object, u8 val) { u8 *p object; u8 *endobject object s-object_size; if (s-flags SLAB_RED_ZONE) { // 左红区 if (!check_bytes_and_report(s, slab, object, Left Redzone, object - s-red_left_pad, val, s-red_left_pad, true)) return 0; // 右红区 if (!check_bytes_and_report(s, slab, object, Right Redzone, endobject, val, s-inuse - s-object_size, true)) return 0; } else { // 未开红区对象首尾的 padding 也应检查 if ((unsigned long *)object ! slab-freelist !check_bytes_and_report(s, slab, object, Object head, object, val, sizeof(void *), true)) return 0; } if (s-flags SLAB_POISON) { // 对象数据区后的 poison if (!check_bytes_and_report(s, slab, object, Poison, p s-inuse, val, s-size - s-inuse, true)) return 0; } // 对象内部 padding if (!check_pad_bytes(s, slab, p)) return 0; return 1; }逻辑顺序红区检查若SLAB_RED_ZONE左红区object - red_left_pad到object期望val。右红区endobject到inuse期望val。对象头检查无红区时对象开头sizeof(void *)字节排除 freelist 头对象。poison 检查若SLAB_POISONp inuse到s-size期望val。padding 检查check_pad_bytes()校验元数据后到槽位结束的填充。全部通过返回 1任一失败返回 0。三、各部分解析1. 左红区check_bytes_and_report(s, slab, object, Left Redzone, object - s-red_left_pad, val, s-red_left_pad, true)起点object - red_left_pad长度red_left_pad。期望值val对象状态对应的 poison。左红区被越界写破坏时这里会检测到。2. 右红区check_bytes_and_report(s, slab, object, Right Redzone, endobject, val, s-inuse - s-object_size, true)起点object object_size长度inuse - object_size。右红区被越界写破坏时检测到。3. 无红区时的对象头if ((unsigned long *)object ! slab-freelist !check_bytes_and_report(s, slab, object, Object head, object, val, sizeof(void *), true))无红区时对象开头可能被 freelist 复用为下一个指针。若object正是slab-freelist头其开头是 freepointer不是 poison跳过检查。否则检查对象开头sizeof(void *)字节是否为val。4. poison 区check_bytes_and_report(s, slab, object, Poison, p s-inuse, val, s-size - s-inuse, true)对象有效数据后到槽位结束期望val。检测对象数据区是否被越界写、是否被释放后改写。5. paddingif (!check_pad_bytes(s, slab, p)) return 0;委托check_pad_bytes()校验元数据track、orig_size 等后的填充区。与上面几个check_bytes_and_report互补覆盖元数据之后的空间。四、返回值与调用者的处理返回含义调用者动作1对象完好继续校验其他对象0发现破坏已报告恢复计入错误可能影响 slab 状态判断validate_slab()里遍历所有对象for_each_object(p, s, addr, slab-objects) { u8 val test_bit(__obj_to_index(s, slab, p), map) ? POISON_INUSE : POISON_FREE; if (!check_object(s, slab, p, val)) return 0; // 该 slab 校验失败 }五、与相关函数的关系check_object() ├─ check_bytes_and_report() // 红区、poison、对象头 │ ├─ memchr_inv() │ ├─ slab_bug() │ ├─ print_trailer() │ └─ restore_bytes() │ └─ check_pad_bytes() // 对象内部 padding └─ check_bytes_and_report()函数检查区域期望值check_bytes_and_report左红区对象前valcheck_bytes_and_report右红区对象后valcheck_bytes_and_report对象头对象开头valcheck_bytes_and_reportpoison数据区后valcheck_pad_bytes元数据后POISON_INUSE六、val与对象状态check_object()的关键在于val的正确选择对象在 freelist 上空闲val POISON_FREE期望空闲区域填0x6b。对象已分配使用中val POISON_INUSE期望使用区域填0x5a。如果期望值与实际不符说明空闲对象被改写 → use-after-free。已分配对象的 poison 被覆盖 → 未初始化使用或越界写。红区被破坏 → 越界写。七、与前面知识的呼应前面讲过这里体现check_bytes_and_report()核心校验子函数check_pad_bytes()对象内部 padding 检查restore_bytes()破坏恢复print_trailer()现场打印SLAB_RED_ZONE/SLAB_POISON控制检查哪些区域red_left_pad/inuse/size区域边界计算POISON_FREE/POISON_INUSEval取值object_map/__obj_to_index判断对象是否已分配决定valfor_each_object()遍历对象调用check_object八、一句话总结check_object(s, slab, object, val)校验单个对象的左红区、右红区、对象头、poison 区、内部 padding是否都等于期望的val空闲POISON_FREE/ 使用POISON_INUSE逐段调用check_bytes_and_report()和check_pad_bytes()发现破坏就报告、打印现场并恢复。返回 1 表示对象完好0 表示发现并修复了破坏。它是validate_slab()的核心子函数是 SLUB 调试一致性检查的落地点。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑