
slab_pad_check()是 SLUB 調(diào)試中用于校驗(yàn)整個(gè) slab 頁尾部填充區(qū)的函數(shù)。與上一問的check_pad_bytes()校驗(yàn)單個(gè)對(duì)象內(nèi)部的 padding不同它檢查的是最后一個(gè)對(duì)象之后、到 slab 頁結(jié)束那段空間。一、函數(shù)簽名static pad_check_attributes void slab_pad_check(struct kmem_cache *s, struct slab *slab)項(xiàng)含義pad_check_attributes編譯器屬性避免 sanitizer 誤報(bào)同check_bytes_and_reports緩存slab要檢查的 slab 頁無返回值。二、典型實(shí)現(xiàn)static pad_check_attributes void slab_pad_check(struct kmem_cache *s, struct slab *slab) { u8 *end; if (!(s-flags SLAB_POISON)) return; end slab_address(slab) (PAGE_SIZE oo_order(s-oo)); end - sizeof(void *); // 末尾可能殘留 freepointer 空間 ... }核心思路門控未開SLAB_POISON直接返回。算出 slab 頁末尾地址slab_address(slab)slab 頁起始。PAGE_SIZE oo_order(s-oo)slab 總字節(jié)數(shù)2^order個(gè)頁。相加得到 slab 頁結(jié)束地址。計(jì)算最后一個(gè)對(duì)象的結(jié)束位置slab_address objects * s-size。檢查兩者之間的空隙這段是 slab 頁尾部 padding正常應(yīng)填POISON_FREE。發(fā)現(xiàn)異常則報(bào)告 恢復(fù)用slab_err()/restore_bytes()。三、與check_pad_bytes()的區(qū)別函數(shù)檢查范圍期望值觸發(fā)條件check_pad_bytes()單個(gè)對(duì)象內(nèi)部元數(shù)據(jù)后到對(duì)象槽位結(jié)束POISON_INUSESLAB_POISONslab_pad_check()整個(gè) slab 頁尾部最后一個(gè)對(duì)象后到頁結(jié)束POISON_FREESLAB_POISONslab 頁布局 -------------------------------- ... -------------------------------- | 對(duì)象 0 | 對(duì)象 1 | | 對(duì)象 N-1 | 頁尾 padding | -------------------------------- ... -------------------------------- ^ ^ ^ slab_address objects*size 頁結(jié)束 └── slab_pad_check 檢查 ──┘check_pad_bytes()檢查每個(gè)對(duì)象槽位內(nèi)部的填充用戶數(shù)據(jù)后到s-size。slab_pad_check()檢查整個(gè) slab 頁最后一個(gè)對(duì)象之后到頁結(jié)束的填充。四、為什么需要檢查 slab 頁尾slab 頁大小是2^order個(gè)頁所有對(duì)象按s-size排列后剩余空間就是頁尾 padding。這段空間正常填POISON_FREE。如果被越界寫破壞如某對(duì)象寫超出自身槽位、freelist 操作越界這里會(huì)留下痕跡。檢查它能發(fā)現(xiàn)跨對(duì)象、跨槽位的越界寫是對(duì)象內(nèi)部 padding 檢查的補(bǔ)充。五、典型實(shí)現(xiàn)細(xì)節(jié)更完整的實(shí)現(xiàn)可能static pad_check_attributes void slab_pad_check(struct kmem_cache *s, struct slab *slab) { u8 *start; u8 *end; u8 *p; unsigned int length; if (!(s-flags SLAB_POISON)) return; start slab_address(slab); end start (PAGE_SIZE oo_order(s-oo)); // 最后一個(gè)對(duì)象的結(jié)束位置 p start slab-objects * s-size; length end - p; if (!length) return; check_bytes_and_report(s, slab, p, Slab tail padding, p, POISON_FREE, length, false); }start/endslab 頁范圍。p start objects * s-size所有對(duì)象結(jié)束位置。length end - p頁尾 padding 長度。交給check_bytes_and_report()檢查POISON_FREE發(fā)現(xiàn)破壞則報(bào)告 restore_bytes()恢復(fù)。slab_obj_print false頁尾 padding 出錯(cuò)時(shí)只需 slab 級(jí)信息不用打印整個(gè)對(duì)象現(xiàn)場。六、調(diào)用時(shí)機(jī)slab_pad_check()通常在slab 頁級(jí)一致性校驗(yàn)里調(diào)用static int validate_slab(struct kmem_cache *s, struct slab *slab, ...) { ... slab_pad_check(s, slab); ... }或check_slab()里static int check_slab(struct kmem_cache *s, struct slab *slab) { ... slab_pad_check(s, slab); ... }它在對(duì)象級(jí)校驗(yàn)check_object→check_pad_bytes之外提供頁級(jí)的填充完整性檢查。七、與前面知識(shí)的呼應(yīng)前面講過這里體現(xiàn)check_bytes_and_report()slab_pad_check底層調(diào)用的校驗(yàn)函數(shù)check_pad_bytes()對(duì)象內(nèi)部 padding 檢查與本函數(shù)互補(bǔ)restore_bytes()發(fā)現(xiàn)破壞后恢復(fù)SLAB_POISON門控條件oo_order(s-oo)算 slab 頁大小slab_address()取 slab 頁起始地址slab-objects/s-size算對(duì)象區(qū)結(jié)束位置POISON_FREE頁尾 padding 期望值pad_check_attributes避免 sanitizer 誤報(bào)八、一句話總結(jié)slab_pad_check(s, slab)在開啟SLAB_POISON時(shí)檢查 slab 頁中最后一個(gè)對(duì)象之后到頁結(jié)束的尾部填充區(qū)是否仍為POISON_FREE發(fā)現(xiàn)破壞則報(bào)告并恢復(fù)。它與check_pad_bytes()對(duì)象內(nèi)部 padding互補(bǔ)共同覆蓋 slab 頁內(nèi)所有“無用空間”用于檢測越界寫。