Computer Security

#2 리눅스 커널 2 본문

리눅스 커널 해킹

#2 리눅스 커널 2

쿠리 Kuri 2022. 8. 10. 18:30
반응형

태스크

  • 리눅스 커널에서는 프로세스와 쓰레드(1)를 별도로 구분하지 않고, 모두 태스크로 동등하게 관리한다.
  • 단지 쓰레드 그룹에 속해 있는가 등의 여부에 다라 차이가 나는 것이다.
  • 모든 태스크들은 task_struct 구조체로 관리 된다.
  • 프로세스와 쓰레드를 생성하는 모든 함수는 do_fork()함수를 거치며, 이 함수는 task_struct를 생성하는 역할을 한다.
  • 하나의 태스크가 생성 될 때, 결론적으로 커널스택과 task_struct가 할당 된다.

각 함수의 흐름

 위 함수를 살펴보면 프로세스(2)나 쓰레드를 생성하는 다른 함수도 결국엔 마지막엔 do_fork() 커널함수를 호출한다. 

이것이 쓰레드와 프로세스가 모두 task_struct를 가지게 되는 이유다.

 

 

 


(1) 쓰레드

 어떠한 프로그램 내에서, 특히 프로세스 내에서 실행되는 흐름의 단위를 말한다. 일반적으로 한 프로그램은 하나의 쓰레드를 가지고 있지만, 프로그램 환경에 따라 둘 이상의 스레드를 동시에 실행할 수 있다. 이러한 실행 방식을 멀티쓰레드 라고 한다.

 

(2) fork()

실행 중인 프로세스의 복사본 프로세스를 생성하는 함수이다.

주로 실행 중에 별도의 독립된 작업이 필요한 경우 fork()로 복사된 프로세스가 수행하도록 하는 것이 일반적인 사용이다.


task_struct

  • pid_t pid:    프로세스마다 부여하는 식별 값
  • pid_t tgid :   쓰레드 그룹 아이디
  • char comm[]:  프로세스의 이름
  • struct task_struct *real_parent:   자신을 생성한 부모 태스크를 가르킨다.
  • struct task_struct *parent :   현재 부모 태스크를 가르킨다.
  • struct mm_struct*mm:    mm_struct는 유저공간의 텍스트,데이터,스택,힙 등의 영역의 위치와 메타데이터를 가지고 있다.

mm_struct

start_code, end_code : 각각 Text 영역의 시작과 끝의 주소

start_data, end_data : 각각 Data영역의 시작과 끝의 주소

start_brk, brk : 각각 Heap 영역의 시작과 끝의 주소. brk 는 증가가 가능하다.

stack_start : Stack영역의 시작 주소

 


리눅스 가상메모리 레이아웃


슬랩 할당자

 

