Computer Security

#3 리눅스 커널 3 본문

리눅스 커널 해킹

#3 리눅스 커널 3

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

디바이스 드라이버

 

  • 컴퓨터와 연결된 장치를 추상화시켜서, 유저 애플리케이션이 정형화된 인터페이스를 통해 장치에 접근할 수 있도록 해주는 소프트웨어이다.
  • 커널이 컴파일 될 때 부터 포함된 디바이스 드라이버도 있고 별도로 컴파일되어 커널 부팅 후에 로드되는 디바이스 드라이버도 있다.
  • 디바이스 드라이버는 모듈의 일종이므로 모듈 프로그래밍을 통해 프로그래밍 할 수 있다.

 

종류

 

Character Device  :  버퍼 캐시를 사용하지 않으며, Device를 파일처럼 직접 접근한다.(마우스,키보드,사운드카드 드라이버등)

 

Block Device  :  Hard Disk와 같은 file system을 기반으로 block단위로 접근한다.

 

Network Device : 네트워크 스택과 네트워크 하드웨어 사이에 위치하여 데이터의 송수신을 담당한다.

 


file_operations

  • 디바이스 드라이버와 유저 애플리케이션간의 커뮤니케이션을 위한 인터페이스이다.
  • 각종 함수 포인터 멤버들이 선언되어 있다.

 

운영체제는 파일 생성, 파일 쓰기, 파일 읽기, 위치 재설정, 파일 삭제, 파일 절단의 6개의 기본적인 시스템콜을 제공한다.

 

  • 파일 생성
    • 파일 시스템 내에서 파일을 저장할 수 있는 공간을 찾는다.
    • 새로 생성된 파일에 대한 항목을 디렉토리에 생성한다.
  • 파일 쓰기
    • 파일 이름과 기록될 정보를 명시하는 시스템콜을 실행한다.
    • 시스템은 그 이름을 갖는 파일의 위치를 찾기위해 디렉토리를 탐색한다.
    • 파일 내에서 write pointer를 유지해서 다음 쓰기가 일어날 위치를 표시한다. 이 포인터는 쓰기가 일어날때마다 갱신된다.
  • 파일 읽기
    • 파일의 이름과 파일이 읽혀 들어갈 블록의 위치를 명시하는 시스템콜을 실행한다.
    • 시스템은 그 이름을 갖는 파일의 위치를 찾기 위해 디렉토리를 탐색한다.
    • 파일 내에서 read pointer를 유지해서 다음 읽기가 발생할 위치를 표시한다. 읽기가 발생할때마다 이 포이터는 갱신된다.
    • 대부분의 시스템은 current file position pointer를 가지기 때문에 읽기, 쓰기 연산 모두 이 포인터를 사용할 수 있다.
  • 파일 안에서의 위치 재설정
    • 디렉토리에서 항목을 탐색하고 현재 파일 위치를 주어진 값으로 설정한다.
  • 파일 삭제
    • 지명된 파일을 디렉토리에서 찾는다.
    • 해당 파일이 차지하고 있는 공간을 방출하고 디렉토리 항목을 삭제한다.
  • 파일 절단
    • 파일의 내용은 지우고 속성만 남길때 사용되는 연산이다.
    • 파일의 길이를 0으로 재설정한다.
    • 파일이 갖고있던 공간은 해제한다.

 

struct file_operations test_fops = {
  .open   = test_open,
  .release = test_release,
  .read = test_read,
  .write = test_write,
  .unlocked_ioctl = test_ioctl,

};

static struct miscdevice test_driver = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = "test",
    .fops = &test_fops,

};

static int test_open(struct inode *inode, struct file *file){
     printk("test open");
     
     return 0;
}

static int test_init(void) {
     return misc_register(&test_driver);
}

static void test_exit(void) {
     misc_deregister(&test_driver);
}

module_init(test_init);
module_exit(test_exit);

file_operations 구조체에 디바이스 드라이버 내부 함수 등록

 

유저공간에서 해당 디바이스에 대한 open() 함수를 호출 시, 커널에서는 test_open() 함수를 호출 후 나머지 작업을 진행한다.

 

디바이스 드라이버가 등록될 때 test_init() 함수를 호출, 디바이스 드라이버가 제거될 때 test_exit()함수를 호출한다.

 


주로 사용 되는 함수

 

copy_from_user(a,b,c) : 유저 공간에서 커널 공간으로 데이터를 안전하게 복사하는 함수이다.

                                       유저공간 주소 b에서 c바이트 만큼 커널 공간 주소 a로 복사한다.

 

copy_to_user(a,b,c) : 커널 공간에서 유저 공간으로 데이터를 안전하게 복사하는 함수이다.

                                   커널 공간 주소 b에서 c바이트 만큼 유저 공간 주소 a로 복사한다.

 

mutex/spinlock : 커널에서의 race condition을 방지하기 위한 커널 동기화 함수이다.

 


모듈 프로그래밍

 

  • 모듈이란 동적으로 커널에 등록하거나 제거 할 수 있는 프로그램을 뜻한다.  이로 인해 커널 이미지를 재컴파일 하지 않고도 기능을 추가할 수 있다.
  • 모듈 프로그래밍을 통해 디바이스 드라이버를 작성할 수 있다.
  • 모듈은 kbuild라는 규칙이 있는 Makefile을 통해 컴파일 할 수 있다.
  • 컴파일된 모듈은 insmod, rmmod등의 명령어로 등록 및 제거가 가능하다.

 

obj-m += test.o

PWD += $(shell pwd)

all:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

위와 같은 형식의 Makefile을 작성해서 컴파일이 가능하다.

위의 경우는 현재 호스트 커널 버전에 따르는 test라는 모듈을 컴파일 하는 것이다.

 


 

모듈 동작 확인을 위한 test.c 예제코드

static int test_open(struct inode* inode, struct file* file);

struct file_operations test_fops = {
	.open           =test_open,
};

static struct miscdevice test_driver = {
	.minor = MISC_DYNAMIC_MINOR,
	.name = "test",
	.fops = &test_fops,
};


static int test_open(struct inode* inode, struct file* file) {
	return 0;
}


static int test_init(void) {
	int result;
	
	printk("my name is noob");

	result = misc_register(&test_driver);

	return 0;
}

static void test_exit(void) {
	misc_deregister(&test_driver);
}

module_init(test_init);
module_exit(test_exit);

 

module_init(test_init) 부분은 이 드라이버가 커널에 등록될 때 test_init()함수를 호출하는 역할을 한다.

 

test_init()함수에서 printk()함수를 이용해 "my name is noob"이라는 커널 로그를 출력하도록 구현되었다.

 

그 뒤에 misc 디바이스를 생성하며, /dev 경로에 test라는 디바이스가 생성된다.

 

이 디바이스를 통해 유저 공간과 커뮤니케이션이 가능하다.

 

 

#커널로그는 루트권한으로만 볼 수 있다.

 


insmode test.ko 명령을 통해 커널에 test.ko 모듈을 등록할 수 있다.

rmmode test.ko 명령을 통해 test.ko 모듈을 제거할 수 있다.

 

test.ko 모듈을 등록하면 "my name is noob" 커널 로그가 출력되는 것을 확인 할 수 있다.(성공적 모듈등록)

반응형

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

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