Slub Memory Allocator -12- (slub 디버깅)

<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

 

참고

 

댓글 남기기