<kernel v5.0>
슬랩 object 디버깅 (slub)
SLAB_POISON
Slub 디버깅을 위해 SLAB_POISON을 사용하는 경우 object의 할당과 해제 시에 특별한 데이터를 object 데이터 영역에 기록하고 이를 통해서 다음의 에러를 찾아낸다.
- Object already free – 이중 해제
- 해제를 하게되면 object에는 poison free 데이터(0x6b가 연속되고 마지막에 0xa5)가 기록되는데 만일 해제된 object를 다시 한 번 해제하는 순간 poison free 데이터를 발견하면 반복하여 해제하려고 한다는 것을 알게되어 에러를 출력한다.
- Poison overwritten – 해제 후 사용
- 엄밀히 이 free object를 침해하여 사용하였을 때에는 체크를 하지 못한다. 다만 다시 object를 할당할 때 free 라고 생각했던 object의 poison free 데이터가 파괴된 것을 보고 누군가가 침해를 한 것으로 판단하여 에러를 출력한다.
커널 파라미터 설정
- “slub_debug=FP[,<슬랩명>]”
다음 그림은 슬랩 object에서의 poison 값의 변화 추이를 보여준다.
SLAB_RED_ZONE
Slab(Slub) 디버깅을 위해 RED_ZONE을 사용하는 경우 object의 할당과 해제 시에 특별한 데이터를 red zone 영역에 기록하고 이를 통해서 다음의 에러를 찾아낸다.
- Redzone overwritten
- object 데이터가 자신의 영역을 초과하여 red zone 영역을 침범한 경우 object를 할당 또는 해지하는 순간 알아낸 후 에러를 출력한다.
커널 파라미터 설정
- “slub_debug=FZ[,<슬랩명>]”
다음 그림은 poison 및 red-zone에 대한 값의 처리 과정을 보여준다.
슬랩 페이지 및 슬랩 object 구성 체크
슬랩 페이지의 구성 값, 패딩 그리고 슬랩 object의 FP(Freelist) 등에 문제가 있는지 체크하여 다음과 같은 에러를 보고한다.
- Object padding overwritten
- 처음 새 슬랩 페이지는 전체 영역에 대해 슬랩 object를 초기화하기 전에 poison inuse 데이터(0x5a) 초기 값으로 기록된다.
- 슬랩 할당 또는 해제 시 패딩 공간에 기록된 0x5a 값을 확인하여 변경된 것을 알게되면 에러를 출력한다.
- Alignment padding
- red-zone을 사용하지 않을 때 s->object_size와 s->inuse가 다르면 에러를 출력한다.
- Invalid object pointer 0x%p
- 포인터 주소가 슬랩 페이지 범위를 벗어나는 경우 에러를 출력한다.
- Freepointer corrupt
- 슬랩 페이지 범위를 벗어난 FP(Free Pointer) 주소를 사용한 경우 에러를 출력한다.
- Freechain corrupt
- FP 값이 슬랩 페이지 범위를 벗어나는 경우 에러를 출력한다.
- Wrong number of objects. Found %d but should be %d
- 슬랩 페이지에 들어갈 수 있는 최대 수가 잘못되어 에러를 출력한다.
- Wrong object count. Counter is %d but counted were %d
- 슬랩 페이지의 사용 중인 object 수가 잘못된 경우 에러를 출력한다.
- 정상인 경우 p->objects – free object 수 = p->inuse 이다.
- Not a valid slab page
- 슬랩 페이지가 아닌 경우이다.
- objects %u > max %u
- 슬랩 페이지에서 사용 중인 object 수가 들어갈 수 있는 최대 슬랩 object 수를 초과한 값을 사용하여 에러를 출력한다.
- inuse %u > max %u
- 슬랩 페이지에서 사용(inuse) 중인 object 수가 최대 슬랩 object 수를 초과한 값을 사용한다.
- Padding overwritten. 0x%p-0x%p
- 슬랩 페이지 뒷 부분 사용하지 않는 공간의 패딩 값이 변경되었다.
SLAB_STORE_USER
Slab(Slub) 디버깅을 위해 SLAB_STORE_USER를 사용하는 경우 object를 할당과 해제를 한 pid, cpu, 호출한 주소(함수 추적). 시각 등을 추적할 수 있다. 만일 CONFIG_STACKTRACE 커널 옵션을 추가 사용하는 경우 16개까지의 function track back을 할 수 있다.
커널 파라미터 설정
- “slub_debug=FU[,<슬랩명>]”
alloc 유저 트래킹
다음은 유저 트래킹을 허용한 foo 슬랩 캐시에서 두 번 할당(alloc)된 내역을 보여준다.
$ cat /sys/kernel/slab/foo/alloc_calls 1 0xffff000008b8a068 age=2609 pid=3481 1 0xffff000008b8a078 age=2596 pid=3481
free 유저 트래킹
다음은 유저 트래킹을 허용한 foo 슬랩 캐시에서 한 번 할당 해제(free)된 내역을 보여준다.
$ cat /sys/kernel/slab/foo/free_calls 2 <not-available> age=4295439025 pid=0
TRACE
슬랩(Slub) 디버깅을 위해 SLAB_TRACE를 사용하는 경우 object의 할당과 해제 시 해당 object의 주소, inuse 값, FP(Free pointer) 및 object의 16진수 덤프를 수행하여 추적할 수 있다.
커널 파라미터 설정
-
- “slub_debug=FT[,<슬랩명>]”
[ 242.214756] TRACE jake free 0xffff800039509d20 inuse=2 fp=0xffff800039508190 [ 242.217524] Object ffff800039509d20: 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD [ 242.221762] Object ffff800039509d30: 44 44 44 44 44 44 44 44 44 44 44 44 44 44 DDDDDDDDDDDDDD
슬랩 할당 관련 플래그들
다음은 디버그와 관련된 플래그들이다.
- SLAB_CONSISTENCY_CHECKS
- 슬랩 object의 alloc 및 free 시마다 체크를 수행하게 한다. (expensive)
- SLAB_RED_ZONE
- red zone 영역을 사용한 디버깅
- SLAB_POISON
- object 영역에 poison 데이터를 기록하여 디버깅
- SLAB_STORE_USER
- 디버깅을 위해 last owner 관련 정보를 저장한다.
- SLAB_TRACE
- 디버깅을 위해 트레이스를 지원한다.
- SLAB_DEBUG_OBJECTS
- 슬랩 object의 free 시 디버깅을 하지 않게 한다.
- SLAB_KASAN
- 슬랩 디버깅에 런타임 디버깅을 지원한다.
- 메모리 소모 및 성능이 크게 떨어지지만 슬랩 object 침해를 즉각 감지한다.
- SLAB_NOLEAKTRACE
- kmemleak 트레이스를 하지 않게 한다.
- SLAB_FAILSLAB
- 슬랩 object 할당 시 Fault injection으로 에러를 발생시킨다.
- SLAB_PANIC
- 슬랩 object 에러 시 panic()을 호출한다.
슬랩(slub) 페이지 할당 시 object의 디버그 초기화
setup_object()
mm/slub.c
static void setup_object(struct kmem_cache *s, struct page *page, void *object) { setup_object_debug(s, page, object); object = kasan_init_slab_obj(s, object); if (unlikely(s->ctor)) { kasan_unpoison_object_data(s, object); s->ctor(object); kasan_poison_object_data(s, object); } }
커널 옵션에 의한 디버깅과 런타임 메모리 디버깅을 위해 슬랩(Slub) object를 초기화한다.
- 코드 라인 4에서 슬랩 디버깅을 위해 POISON, RED ZONE, 트래킹 데이터를 설치한다.
- 코드 라인 5에서 런타임 메모리 디버거를 위해 shadow 영역을 0으로 초기화한다.
- 코드 라인 6~10에서 적은 확률로 생성자가 준비된 슬랩 캐시인 경우 슬랩 object 생성자를 동작시킨다.
setup_object_debug()
mm/slub.c
/* Object debug checks for alloc/free paths */ static void setup_object_debug(struct kmem_cache *s, struct page *page, void *object) { if (!(s->flags & (SLAB_STORE_USER|SLAB_RED_ZONE|__OBJECT_POISON))) return; init_object(s, object, SLUB_RED_INACTIVE); init_tracking(s, object); }
슬랩(slub) 디버깅을 위해 POISON, RED ZONE, 트래킹 데이터를 설치한다.
- 코드 라인 5~6에서 슬랩(slub) 디버깅 플래그가 없는 경우 함수를 빠져나간다.
- 코드 라인 8에서 POISON 데이터와 RED ZONE 데이터를 설치한다.
- 코드 라인 9에서 alloc/free 유저 트래킹용 데이터를 초기화한다.
init_object()
mm/slub.c
static void init_object(struct kmem_cache *s, void *object, u8 val) { u8 *p = object; if (s->flags & SLAB_RED_ZONE) memset(p - s->red_left_pad, val, s->red_left_pad); if (s->flags & __OBJECT_POISON) { memset(p, POISON_FREE, s->object_size - 1); p[s->object_size - 1] = POISON_END; } if (s->flags & SLAB_RED_ZONE) memset(p + s->object_size, val, s->inuse - s->object_size); }
슬랩(Slub) object를 초기화할 때 poison_free(0x6b) 및 red-zone 용 @val값을 지정한다.
- 코드 라인 4~5에서 좌측 red-zone 영역에 @val 값으로 채운다.
- 코드 라인 6~9에서 object 내에 poison_free(0x6b) 값으로 채운다.
- 코드 라인 11~12에서 object 우측의 red-zone 영역에 @val 값으로 채운다.
init_tracking()
mm/slub.c
static void init_tracking(struct kmem_cache *s, void *object) { if (!(s->flags & SLAB_STORE_USER)) return; set_track(s, object, TRACK_FREE, 0UL); set_track(s, object, TRACK_ALLOC, 0UL); }
alloc/free 유저 트래킹을 위해 TRACK_FREE 및 TRACK_ALLOC 등 2개 영역의 데이터를 0으로 초기화한다.
set_track()
mm/slub.c
static void set_track(struct kmem_cache *s, void *object, enum track_item alloc, unsigned long addr) { struct track *p = get_track(s, object, alloc); if (addr) { #ifdef CONFIG_STACKTRACE struct stack_trace trace; int i; trace.nr_entries = 0; trace.max_entries = TRACK_ADDRS_COUNT; trace.entries = p->addrs; trace.skip = 3; metadata_access_enable(); save_stack_trace(&trace); metadata_access_disable(); /* See rant in lockdep.c */ if (trace.nr_entries != 0 && trace.entries[trace.nr_entries - 1] == ULONG_MAX) trace.nr_entries--; for (i = trace.nr_entries; i < TRACK_ADDRS_COUNT; i++) p->addrs[i] = 0; #endif p->addr = addr; p->cpu = smp_processor_id(); p->pid = current->pid; p->when = jiffies; } else memset(p, 0, sizeof(struct track)); }
트래킹을 하기 위한 호출 주소, cpu, pid, 시각에 대한 데이터를 저장한다.
- CONFIG_STACKTRACE 커널 옵션을 사용하는 경우 slub 에서도 16개까지의 함수 역추적을 할 수 있도록 한다.
슬랩 object 할당 시 디버그 체크
슬랩 object가 할당될 때 호출되어 체크한다.
alloc_debug_processing()
mm/slub.c
static noinline int alloc_debug_processing(struct kmem_cache *s, struct page *page, void *object, unsigned long addr) { if (s->flags & SLAB_CONSISTENCY_CHECKS) { if (!alloc_consistency_checks(s, page, object, addr)) goto bad; } /* Success perform special debug activities for allocs */ if (s->flags & SLAB_STORE_USER) set_track(s, object, TRACK_ALLOC, addr); trace(s, page, object, 1); init_object(s, object, SLUB_RED_ACTIVE); return 1; bad: if (PageSlab(page)) { /* * If this is a slab page then lets do the best we can * to avoid issues in the future. Marking all objects * as used avoids touching the remaining objects. */ slab_fix(s, "Marking all objects used"); page->inuse = page->objects; page->freelist = NULL; } return 0; }
슬랩 object 할당 시 디버그 체크를 수행한다. 성공 시 1을 반환한다.
- 코드 라인 5~8에서 “slub_debug=F,<슬랩캐시명>”으로 지정된 슬랩 캐시의 sanity 체크를 수행한다.
- 코드 라인 11~12에서 “slub_debug=FU,<슬랩캐시명>”으로 지정된 슬랩 캐시의 object에 대한 할당 요청 owner 함수를 기록한다.
- 코드 라인 13에서 “slub_debug=FT,<슬랩캐시명>”으로 지정된 슬랩 캐시의 트레이스를 수행한다.
- “TRACE <슬랩명> alloc <object주소> inuse=xx fp=<FP 주소>”가 출력되고 “Object”의 16진수 값들이 덤프된다.
- 코드 라인 14에서 슬랩(Slub) object를 초기화하면서 poison_free(0x6b) 및 red-zone 용 SLUB_RED_ACTIVE(0xcc)값을 지정한다.
- 코드 라인 15에서 정상 값인 1을 반환한다.
- 코드 라인 17에서 sanity 체크에서 실패한 경우 진입되는 bad: 레이블이다.
- 코드 라인 18~28에서 해당 슬랩 페이지의 모든 free object들의 사용을 중단 시키기 위해 모두 사용 중으로 마크하고 실패 0을 반환한다.
슬랩 object 할당 시 consistency 체크
alloc_consistency_checks()
mm/slub.c
static inline int alloc_consistency_checks(struct kmem_cache *s, struct page *page, void *object, unsigned long addr) { if (!check_slab(s, page)) return 0; if (!check_valid_pointer(s, page, object)) { object_err(s, page, object, "Freelist Pointer check fails"); return 0; } if (!check_object(s, page, object, SLUB_RED_INACTIVE)) return 0; return 1; }
@object 할당 전에 consistency 체크를 수행한다. 정상일 때 1을 반환한다.
- 코드 라인 5~6에서 슬랩 페이지의 전체 object 수 및 사용 중인 object 수를 체크한다.
- 코드 라인 8~11에서 @object 가상 주소가 슬랩 페이지 범위내에 포함되는지 여부를 조사한다.
- 코드 라인 13~14에서 슬랩 object를 할당하기 전에 poison 값(0x6b) 및 red-zone 값(SLUB_RED_INACTIVE-0xbb)들이 잘 기록되어 있는지 체크한다.
- 코드 라인 16에서 슬랩 object가 정상인 경우이며 1을 반환한다.
슬랩 object 할당 해제 시 디버그 체크
슬랩 object의 할당 해제 시 호출되어 체크한다.
free_debug_processing()
mm/slub.c
/* Supports checking bulk free of a constructed freelist */ static noinline int free_debug_processing( struct kmem_cache *s, struct page *page, void *head, void *tail, int bulk_cnt, unsigned long addr) { struct kmem_cache_node *n = get_node(s, page_to_nid(page)); void *object = head; int cnt = 0; unsigned long uninitialized_var(flags); int ret = 0; spin_lock_irqsave(&n->list_lock, flags); slab_lock(page); if (s->flags & SLAB_CONSISTENCY_CHECKS) { if (!check_slab(s, page)) goto out; } next_object: cnt++; if (s->flags & SLAB_CONSISTENCY_CHECKS) { if (!free_consistency_checks(s, page, object, addr)) goto out; } if (s->flags & SLAB_STORE_USER) set_track(s, object, TRACK_FREE, addr); trace(s, page, object, 0); /* Freepointer not overwritten by init_object(), SLAB_POISON moved it */ init_object(s, object, SLUB_RED_INACTIVE); /* Reached end of constructed freelist yet? */ if (object != tail) { object = get_freepointer(s, object); goto next_object; } ret = 1; out: if (cnt != bulk_cnt) slab_err(s, page, "Bulk freelist count(%d) invalid(%d)\n", bulk_cnt, cnt); slab_unlock(page); spin_unlock_irqrestore(&n->list_lock, flags); if (!ret) slab_fix(s, "Object at 0x%p not freed", object); return ret; }
슬랩 object 할당 해제시 디버그 체크를 수행한다. 성공 시 1을 반환한다.
- 코드 라인 16~19에서 “slub_debug=F,<슬랩캐시명>”으로 지정된 슬랩 캐시의 해당 슬랩 페이지에 대한 sanity 체크를 수행한다.
- 코드 라인 21~22에서 전체 free object를 체크하기 위해 반복되는 next_object: 레이블이다.
- 코드 라인 24~27에서 “slub_debug=F,<슬랩캐시명>”으로 지정된 슬랩 캐시의 순회 중인 object에 대한 alloc sanity 체크를 수행한다.
- 코드 라인 29~30에서 “slub_debug=FU,<슬랩캐시명>”으로 지정된 슬랩 캐시의 object에 대한 해제 요청 owner 함수를 기록한다.
- 코드 라인 31에서 “slub_debug=FT,<슬랩캐시명>”으로 지정된 슬랩 캐시의 트레이스를 수행한다.
- “TRACE <슬랩명> free <object주소> inuse=xx fp=<FP 주소>”가 출력되고 “Object”의 16진수 값들이 덤프된다.
- 코드 라인 33에서 슬랩(Slub) object를 초기화하면서 poison_free(0x6b) 및 red-zone 용 SLUB_RED_INACTIVE(0xbb)값을 지정한다.
- 코드 라인 36~39에서 @tail object까지 순회를 위해 next_object: 레이블로 이동한다.
- 코드 라인 40에서 완료된 경우 정상 값인 1을 반환하도록 준비한다.
- 코드 라인 42에서 함수를 빠져나갈때 진행될 out: 레이블이다.
- 코드 라인 43~45에서 @head ~ @tail 까지의 object 수와 @bulk_cnt 수가 서로 다르면 에러 메시지를 출력한다.
- 코드 라인 49~50에서 에러 발견 시 해당 object가 free되지 않았다고 에러 메시지를 출력한다.
슬랩 object 할당 해제시 consistency 체크
free_consistency_checks()
mm/slub.c
static inline int free_consistency_checks(struct kmem_cache *s, struct page *page, void *object, unsigned long addr) { if (!check_valid_pointer(s, page, object)) { slab_err(s, page, "Invalid object pointer 0x%p", object); return 0; } if (on_freelist(s, page, object)) { object_err(s, page, object, "Object already free"); return 0; } if (!check_object(s, page, object, SLUB_RED_ACTIVE)) return 0; if (unlikely(s != page->slab_cache)) { if (!PageSlab(page)) { slab_err(s, page, "Attempt to free object(0x%p) outside of slab", object); } else if (!page->slab_cache) { pr_err("SLUB <none>: no slab for object 0x%p.\n", object); dump_stack(); } else object_err(s, page, object, "page slab pointer corrupt."); return 0; } return 1; }
@object 할당 해제전에 consistency 체크를 수행한다. 정상일 때 1을 반환한다.
- 코드 라인 4~7에서 @object 가상 주소가 슬랩 페이지 범위내에 포함되는지 여부를 조사한다.
- 코드 라인 9~12에서 요청한 슬랩 페이지의 freelist 체인에서 @object까지 검색하며 각 free object들의 FP(Free Pointer) 값이 유효한지 체크한다.
- 코드 라인 14~15에서 슬랩 object를 할당 해제하기 전에 red-zone 값(SLUB_RED_ACTIVE-0xcc)들이 잘 기록되어 있는지 체크한다. 또한 red-zone을 사용하지 않고 poison을 만을 사용하는 경우라면 object 다음에 위치한 패딩 위치에 poison 값(0x6b)이 잘 기록되어 있는지도 체크한다.
- 코드 라인 17~29에서 슬렙 페이지가 슬랩 캐시 @s를 가리키지 않는 경우 에러를 출력하고 0을 반환한다.
- 코드 라인 30에서 정상이므로 1을 반환한다.
공통 체크 함수
슬랩 체크
check_slab()
mm/slub.c
static int check_slab(struct kmem_cache *s, struct page *page) { int maxobj; VM_BUG_ON(!irqs_disabled()); if (!PageSlab(page)) { slab_err(s, page, "Not a valid slab page"); return 0; } maxobj = order_objects(compound_order(page), s->size); if (page->objects > maxobj) { slab_err(s, page, "objects %u > max %u", page->objects, maxobj); return 0; } if (page->inuse > page->objects) { slab_err(s, page, "inuse %u > max %u", page->inuse, page->objects); return 0; } /* Slab_pad_check fixes things up after itself */ slab_pad_check(s, page); return 1; }
슬랩 페이지의 전체 object 수 및 사용 중인 object 수를 체크한다. 또한 슬랩 페이지에서 사용하지 않는 패딩 영역을 체크하고 교정한다. 성공 시 1을 반환한다.
- 코드 라인 7~10에서 요청한 페이지가 슬랩 페이지가 아닌 경우 실패 0을 반환한다.
- 코드 라인 12~17에서 최대 object 수가 잘못 지정된 경우 에러를 출력하고 0을 반환한다.
- 코드 라인 18~22에서 사용 중인 object 수가 최대 object 수를 넘는 경우에도 에러를 출력하고 0을 반환한다.
- 코드 라인 24에서 슬랩 페이지에서 사용하지 않는 패딩 영역을 체크하여 poison 값이 잘못 기록된 부분의 에러를 출력하고 교정한다.
- 코드 라인 25에서 성공 1을 반환한다.
패드 영역 체크
slab_pad_check()
mm/slub.c
/* Check the pad bytes at the end of a slab page */ static int slab_pad_check(struct kmem_cache *s, struct page *page) { u8 *start; u8 *fault; u8 *end; u8 *pad; int length; int remainder; if (!(s->flags & SLAB_POISON)) return 1; start = page_address(page); length = PAGE_SIZE << compound_order(page); end = start + length; remainder = length % s->size; if (!remainder) return 1; pad = end - remainder; metadata_access_enable(); fault = memchr_inv(pad, POISON_INUSE, remainder); metadata_access_disable(); if (!fault) return 1; while (end > fault && end[-1] == POISON_INUSE) end--; slab_err(s, page, "Padding overwritten. 0x%p-0x%p", fault, end - 1); print_section(KERN_ERR, "Padding ", pad, remainder); restore_bytes(s, "slab padding", POISON_INUSE, fault, end); return 0; }
슬랩 페이지에서 사용하지 않는 패딩 영역을 체크한다. 성공 시 1을 반환한다.
- 코드 라인 11~12에서 poison을 사용하지 않는 경우 poison 값을 체크할 필요 없으므로 성공 1을 반환한다.
- 코드 라인 14~19에서 슬랩 페이지에서 남는 영역이 없는 경우 성공 1을 반환한다.
- 코드 라인 21~26에서 남는 패딩 영역에 POISON_INUSE(0x5a)값이 잘 기록되어 있는 경우 성공 1을 반환한다.
- 코드 라인 27~34에서 실패한 위치의 주소를 찾아 “Padding overwritten” 에러를 출력하고, 잘못된 부분의 poison 값을 다시 기록하며 실패 0을 반환한다.
Object 체크
check_object()
mm/slub.c
static int check_object(struct kmem_cache *s, struct page *page, 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, page, object, "Redzone", object - s->red_left_pad, val, s->red_left_pad)) return 0; if (!check_bytes_and_report(s, page, object, "Redzone", endobject, val, s->inuse - s->object_size)) return 0; } else { if ((s->flags & SLAB_POISON) && s->object_size < s->inuse) { check_bytes_and_report(s, page, p, "Alignment padding", endobject, POISON_INUSE, s->inuse - s->object_size); } } if (s->flags & SLAB_POISON) { if (val != SLUB_RED_ACTIVE && (s->flags & __OBJECT_POISON) && (!check_bytes_and_report(s, page, p, "Poison", p, POISON_FREE, s->object_size - 1) || !check_bytes_and_report(s, page, p, "Poison", p + s->object_size - 1, POISON_END, 1))) return 0; /* * check_pad_bytes cleans up on its own. */ check_pad_bytes(s, page, p); } if (!s->offset && val == SLUB_RED_ACTIVE) /* * Object and freepointer overlap. Cannot check * freepointer while object is allocated. */ return 1; /* Check free pointer validity */ if (!check_valid_pointer(s, page, get_freepointer(s, p))) { object_err(s, page, p, "Freepointer corrupt"); /* * No choice but to zap it and thus lose the remainder * of the free objects in this slab. May cause * another error because the object count is now wrong. */ set_freepointer(s, p, NULL); return 0; } return 1; }
슬랩 object를 할당/해제하기 전에 poison 값 및 red-zone 값들이 잘 기록되어 있는지 체크한다. 성공 시 1을 반환한다.
- 코드 라인 7~14에서 두 개의 red-zone 영역이 @val 값으로 채워져있는지 체크한다.
- 코드 라인 15~21에서 red-zone을 사용하지 않지만 poison을 사용하는 경우 object 뒤에 위치한 alignment 패딩 영역에 POISON_INUSE(0x5a) 값이 잘 기록되어 있는지 체크한다.
- 코드 라인 23~34에서 poison을 사용하는 경우 패딩 영역이 POISON_INUSE(0x5a)로 잘 기록되어 있는지 체크한다. 또한 object 할당을 위해 진입한 경우 object 영역에 POISON_FREE(0x6b) 값으로 채워져 있었는지 확인한다. 단 마지막 바이트에는 POISON_END(0xa5)가 위치하여야 한다.
- 코드 라인 36~41에서 fp 이동 사유가 없어 fp를 가리키는 offset이 0이고, 할당 해제를 위해 진입한 경우 정상 1을 반환한다.
- 코드 라인 44~53에서 다음 object를 가리키는 FP(Free Pointer) 값이 해당 슬랩 페이지의 주소 범위를 사용하는지 체크하며, 문제가 있는 경우 null 값을 기록하고, 실패 0을 반환한다.
- 코드 라인 54에서 성공 1을 반환한다.
check_pad_bytes()
mm/slub.c
/* * Object layout: * * object address * Bytes of the object to be managed. * If the freepointer may overlay the object then the free * pointer is the first word of the object. * * Poisoning uses 0x6b (POISON_FREE) and the last byte is * 0xa5 (POISON_END) * * object + s->object_size * Padding to reach word boundary. This is also used for Redzoning. * Padding is extended by another word if Redzoning is enabled and * object_size == inuse. * * We fill with 0xbb (RED_INACTIVE) for inactive objects and with * 0xcc (RED_ACTIVE) for objects in use. * * object + s->inuse * Meta data starts here. * * A. Free pointer (if we cannot overwrite object on free) * B. Tracking data for SLAB_STORE_USER * C. Padding to reach required alignment boundary or at mininum * one word if debugging is on to be able to detect writes * before the word boundary. * * Padding is done using 0x5a (POISON_INUSE) * * object + s->size * Nothing is used beyond s->size. * * If slabcaches are merged then the object_size and inuse boundaries are mostly * ignored. And therefore no slab options that rely on these boundaries * may be used with merged slabcaches. */
static int check_pad_bytes(struct kmem_cache *s, struct page *page, u8 *p) { unsigned long off = s->inuse; /* The end of info */ if (s->offset) /* Freepointer is placed after the object. */ off += sizeof(void *); if (s->flags & SLAB_STORE_USER) /* We also have user information there */ off += 2 * sizeof(struct track); off += kasan_metadata_size(s); if (size_from_object(s) == off) return 1; return check_bytes_and_report(s, page, p, "Object padding", p + off, POISON_INUSE, size_from_object(s) - off); }
object 다음에 위치한 alignment 패딩 영역의 poison 값들을 체크한다. 성공 시 1을 반환한다.
- 코드 라인 3에서 off 값은 패딩 위치를 계산하기 위해 준비하며, 먼저 object와 object에 따른 alignment 값이 포함된 s->inuse 값을 지정한다.
- 코드 라인 5~7에서 free object를 가리키는 FP(Free Pointer)의 위치 값이 주어진 경우 그 영역을 넘어선다.
- 코드 라인 9~11에서 유저 트래킹을 사용하는 경우 해당 영역을 넘어선다.
- 코드 라인 13에서 KASAN에서 사용하는 영역을 넘어선다.
- 코드 라인 15~16에서 정확히 alignment되어 최후의 패딩이 필요 없는 경우 성공 1을 반환한다.
- 코드 라인 18~19에서 마지막 alignment 패딩 영역이 POISON_INUSE(0x5a) 값으로 채워져 있는지 체크한다.
check_bytes_and_report()
mm/slub.c
static int check_bytes_and_report(struct kmem_cache *s, struct page *page, u8 *object, char *what, u8 *start, unsigned int value, unsigned int bytes) { u8 *fault; u8 *end; metadata_access_enable(); fault = memchr_inv(start, value, bytes); metadata_access_disable(); if (!fault) return 1; end = start + bytes; while (end > fault && end[-1] == value) end--; slab_bug(s, "%s overwritten", what); pr_err("INFO: 0x%p-0x%p. First byte 0x%x instead of 0x%x\n", fault, end - 1, fault[0], value); print_trailer(s, page, object); restore_bytes(s, what, value, fault, end); return 0; }
@start 주소부터 @bytes만큼 @value값이 기록되어 있는지 체크한다. 성공 시 1을 반환하고, 문제가 있는 경우 에러 메시지를 출력하고, 덤프하며 0을 반환한다. 다음과 같은 에러 명을 출력하기 위해 사용된다.
- “Object padding overwritten”
- “Redzone overwritten”
- “Alignment padding overwritten”
- “Poison overwritten”
freelist 체크
on_freelist()
mm/slub.c
/* * Determine if a certain object on a page is on the freelist. Must hold the * slab lock to guarantee that the chains are in a consistent state. */
static int on_freelist(struct kmem_cache *s, struct page *page, void *search) { int nr = 0; void *fp; void *object = NULL; int max_objects; fp = page->freelist; while (fp && nr <= page->objects) { if (fp == search) return 1; if (!check_valid_pointer(s, page, fp)) { if (object) { object_err(s, page, object, "Freechain corrupt"); set_freepointer(s, object, NULL); } else { slab_err(s, page, "Freepointer corrupt"); page->freelist = NULL; page->inuse = page->objects; slab_fix(s, "Freelist cleared"); return 0; } break; } object = fp; fp = get_freepointer(s, object); nr++; } max_objects = order_objects(compound_order(page), s->size); if (max_objects > MAX_OBJS_PER_PAGE) max_objects = MAX_OBJS_PER_PAGE; if (page->objects != max_objects) { slab_err(s, page, "Wrong number of objects. Found %d but should be %d", page->objects, max_objects); page->objects = max_objects; slab_fix(s, "Number of objects adjusted."); } if (page->inuse != page->objects - nr) { slab_err(s, page, "Wrong object count. Counter is %d but counted were %d", page->inuse, page->objects - nr); page->inuse = page->objects - nr; slab_fix(s, "Object count adjusted."); } return search == NULL; }
요청한 슬랩 페이지의 freelist 체인에서 @search free object까지 검색하며 각 free object들의 FP(Free Pointer) 값이 유효한지 체크한다. 성공 시 1을 반환하며, @search object가 발견되지 못하거나 FP 값에 문제가 있는 경우 실패 0을 반환한다. (@search가 null인 경우 끝 까지 검색한다)
- 코드 라인 8~29에서 슬랩 페이지의 freelist에 연결된 모든 free object들을 @search object가 발견될 떄 까지 순회하며 FP(Free Pointer) 값들의 유효함을 체크한다. @search object가 발견되는 경우 정상 1을 반환한다. 만일 문제가 있는 경우 문제가 발생된 free object 뒤의 연결을 끊고 “Freechain corrupt” 에러를 출력한다.
- 코드 라인 31~40에서 order 페이지에 포함가능한 object 수가 s->objects와 동일한지 체크하며, 다른 경우 “Wrong number of objects. Found %d but should be %d” 메시지를 출력하고, s->objects 값을 교정한다.
- 코드 라인 41~46에서 사용 중인 object 수가 다른 경우에도 “Wrong object count. Counter is %d but counted were %d” 메시지를 출력하고, s->inuse 값을 교정한다.
- 코드 라인 47에서 입력 인자 @search가 null로 진입한 경우에만 성공 1을 반환하고, 그렇지 않고 @search object를 지정하였지만 못 찾은 경우 실패 0을 반환한다.
check_valid_pointer()
mm/slub.c
/* Verify that a pointer has an address that is valid within a slab page */ static inline int check_valid_pointer(struct kmem_cache *s, struct page *page, void *object) { void *base; if (!object) return 1; base = page_address(page); object = kasan_reset_tag(object); object = restore_red_left(s, object); if (object < base || object >= base + page->objects * s->size || (object - base) % s->size) { return 0; } return 1; }
@object 가상 주소가 슬랩 페이지 범위내에 포함되는지 여부를 조사한다. 정상일 때 1을 반환한다.
디버깅 사례
Object already free
슬랩 object를 두 번 free 할 때 이를 알아내어 출력한다.
[ 2202.358934] ============================================================================= [ 2202.362125] BUG jake (Tainted: G B W O ): Object already free [ 2202.365019] ----------------------------------------------------------------------------- [ 2202.365019] [ 2202.369155] INFO: Allocated in foo_init+0x54/0x1000 [poison] age=131 cpu=0 pid=6663 [ 2202.372442] __slab_alloc+0x24/0x34 [ 2202.374002] kmem_cache_alloc+0x1b8/0x264 [ 2202.375754] foo_init+0x54/0x1000 [poison] [ 2202.377567] do_one_initcall+0x48/0x160 [ 2202.379247] do_init_module+0x54/0x1c4 [ 2202.380937] load_module+0x1ec8/0x20ac [ 2202.382578] __se_sys_finit_module+0xc8/0xdc [ 2202.384429] __arm64_sys_finit_module+0x18/0x20 [ 2202.386411] el0_svc_common+0xc0/0x100 [ 2202.388060] el0_svc_handler+0x2c/0x70 [ 2202.389726] el0_svc+0x8/0xc [ 2202.390985] INFO: Freed in foo_init+0xfc/0x1000 [poison] age=12 cpu=0 pid=6663 [ 2202.394121] kmem_cache_free+0x220/0x230 [ 2202.395815] foo_init+0xfc/0x1000 [poison] [ 2202.397603] do_one_initcall+0x48/0x160 [ 2202.399291] do_init_module+0x54/0x1c4 [ 2202.400931] load_module+0x1ec8/0x20ac [ 2202.402580] __se_sys_finit_module+0xc8/0xdc [ 2202.404422] __arm64_sys_finit_module+0x18/0x20 [ 2202.406395] el0_svc_common+0xc0/0x100 [ 2202.408001] el0_svc_handler+0x2c/0x70 [ 2202.409637] el0_svc+0x8/0xc [ 2202.410917] INFO: Slab 0xffff7e0000e5cf00 objects=20 used=0 fp=0xffff80003973c008 flags=0xfffc00000010201 [ 2202.415035] INFO: Object 0xffff80003973c008 @offset=8 fp=0xffff80003973dd20 [ 2202.415035] [ 2202.418671] Redzone ffff80003973c000: bb bb bb bb bb bb bb bb ........ [ 2202.422397] Object ffff80003973c008: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk [ 2202.426349] Object ffff80003973c018: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b a5 kkkkkkkkkkkkk. [ 2202.430291] Redzone ffff80003973c026: bb bb .. [ 2202.433803] Padding ffff80003973c160: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ [ 2202.437785] Padding ffff80003973c170: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ [ 2202.441817] Padding ffff80003973c180: 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZ [ 2202.445556] CPU: 0 PID: 6663 Comm: insmod Tainted: G B W O 5.0.0+ #24 [ 2202.448676] Hardware name: linux,dummy-virt (DT) [ 2202.450626] Call trace: [ 2202.451732] dump_backtrace+0x0/0x154 [ 2202.453299] show_stack+0x14/0x1c [ 2202.454739] dump_stack+0x88/0xb0 [ 2202.456150] print_trailer+0x108/0x194 [ 2202.457787] object_err+0x3c/0x4c [ 2202.459198] free_debug_processing+0x278/0x484 [ 2202.461125] __slab_free+0x74/0x4b0 [ 2202.462602] kmem_cache_free+0x220/0x230 [ 2202.464400] foo_init+0x108/0x1000 [poison] [ 2202.466332] do_one_initcall+0x48/0x160 [ 2202.468010] do_init_module+0x54/0x1c4 [ 2202.469673] load_module+0x1ec8/0x20ac [ 2202.471324] __se_sys_finit_module+0xc8/0xdc [ 2202.473174] __arm64_sys_finit_module+0x18/0x20 [ 2202.475137] el0_svc_common+0xc0/0x100 [ 2202.476783] el0_svc_handler+0x2c/0x70 [ 2202.478387] el0_svc+0x8/0xc [ 2202.484819] FIX jake: Object at 0xffff80003973c008 not freed
Poison overwritten
free된 32바이트 object에 1바이트를 기록하였다.
- foo_init+0x58/0x1000에서 free된 후 데이터가 기록되어 문제가 있었다는 것을 슬랩 object가 다시 할당(alloc)될 때 알아내어 출력한다.
[ 1774.452218] ============================================================================= [ 1774.455625] BUG jake (Tainted: G B W O ): Poison overwritten [ 1774.458420] ----------------------------------------------------------------------------- [ 1774.458420] [ 1774.462528] INFO: 0xffff8000364ae008-0xffff8000364ae008. First byte 0x11 instead of 0x6b [ 1774.465971] INFO: Allocated in foo_init+0x54/0x1000 [poison] age=132 cpu=0 pid=5940 [ 1774.469231] __slab_alloc+0x24/0x34 [ 1774.470709] kmem_cache_alloc+0x1b8/0x264 [ 1774.472424] foo_init+0x54/0x1000 [poison] [ 1774.474216] do_one_initcall+0x48/0x160 [ 1774.475892] do_init_module+0x54/0x1c4 [ 1774.477545] load_module+0x1ec8/0x20ac [ 1774.479150] __se_sys_finit_module+0xc8/0xdc [ 1774.480982] __arm64_sys_finit_module+0x18/0x20 [ 1774.482968] el0_svc_common+0xc0/0x100 [ 1774.484590] el0_svc_handler+0x2c/0x70 [ 1774.486226] el0_svc+0x8/0xc [ 1774.487470] INFO: Freed in foo_init+0xfc/0x1000 [poison] age=11 cpu=0 pid=5940 [ 1774.490571] kmem_cache_free+0x220/0x230 [ 1774.492256] foo_init+0xfc/0x1000 [poison] [ 1774.494028] do_one_initcall+0x48/0x160 [ 1774.495697] do_init_module+0x54/0x1c4 [ 1774.497343] load_module+0x1ec8/0x20ac [ 1774.498957] __se_sys_finit_module+0xc8/0xdc [ 1774.500790] __arm64_sys_finit_module+0x18/0x20 [ 1774.502726] el0_svc_common+0xc0/0x100 [ 1774.504325] el0_svc_handler+0x2c/0x70 [ 1774.505964] el0_svc+0x8/0xc [ 1774.507206] INFO: Slab 0xffff7e0000d92b80 objects=20 used=20 fp=0x0000000000000000 flags=0xfffc00000010200 [ 1774.511296] INFO: Object 0xffff8000364ae008 @offset=8 fp=0xffff8000364afd20 [ 1774.511296] [ 1774.514915] Redzone ffff8000364ae000: bb bb bb bb bb bb bb bb ........ [ 1774.518603] Object ffff8000364ae008: 11 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b .kkkkkkkkkkkkkkk [ 1774.522580] Object ffff8000364ae018: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b a5 kkkkkkkkkkkkk. [ 1774.526446] Redzone ffff8000364ae026: bb bb .. [ 1774.529898] Padding ffff8000364ae160: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ [ 1774.533904] Padding ffff8000364ae170: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ [ 1774.537913] Padding ffff8000364ae180: 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZ [ 1774.541595] CPU: 0 PID: 5940 Comm: insmod Tainted: G B W O 5.0.0+ #24 [ 1774.544697] Hardware name: linux,dummy-virt (DT) [ 1774.546662] Call trace: [ 1774.547769] dump_backtrace+0x0/0x154 [ 1774.549315] show_stack+0x14/0x1c [ 1774.550895] dump_stack+0x88/0xb0 [ 1774.552466] print_trailer+0x108/0x194 [ 1774.554235] check_bytes_and_report+0xe0/0x124 [ 1774.556293] check_object+0x210/0x258 [ 1774.558037] alloc_debug_processing+0x154/0x1c4 [ 1774.560215] ___slab_alloc+0x89c/0x8bc [ 1774.562112] __slab_alloc+0x24/0x34 [ 1774.563769] kmem_cache_alloc+0x1b8/0x264 [ 1774.565689] foo_init+0x110/0x1000 [poison] [ 1774.567645] do_one_initcall+0x48/0x160 [ 1774.569487] do_init_module+0x54/0x1c4 [ 1774.571259] load_module+0x1ec8/0x20ac [ 1774.573014] __se_sys_finit_module+0xc8/0xdc [ 1774.575059] __arm64_sys_finit_module+0x18/0x20 [ 1774.577203] el0_svc_common+0xc0/0x100 [ 1774.578981] el0_svc_handler+0x2c/0x70 [ 1774.580742] el0_svc+0x8/0xc [ 1774.582118] FIX jake: Restoring 0xffff8000364ae008-0xffff8000364ae008=0x6b
Redzone overwritten
32바이트 object 사이즈 좌측에 있는 red-zone의 끝 1바이트를 침범당하였다.
- foo_init+0x58/0x1000에서 할당된 후 red-zone이 침범되었다는 것을 슬랩 object를 free할 때 알아내어 출력한다.
[ 901.853653] ============================================================================= [ 901.857016] BUG jake (Tainted: G B W O ): Redzone overwritten [ 901.860153] ----------------------------------------------------------------------------- [ 901.860153] [ 901.864665] INFO: 0xffff80003971c007-0xffff80003971c007. First byte 0x11 instead of 0xcc [ 901.868451] INFO: Allocated in foo_init+0x54/0x1000 [poison] age=139 cpu=0 pid=4085 [ 901.872126] __slab_alloc+0x24/0x34 [ 901.873805] kmem_cache_alloc+0x1b8/0x264 [ 901.875729] foo_init+0x54/0x1000 [poison] [ 901.877650] do_one_initcall+0x48/0x160 [ 901.879484] do_init_module+0x54/0x1c4 [ 901.881251] load_module+0x1ec8/0x20ac [ 901.883053] __se_sys_finit_module+0xc8/0xdc [ 901.885051] __arm64_sys_finit_module+0x18/0x20 [ 901.887255] el0_svc_common+0xc0/0x100 [ 901.888996] el0_svc_handler+0x2c/0x70 [ 901.890799] el0_svc+0x8/0xc [ 901.892227] INFO: Slab 0xffff7e0000e5c700 objects=20 used=1 fp=0xffff80003971dd20 flags=0xfffc00000010201 [ 901.896674] INFO: Object 0xffff80003971c008 @offset=8 fp=0xffff80003971c190 [ 901.896674] [ 901.900681] Redzone ffff80003971c000: cc cc cc cc cc cc cc 11 ........ [ 901.904770] Object ffff80003971c008: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 901.909141] Object ffff80003971c018: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .............. [ 901.913406] Redzone ffff80003971c026: cc cc .. [ 901.917241] Padding ffff80003971c160: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ [ 901.921614] Padding ffff80003971c170: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ [ 901.926018] Padding ffff80003971c180: 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZ [ 901.930064] CPU: 0 PID: 4085 Comm: insmod Tainted: G B W O 5.0.0+ #24 [ 901.933449] Hardware name: linux,dummy-virt (DT) [ 901.935553] Call trace: [ 901.936723] dump_backtrace+0x0/0x154 [ 901.938436] show_stack+0x14/0x1c [ 901.939978] dump_stack+0x88/0xb0 [ 901.941523] print_trailer+0x108/0x194 [ 901.943253] check_bytes_and_report+0xe0/0x124 [ 901.945320] check_object+0x184/0x258 [ 901.946981] free_debug_processing+0x1e0/0x484 [ 901.949706] __slab_free+0x74/0x4b0 [ 901.951371] kmem_cache_free+0x220/0x230 [ 901.953287] foo_init+0x104/0x1000 [poison] [ 901.955290] do_one_initcall+0x48/0x160 [ 901.957125] do_init_module+0x54/0x1c4 [ 901.958932] load_module+0x1ec8/0x20ac [ 901.960718] __se_sys_finit_module+0xc8/0xdc [ 901.962721] __arm64_sys_finit_module+0x18/0x20 [ 901.964827] el0_svc_common+0xc0/0x100 [ 901.966606] el0_svc_handler+0x2c/0x70 [ 901.968403] el0_svc+0x8/0xc [ 901.969785] FIX jake: Restoring 0xffff80003971c007-0xffff80003971c007=0xcc [ 901.969785] [ 901.978507] FIX jake: Object at 0xffff80003971c008 not freed
32바이트 object 사이즈이지만 2자를 더 overwrite하여 우측 red-zone이 침범당하였다.
- foo_init+0x54/0x1000에서 할당된 후 red-zone이 침범되었다는 것을 슬랩 object를 free할 때 알아내어 출력한다.
[ 1416.793614] ============================================================================= [ 1416.796913] BUG jake (Tainted: G B W O ): Redzone overwritten [ 1416.799971] ----------------------------------------------------------------------------- [ 1416.799971] [ 1416.804445] INFO: 0xffff80003b1c6026-0xffff80003b1c6027. First byte 0x11 instead of 0xcc [ 1416.808208] INFO: Allocated in foo_init+0x54/0x1000 [poison] age=126 cpu=0 pid=4905 [ 1416.811812] __slab_alloc+0x24/0x34 [ 1416.813468] kmem_cache_alloc+0x1b8/0x264 [ 1416.815368] foo_init+0x54/0x1000 [poison] [ 1416.817276] do_one_initcall+0x48/0x160 [ 1416.819100] do_init_module+0x54/0x1c4 [ 1416.820886] load_module+0x1ec8/0x20ac [ 1416.822650] __se_sys_finit_module+0xc8/0xdc [ 1416.824629] __arm64_sys_finit_module+0x18/0x20 [ 1416.826814] el0_svc_common+0xc0/0x100 [ 1416.828593] el0_svc_handler+0x2c/0x70 [ 1416.830363] el0_svc+0x8/0xc [ 1416.831725] INFO: Slab 0xffff7e0000ec7180 objects=20 used=1 fp=0xffff80003b1c7d20 flags=0xfffc00000010201 [ 1416.836152] INFO: Object 0xffff80003b1c6008 @offset=8 fp=0xffff80003b1c6190 [ 1416.836152] [ 1416.840133] Redzone ffff80003b1c6000: cc cc cc cc cc cc cc cc ........ [ 1416.844160] Object ffff80003b1c6008: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 1416.848511] Object ffff80003b1c6018: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .............. [ 1416.852767] Redzone ffff80003b1c6026: 11 11 .. [ 1416.856576] Padding ffff80003b1c6160: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ [ 1416.860998] Padding ffff80003b1c6170: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ [ 1416.865338] Padding ffff80003b1c6180: 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZ [ 1416.869421] CPU: 0 PID: 4905 Comm: insmod Tainted: G B W O 5.0.0+ #24 [ 1416.872812] Hardware name: linux,dummy-virt (DT) [ 1416.875023] Call trace: [ 1416.876164] dump_backtrace+0x0/0x154 [ 1416.877885] show_stack+0x14/0x1c [ 1416.879479] dump_stack+0x88/0xb0 [ 1416.881010] print_trailer+0x108/0x194 [ 1416.882789] check_bytes_and_report+0xe0/0x124 [ 1416.884901] check_object+0x1b4/0x258 [ 1416.886653] free_debug_processing+0x1e0/0x484 [ 1416.888706] __slab_free+0x74/0x4b0 [ 1416.890352] kmem_cache_free+0x220/0x230 [ 1416.892196] foo_init+0x104/0x1000 [poison] [ 1416.894140] do_one_initcall+0x48/0x160 [ 1416.895959] do_init_module+0x54/0x1c4 [ 1416.897739] load_module+0x1ec8/0x20ac [ 1416.899555] __se_sys_finit_module+0xc8/0xdc [ 1416.901553] __arm64_sys_finit_module+0x18/0x20 [ 1416.903754] el0_svc_common+0xc0/0x100 [ 1416.905550] el0_svc_handler+0x2c/0x70 [ 1416.907376] el0_svc+0x8/0xc [ 1416.908711] FIX jake: Restoring 0xffff80003b1c6026-0xffff80003b1c6027=0xcc [ 1416.908711] [ 1416.917035] FIX jake: Object at 0xffff80003b1c6008 not freed
Object padding overwritten
패딩 위치에 1바이트를 기록하여 패딩을 침범하였다.
- foo_init+0x10c/0x1000에서 슬랩 object를 free할 때 패딩이 침범되었다는 것을 알아내어 출력한다.
[ 641.785286] ============================================================================= [ 641.788638] BUG jake (Tainted: G B W O ): Object padding overwritten [ 641.791951] ----------------------------------------------------------------------------- [ 641.791951] [ 641.796458] INFO: 0xffff80003b2e4187-0xffff80003b2e4187. First byte 0x11 instead of 0x5a [ 641.800288] INFO: Allocated in foo_init+0x54/0x1000 [poison] age=124 cpu=0 pid=3812 [ 641.803902] __slab_alloc+0x24/0x34 [ 641.805508] kmem_cache_alloc+0x1b8/0x264 [ 641.807441] foo_init+0x54/0x1000 [poison] [ 641.809350] do_one_initcall+0x48/0x160 [ 641.811194] do_init_module+0x54/0x1c4 [ 641.812974] load_module+0x1ec8/0x20ac [ 641.814741] __se_sys_finit_module+0xc8/0xdc [ 641.816755] __arm64_sys_finit_module+0x18/0x20 [ 641.818906] el0_svc_common+0xc0/0x100 [ 641.820700] el0_svc_handler+0x2c/0x70 [ 641.822490] el0_svc+0x8/0xc [ 641.823938] INFO: Slab 0xffff7e0000ecb900 objects=20 used=1 fp=0xffff80003b2e5d20 flags=0xfffc00000010201 [ 641.828332] INFO: Object 0xffff80003b2e4008 @offset=8 fp=0xffff80003b2e4190 [ 641.828332] [ 641.832301] Redzone ffff80003b2e4000: cc cc cc cc cc cc cc cc ........ [ 641.836372] Object ffff80003b2e4008: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 641.840714] Object ffff80003b2e4018: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .............. [ 641.844984] Redzone ffff80003b2e4026: cc cc .. [ 641.848801] Padding ffff80003b2e4160: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ [ 641.853194] Padding ffff80003b2e4170: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ [ 641.857547] Padding ffff80003b2e4180: 5a 5a 5a 5a 5a 5a 5a 11 ZZZZZZZ. [ 641.861674] CPU: 0 PID: 3812 Comm: insmod Tainted: G B W O 5.0.0+ #24 [ 641.865067] Hardware name: linux,dummy-virt (DT) [ 641.867282] Call trace: [ 641.868449] dump_backtrace+0x0/0x154 [ 641.870200] show_stack+0x14/0x1c [ 641.871793] dump_stack+0x88/0xb0 [ 641.873373] print_trailer+0x108/0x194 [ 641.875134] check_bytes_and_report+0xe0/0x124 [ 641.877221] check_object+0xb4/0x258 [ 641.878925] free_debug_processing+0x1e0/0x484 [ 641.880980] __slab_free+0x74/0x4b0 [ 641.882649] kmem_cache_free+0x220/0x230 [ 641.884519] foo_init+0x104/0x1000 [poison] [ 641.886502] do_one_initcall+0x48/0x160 [ 641.888325] do_init_module+0x54/0x1c4 [ 641.890102] load_module+0x1ec8/0x20ac [ 641.891877] __se_sys_finit_module+0xc8/0xdc [ 641.893882] __arm64_sys_finit_module+0x18/0x20 [ 641.896013] el0_svc_common+0xc0/0x100 [ 641.897772] el0_svc_handler+0x2c/0x70 [ 641.899587] el0_svc+0x8/0xc [ 641.900994] FIX jake: Restoring 0xffff80003b2e4187-0xffff80003b2e4187=0x5a
샘플 소스 – poison.c
#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/string.h> #include <linux/slab.h> #include <linux/version.h> /* LINUX_VERSION_CODE & KERNEL_VERSION() */ #include <linux/printk.h> static int __init foo_init(void) { int ret = 0; void *obj; int size = 768; printk("%s\n", __func__); s = kmem_cache_create("jake", OBJ_SIZE, OBJ_ALIGN, 0, NULL); obj = kmem_cache_alloc(s, 0); printk(KERN_ERR "\n"); printk(KERN_ERR "--------------------------------------------------\n"); print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 16, 1, obj, size, 1); memset(obj, 0, OBJ_SIZE); // memset(obj - 1, 0x11, 1); /* Redzone overwritten */ // memset(obj + 383, 0x11, 1); /* Object padding overwritten */ printk(KERN_ERR "\n"); printk(KERN_ERR "--------------------------------------------------\n"); print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 16, 1, obj, size, 1); kmem_cache_free(s, obj); // kmem_cache_free(s, obj); /* Object already free */ // memset(obj, 0x11, 1); /* Poison overwritten */ // obj = kmem_cache_alloc(s, 0); // kmem_cache_free(s, obj); printk(KERN_ERR "\n"); printk(KERN_ERR "--------------------------------------------------\n"); print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 16, 1, obj, size, 1); return ret; /* 0=success */ } static void __exit foo_exit(void) { printk("%s\n", __func__); kmem_cache_destroy(s); } module_init(foo_init); module_exit(foo_exit); MODULE_LICENSE("GPL");
다음은 정상 출력 결과이다.
$ insmod poison.ko [81403.699138] foo_init [ 448.848125] -------------------------------------------------- [ 448.968221] ffff80003b1b6008: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk [ 448.978732] ffff80003b1b6018: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b a5 cc cc kkkkkkkkkkkkk... [ 448.985722] ffff80003b1b6028: 90 61 1b 3b 00 80 ff ff 54 a0 b8 08 00 00 ff ff .a.;....T....... [ 448.988850] ffff80003b1b6038: 5c b0 22 10 00 00 ff ff 24 b2 22 10 00 00 ff ff \.".....$."..... [ 448.993154] ffff80003b1b6048: 54 a0 b8 08 00 00 ff ff 18 42 08 10 00 00 ff ff T........B...... [ 448.996288] ffff80003b1b6058: 18 19 16 10 00 00 ff ff e0 39 16 10 00 00 ff ff .........9...... [ 449.000385] ffff80003b1b6068: 80 3e 16 10 00 00 ff ff cc 3e 16 10 00 00 ff ff .>.......>...... [ 449.004501] ffff80003b1b6078: 04 4e 09 10 00 00 ff ff 70 4e 09 10 00 00 ff ff .N......pN...... [ 449.008632] ffff80003b1b6088: 48 40 08 10 00 00 ff ff 00 00 00 00 00 00 00 00 H@.............. [ 449.012671] ffff80003b1b6098: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.016834] ffff80003b1b60a8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.020962] ffff80003b1b60b8: 00 00 00 00 d0 0d 00 00 25 91 00 00 01 00 00 00 ........%....... [ 449.025210] ffff80003b1b60c8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.028337] ffff80003b1b60d8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.032464] ffff80003b1b60e8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.036560] ffff80003b1b60f8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.040701] ffff80003b1b6108: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.044866] ffff80003b1b6118: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.049156] ffff80003b1b6128: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.052225] ffff80003b1b6138: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.056406] ffff80003b1b6148: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.060468] ffff80003b1b6158: 00 00 00 00 00 00 00 00 5a 5a 5a 5a 5a 5a 5a 5a ........ZZZZZZZZ [ 449.064601] ffff80003b1b6168: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ [ 449.068740] ffff80003b1b6178: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ [ 449.072893] ffff80003b1b6188: bb bb bb bb bb bb bb bb 6b 6b 6b 6b 6b 6b 6b 6b ........kkkkkkkk [ 449.077104] ffff80003b1b6198: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk [ 449.080262] ffff80003b1b61a8: 6b 6b 6b 6b 6b a5 bb bb 00 00 00 00 00 00 00 00 kkkkk........... [ 449.084328] ffff80003b1b61b8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.088401] ffff80003b1b61c8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.092573] ffff80003b1b61d8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.096696] ffff80003b1b61e8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.100803] ffff80003b1b61f8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.104885] ffff80003b1b6208: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.109140] ffff80003b1b6218: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.112250] ffff80003b1b6228: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.116340] ffff80003b1b6238: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.120410] ffff80003b1b6248: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.124536] ffff80003b1b6258: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.128709] ffff80003b1b6268: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.132914] ffff80003b1b6278: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.137103] ffff80003b1b6288: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.140199] ffff80003b1b6298: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.144304] ffff80003b1b62a8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.148720] ffff80003b1b62b8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.152893] ffff80003b1b62c8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.157051] ffff80003b1b62d8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.160192] ffff80003b1b62e8: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ [ 449.164503] ffff80003b1b62f8: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ [ 449.168664] [ 449.169693] -------------------------------------------------- [ 449.171833] ffff80003b1b6008: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.176219] ffff80003b1b6018: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 cc cc ................ [ 449.180475] ffff80003b1b6028: 90 61 1b 3b 00 80 ff ff 54 a0 b8 08 00 00 ff ff .a.;....T....... [ 449.184559] ffff80003b1b6038: 5c b0 22 10 00 00 ff ff 24 b2 22 10 00 00 ff ff \.".....$."..... [ 449.188792] ffff80003b1b6048: 54 a0 b8 08 00 00 ff ff 18 42 08 10 00 00 ff ff T........B...... [ 449.192897] ffff80003b1b6058: 18 19 16 10 00 00 ff ff e0 39 16 10 00 00 ff ff .........9...... [ 449.197151] ffff80003b1b6068: 80 3e 16 10 00 00 ff ff cc 3e 16 10 00 00 ff ff .>.......>...... [ 449.200274] ffff80003b1b6078: 04 4e 09 10 00 00 ff ff 70 4e 09 10 00 00 ff ff .N......pN...... [ 449.204465] ffff80003b1b6088: 48 40 08 10 00 00 ff ff 00 00 00 00 00 00 00 00 H@.............. [ 449.208564] ffff80003b1b6098: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.212645] ffff80003b1b60a8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.216746] ffff80003b1b60b8: 00 00 00 00 d0 0d 00 00 25 91 00 00 01 00 00 00 ........%....... [ 449.220898] ffff80003b1b60c8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.225150] ffff80003b1b60d8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.228231] ffff80003b1b60e8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.232343] ffff80003b1b60f8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.236527] ffff80003b1b6108: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.240811] ffff80003b1b6118: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.244950] ffff80003b1b6128: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.249140] ffff80003b1b6138: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.252289] ffff80003b1b6148: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.256440] ffff80003b1b6158: 00 00 00 00 00 00 00 00 5a 5a 5a 5a 5a 5a 5a 5a ........ZZZZZZZZ [ 449.260563] ffff80003b1b6168: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ [ 449.264670] ffff80003b1b6178: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ [ 449.268835] ffff80003b1b6188: bb bb bb bb bb bb bb bb 6b 6b 6b 6b 6b 6b 6b 6b ........kkkkkkkk [ 449.272971] ffff80003b1b6198: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk [ 449.277139] ffff80003b1b61a8: 6b 6b 6b 6b 6b a5 bb bb 00 00 00 00 00 00 00 00 kkkkk........... [ 449.280274] ffff80003b1b61b8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.284607] ffff80003b1b61c8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.288818] ffff80003b1b61d8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.293014] ffff80003b1b61e8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.296146] ffff80003b1b61f8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.300283] ffff80003b1b6208: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.304305] ffff80003b1b6218: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.308369] ffff80003b1b6228: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.312433] ffff80003b1b6238: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.316562] ffff80003b1b6248: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.320615] ffff80003b1b6258: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.324791] ffff80003b1b6268: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.329059] ffff80003b1b6278: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.332165] ffff80003b1b6288: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.336283] ffff80003b1b6298: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.340471] ffff80003b1b62a8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.345025] ffff80003b1b62b8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.348173] ffff80003b1b62c8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.352216] ffff80003b1b62d8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.356293] ffff80003b1b62e8: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ [ 449.360331] ffff80003b1b62f8: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ [ 449.408843] [ 449.409632] -------------------------------------------------- [ 449.411684] ffff80003b1b6008: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk [ 449.415920] ffff80003b1b6018: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b a5 bb bb kkkkkkkkkkkkk... [ 449.419903] ffff80003b1b6028: 20 7d 1b 3b 00 80 ff ff 54 a0 b8 08 00 00 ff ff }.;....T....... [ 449.424012] ffff80003b1b6038: 5c b0 22 10 00 00 ff ff 24 b2 22 10 00 00 ff ff \.".....$."..... [ 449.427968] ffff80003b1b6048: 54 a0 b8 08 00 00 ff ff 18 42 08 10 00 00 ff ff T........B...... [ 449.431977] ffff80003b1b6058: 18 19 16 10 00 00 ff ff e0 39 16 10 00 00 ff ff .........9...... [ 449.435914] ffff80003b1b6068: 80 3e 16 10 00 00 ff ff cc 3e 16 10 00 00 ff ff .>.......>...... [ 449.439910] ffff80003b1b6078: 04 4e 09 10 00 00 ff ff 70 4e 09 10 00 00 ff ff .N......pN...... [ 449.443825] ffff80003b1b6088: 48 40 08 10 00 00 ff ff 00 00 00 00 00 00 00 00 H@.............. [ 449.447773] ffff80003b1b6098: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.451670] ffff80003b1b60a8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.455609] ffff80003b1b60b8: 00 00 00 00 d0 0d 00 00 25 91 00 00 01 00 00 00 ........%....... [ 449.459796] ffff80003b1b60c8: fc a0 b8 08 00 00 ff ff c4 cb 22 10 00 00 ff ff .........."..... [ 449.464003] ffff80003b1b60d8: fc a0 b8 08 00 00 ff ff 18 42 08 10 00 00 ff ff .........B...... [ 449.468412] ffff80003b1b60e8: 18 19 16 10 00 00 ff ff e0 39 16 10 00 00 ff ff .........9...... [ 449.472887] ffff80003b1b60f8: 80 3e 16 10 00 00 ff ff cc 3e 16 10 00 00 ff ff .>.......>...... [ 449.477496] ffff80003b1b6108: 04 4e 09 10 00 00 ff ff 70 4e 09 10 00 00 ff ff .N......pN...... [ 449.480951] ffff80003b1b6118: 48 40 08 10 00 00 ff ff 00 00 00 00 00 00 00 00 H@.............. [ 449.485555] ffff80003b1b6128: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.489479] ffff80003b1b6138: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.493448] ffff80003b1b6148: 00 00 00 00 00 00 00 00 00 00 00 00 d0 0d 00 00 ................ [ 449.496857] ffff80003b1b6158: a3 91 00 00 01 00 00 00 5a 5a 5a 5a 5a 5a 5a 5a ........ZZZZZZZZ [ 449.501630] ffff80003b1b6168: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ [ 449.505645] ffff80003b1b6178: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ [ 449.509587] ffff80003b1b6188: bb bb bb bb bb bb bb bb 6b 6b 6b 6b 6b 6b 6b 6b ........kkkkkkkk [ 449.513589] ffff80003b1b6198: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk [ 449.517409] ffff80003b1b61a8: 6b 6b 6b 6b 6b a5 bb bb 00 00 00 00 00 00 00 00 kkkkk........... [ 449.520900] ffff80003b1b61b8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.525481] ffff80003b1b61c8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.528980] ffff80003b1b61d8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.533127] ffff80003b1b61e8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.536551] ffff80003b1b61f8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.541202] ffff80003b1b6208: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.544601] ffff80003b1b6218: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.549210] ffff80003b1b6228: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.552662] ffff80003b1b6238: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.557293] ffff80003b1b6248: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.560751] ffff80003b1b6258: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.565518] ffff80003b1b6268: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.568934] ffff80003b1b6278: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.573518] ffff80003b1b6288: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.577492] ffff80003b1b6298: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.581436] ffff80003b1b62a8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.585435] ffff80003b1b62b8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.588860] ffff80003b1b62c8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.593552] ffff80003b1b62d8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [ 449.597851] ffff80003b1b62e8: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ [ 449.601905] ffff80003b1b62f8: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ
kptr_restrict
커널 v4.15부터 커널에서 사용하는 포인터 주소를 숨긴다. 이를 볼 수 있게 하려면 printk() 함수의 format에 사용하는 “%p” 대신 “%px”를 사용하거나, “%pK”를 사용하고 admin 권한을 가진 유저가 “echo 1 > /proc/sys/kernel/kptr_restrict“을 수행하여 커널 포인터 출력 제한을 풀어야 한다.
Makefile
obj-m := foo.o KER := $(shell uname -r) KER_DIR := /lib/modules/$(KER)/build all: make -C ${KER_DIR} M=$(PWD) modules clean: make -C ${KER_DIR} M=$(PWD) clean
foo.c
#include <linux/kernel.h> #include <linux/module.h> int param = 0; module_param(param, int, 0); int foo_init(void) { void *p = foo_init; printk(KERN_INFO "kptr_restrict=%d, x=0x%llx, p=%p, pK=%pK, px=%px\n", param, (long long unsigned int) p, p, p, p); return 0; } void foo_exit(void) { } module_init(foo_init); module_exit(foo_exit); MODULE_DESCRIPTION("foo"); MODULE_LICENSE("GPL");
run.sh
echo 0 > /proc/sys/kernel/kptr_restrict insmod foo.ko param=0 rmmod foo echo 1 > /proc/sys/kernel/kptr_restrict insmod foo.ko param=1 rmmod foo echo 2 > /proc/sys/kernel/kptr_restrict insmod foo.ko param=2 rmmod foo
실행 결과
admin 권한으로 printk() 함수에서 함수 포인터를 출력하면 kptr_restrict 설정 값에 따라 다음과 같은 결과를 보여준다.
- %llx 옵션
- kptr_restrict 값에 상관없이 정확한 값을 보여준다.
- %p 옵션
- kptr_restrict 값에 상관없이 항상 거짓 값을 보여준다.
- %pK 옵션
- kptr_restrict=1인 경우에는 정확히 보여준다.
- kptr_restrict=2인 경우에는 0000000000000000 값으로 출력한다.
- %px
- kptr_restrict 값에 상관없이 정확한 값을 보여준다.
$ ./run.sh kptr_restrict=0, x=0xffff800008ae9000, p=00000000467430b8, pK=00000000467430b8, px=ffff800008ae9000 kptr_restrict=1, x=0xffff800008ae9000, p=00000000467430b8, pK=ffff800008ae9000, px=ffff800008ae9000 kptr_restrict=2, x=0xffff800008ae9000, p=00000000467430b8, pK=0000000000000000, px=ffff800008ae9000
참고
- Slab Memory Allocator -1- (구조) | 문c – 현재 글
- Slab Memory Allocator -2- (캐시 초기화) | 문c
- Slub Memory Allocator -3- (캐시 생성) | 문c
- Slub Memory Allocator -4- (Order 계산) | 문c
- Slub Memory Allocator -5- (Slub 할당) | 문c
- Slub Memory Allocator -6- (Object 할당) | 문c
- Slub Memory Allocator -7- (Object 해제) | 문c
- Slub Memory Allocator -8- (Drain/Flash 캐시) | 문c
- Slub Memory Allocator -9- (캐시 Shrink) | 문c
- Slub Memory Allocator -10- (Slub 해제) | 문c
- Slub Memory Allocator -11- (캐시 삭제) | 문c
- Slub Memory Allocator -12- (Slub 디버깅) | 문c – 현재 글
- Slub Memory Allocator -13- (slabinfo) | 문c
- Kernel dynamic memory allocation tracking and reduction (2012) | Ezequiel García – 다운로드 pdf
- slub_debug: Detect Kernel heap memory corruption | TechVolve