일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- 컴퓨터구조
- pwncollege
- 리눅스
- kernel
- 시스템 프로그래밍
- Bandit
- radare2
- 시스템해킹
- 알고리즘
- 드론
- 리버싱
- px4
- Leviathan
- 취약점
- 시스템
- 리눅스커널
- wargame
- 시그널
- C++
- 프로그래밍
- 어셈블리어
- Pwnable.kr
- 리눅스 커널
- write up
- 시스템프로그래밍
- 워게임
- C언어
- css
- 커널
- pwn.college
- Today
- Total
Computer Security
#3 리눅스 커널 3 본문
디바이스 드라이버
- 컴퓨터와 연결된 장치를 추상화시켜서, 유저 애플리케이션이 정형화된 인터페이스를 통해 장치에 접근할 수 있도록 해주는 소프트웨어이다.
- 커널이 컴파일 될 때 부터 포함된 디바이스 드라이버도 있고 별도로 컴파일되어 커널 부팅 후에 로드되는 디바이스 드라이버도 있다.
- 디바이스 드라이버는 모듈의 일종이므로 모듈 프로그래밍을 통해 프로그래밍 할 수 있다.
종류
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 |