슬랩 할당자는 커널에서 사용하는 동적 메모리 할당자이며 메모리 풀 구조를 가지고 있다.(즉, 미리 고정된 크기의 메모리 블록들을 할당 해 놓는다는 것이다.

 

 

슬랩 캐시 : 커널에서 자주 요청하는 크기에 대한 동적 메모리를 미리 확보하고 관리하는 주체이다.

 

슬랩 객체 : 슬랩 캐시가 할당해 놓은 메모리 블록. malloc()의 chunk와 비슷한 개념이다.

 

슬랩 페이지:  동일한 크기의 슬랩 객체들로 구성되어 있다.

 

슬랩 페이지는 동일한 크기의 슬랩 객체들로 구성되어 있으며, 이러한 슬랩 페이지 집합을 관리하는 것이 슬랩 캐시 이다.

 

user space - malloc()

#include <stdio.h>
#include <stdlib.h>

int main()
{
  int *ptr;
  ptr = malloc(sizeof(int));
  
  return0;
 
 }

kernel space - kmalloc()

#include <linux/slab.h>

static int test_open(struct inode *inode, struct file *file) {
   int *ptr;
   
   ptr = (int *)kmalloc(sizeof(int), GFP_KERNEL);  //GFP_KERNEL :커널힙과 관련된 설정 flag 
   
   return 0;
   
}

 

Slab

  • 2007~2008년까지 default 로 사용되었다.
  • 관리 방식이 다소 복잡해 메모리 오버헤드가 발생했다.
  • full, partial, empty 리스트들을 이용해 slab object 를 관리했다.

 

Slub

  • 현재까지 default로 사용 되고 있다.
  • slab에 비해 단순한 관리방식이다.
  • partial 리스트만을 사용해서 slab object를 관리한다.

 

Slob

  • 적은 메모리 자원을 가진 시스템에서 사용한다.
  • 속도는 느리지만 메모리 소모가 가장 적다.

주요 자료 구조

  • 슬랩 할당자는 kmalloc_caches[] 라는 전역 배열을 이용해 각 크기별 슬랩 캐시들을 관리한다.
  • 각 슬랩 캐시는 kmem_cache 라는 구조체로 표현된다.
  • 슬랩 캐시는 슬랩 객체의 할당 속도를 높이기 위해 CPU 개수 만큼 kmem_cache_cpu 라는 구조체를 추가적으로 이용한다.

슬랩 페이지


슬랩 객체가 할당 되는 과정

 

1. kamlloc() 호출된다.

static __always_inline void *kmalloc(size_t size, gfp_t flags)
{
    if (__builtin_constant_p(size)) {
#ifndef CONFIG_SLOB
        unsigned int index;
#endif   
        if (size> KMALLOC_MAX_CACHE_SIZE)
           return kmalloc_large(size, flags);
#ifndef CONFIG_SLOB
        index - kmalloc_index(size);
        
        if (!index)
            return ZERO_SIZE_PTR;
        
        return kmem_cache_alloc_trace(
                kmalloc_caches[kmalloc_type(flags)][index],
                flags, size);
                
#endif
   }
   return_kmalloc(size,flags);
}

kamlloc_indext()함수를 호출해  요청한 크기에 해당하는 kmalloc_caches[] 전역 배열의 인덱스를 선택한다.

 

인덱스를 인자로 kmem_cache_alloc_trace()함수를 호출한다.

 

 

 

 

2. kmem_cache_alloc_trace()

void *kmem_cache_alloc_trace(struct kmem_cache *s, gfp_t gfpflags, size_t size)
{
   void *ret = slab_alloc(s, gfpflags, _RET_IP);
   trace_kmalloc(_RET_IP_, ret, size, s->size, gfpflags);
   ret = kasan_kmalloc(s, ret, size, gfpflags)l;
   return ret;
}
EXPORT_STMBOL(kmem_cache_alloc_trace);
}

slab_alloc() 함수를 호출해서 반환값을 ret에 저장한 뒤 반환한다.

 

 

 

 

3. slab_alloc()

static __always_inline void *slab_alloc(struct kmem_cache *s,
        gfp_t gfpflags, unsigned long addr)
{
   return slab_alloc_node(s, gfpflags, NUMA_NO_NODE, addr);
}

slab_alloc_node()함수를 호출한다.

 

 

 

 

4. slab_alloc_node()

 

kmem_cache_cpu 구조체로 관리되는 per-cpu 슬럽 캐시를 불러온다.

 

각종 작업 후 kmem_cache_cpu의 freelist에 해제된 슬랩 객체가 있을 경우, 해당 슬랩 객체를 최종적으로 반환한다.

 

kmem_cache_cpu의 freelist에 NULL이 있을 경우 슬랩 페이지를 새로 할당 받은 뒤, 슬랩 객체를 반환한다.

 

반응형

'리눅스 커널 해킹' 카테고리의 다른 글

#6 리눅스 CTF에서의 환경 셋팅  (0) 2022.08.14
#5 리눅스 qemu&gdb 셋팅  (0) 2022.08.13
#4 리눅스 커널&파일 시스템 빌드  (0) 2022.08.12
#3 리눅스 커널 3  (0) 2022.08.11
#1 리눅스 커널 1  (0) 2022.08.09
Comments