1 / 26

10 장 시스템 콜

10 장 시스템 콜. 김 태 훈. API 와 시스템 콜의 차이. API 는 특정 서비스를 어떻게 받을지를 지정하는 함수 시스템 콜은 소프트웨어 인터럽트를 통해 커널에 하는 직접적인 요청 libc 에서 정의하는 API 중 일부는 시스템 콜을 호출하는 목적으로만 사용하는 “ 래퍼루틴 ” 이 있다 . 보통 각 시스템 콜마다 대응하는 래퍼 루틴이 하나씩 있으며 , 래퍼 루틴은 애플리케이션에서 사용할 API 를 정의한다 .

aleron
Download Presentation

10 장 시스템 콜

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 10장시스템 콜 김 태 훈

  2. API와 시스템 콜의 차이 • API는 특정 서비스를 어떻게 받을지를 지정하는 함수 • 시스템 콜은 소프트웨어 인터럽트를 통해 커널에 하는 직접적인 요청 • libc에서 정의하는 API중 일부는 시스템 콜을 호출하는 목적으로만 사용하는 “래퍼루틴”이 있다. • 보통 각 시스템 콜마다 대응하는 래퍼 루틴이 하나씩 있으며, 래퍼 루틴은 애플리케이션에서 사용할 API를 정의한다. • 그러나 그 역은 성립하지 않는다. 즉, API는 특정 시스템 콜에 대응할 필요가 없다.

  3. 시스템 콜 핸들러와 서비스 루틴 • 사용자 모드 프로세스가 시스템 콜을 호출하면, CPU는 커널 모드로 전환해서 커널함수를 실행하기 시작한다. • 커널은 서로 다른 많은 시스템 콜을 구현하므로 사용자 모드 프로세스는 자신이 원하는 시스템 콜을 구별하는 ‘System Call Number’를 매개 변수로 전달해야 한다. • eax레지스터를 사용한다. • 모든 시스템 콜은 정수 값을 반환한다. • 양수나 0은 성공, 실패는 음수이다. • 에러가 발생한 경우 errno변수를 통해 에러 코드는 나타낸다. • 커널은error변수를 사용하지 않음. • 대신 래퍼 루틴이 시스템 콜에서 돌아온 후 변수를 설정하는 일을 한다.

  4. 시스템 콜핸들러와 서비스 루틴 • 시스템 콜 핸들러의 역할 • 레지스터 내용을 커널 모드 스택에 저장한다. • ‘System Call Service Routine’이라는 C함수를 호출하여 시스템 콜을 처리한다. • 핸들러에서 빠져 나온다. • 커널 모드 스택에 저장된 값을 레지스터들에 로딩하고, CPU는 커널모드에서 사용자 모드로 다시 돌아온다.

  5. 시스템 콜 핸들러와 서비스 루틴 • 그림 10-1 • SYSCALL, SYSEXIT는 사용자 모드에서 커널 모드로, 커널 모드에서 사용자 모드로 CPU를 전환하는 실제 어셈블리 명령어가 있는 곳을 나타낸다. • 커널은 시스템 콜 번호와 해당 시스템 콜 서비스 루틴을 서로 연계하기 위해 ‘System Call Dispatch Table’을 사용한다. • 이 테이블은 sys_call_table배열에 들어 있다. • NR_syscalls개의 엔트리를 포함한다. • __NR_syscall_max개 (279개) • 이 값은 구현 가능한 시스템 콜의 최대 개수로, 실제 구현하고 있는 시스템 콜 수를 의미하지는 않는다.

  6. 시스템 콜로의 진입과 복귀 • 시스템 콜을 호출하는 두 가지 방법 • int $0x80 어셈블리 명령을 수행한다. • 과거버전에서 사용자 모드에서 커널 모드로 전환하는 유일한 방법 • sysenter어셈블리어를 수행한다. • 2.6 커널 이상 부터 지원함. • 펜티엄 2 프로세서 부터 지원함. • 사용자 모드로 전환하는 두 가지 방법 • iret어셈블리 명령어를 수행한다. • sysexit어셈블리 명령어를 수행한다.

  7. 시스템 콜로의 진입과 복귀 • 두 가지 방법이 혼재함으로 인해 고려해야 할 사항. • 커널은int $x80 명령어만 사용하는 라이브러리와 sysenter를 사용하는 라이브러리를 동시에 지원해야 한다. • sysenter를 사용하는 라이브러리는 int $x80만 지원하는 커널에 대처해야 한다. • 커널과 표준 라이브러리는 sysenter명령어를 포함하지 않는 구식 프로세서와 sysenter명령어를 포함하는 최신 프로세서에서 모두 실행될 수 있어야 한다.

  8. int $0x80 명령어를 통한 시스템 콜 발생 • trap_init함수는 128번 (0x80)에 해당하는 ‘Interrupt Descriptor Table’ 엔트리를 다음과 같이 설정한다. • set_system_gate(0x80, &system_call); • 이는 gate descriptor의 필드를 다음 값으로 지정한다. • 세그먼트 셀렉터 • __KERNEL_CS • 오프셋 • system_call() 예외 핸들러에 대한 포인터이다. • 종류(Type) • 15로 설정. • 예외 종류가 Trap이고, 해당 핸들러는 마스크 가능한 인터럽트를 금지하지 않음. • DPL(Descriptor Privilege Level) • 3으로 설정 • 사용자 모드의 프로세스가 예외 핸들러를 호출할 수 있게 한다. • 사용자모드 프로세스가 int $0x80 명령어를 발생시킬 때 CPU는 커널 모드로 전환하고 system_call주소에서 명령어를 수행한다.

  9. system_call() 함수 • 시스템콜 번호와 함께 예외 핸들러가 사용할 수 있도록 eflags와 cs, eip, ss, esp레지스터를 제외한 모든 CPU레지스터를 스택에 저장한다. • SAVE_ALL 매크로는 ds와 es를 각각 커널 데이터 세그먼트의 세그먼트 셀렉터로 설정한다.

  10. system_call() 함수 • ebx레지스터에 현재 프로세스의 thread_info자료 구조의 주소를 저장한다. • thread_info자료 구조의 flags 필드를 검사하여 디버거의 추적이 있는지 확인한다. • TIF_SYSCALL_TRACE, TIF_SYSCALL_AUDIT • 이 경우, do_syscall_trace() 함수를 시스템 콜 실행 전후에 호출한다. • 사용자 모드 프로세스가 전달한 시스템 콜 번호가 올바른지 검사한다. • 시스템 콜 번호가 잘못된 것이면eax를 저장했던 스택위치에–ENOSYS값을 저장한 후 resume+userspace()를 호출한다.

  11. sysenter명령어를 통한 시스템 콜 발생 • low-latency system call • 다음의 세 가지 레지스터를 사용한다. • SYSENTER_CS_MSR • 커널 코드 세그먼트의 세그먼트 셀렉터 • SYSENTER_EIP_MSR • 커널진입점의 선형 주소 • SYSENTER_ESP_MSR • 커널스택 포인터 • sysenter명령어 수행시, • SYSENTER_CS_MSR의 내용을 cs레지스터에 복사한다. • 커널 영역의 코드 세그먼트 정보 • SYSENTER_EIP_MSR의 내용을 eip레지스터에 복사한다. • sysenter_entry() 함수의 주소 • SYSENTER_ESP_MSR의 내용을 esp레지스터에 복사한다. • TSS(Task State Segment)의 주소 • SYSENTER_CS_MSR의 값에 8을 더한 후 ss레지스터에 값을 로딩한다.

  12. vsyscall • 커널이 정의한 실행 코드를 사용자 공간에서 참조할 수 있도록 하기 위해 library에서 실행시키는 것. • 실행하고 있는 CPU에 따라 int 0x80을 사용하거나, sysenter명령을 사용한다. • 장점 : 커널 호출이 불필요한 경우, 실제 시스템 콜을 발생하지 않고 처리를 끝낸다. • 예) gettimeofday • 표준 라이브러리의 래퍼 루틴이 시스템 콜을 호출할 때는 항상 __kernel_vsyscall() 함수를 호출한다.

  13. vsyscall • CPU가 sysenter를 지원하지 않는 경우 • CPU가 sysenter를 지원하는 경우

  14. 시스템 콜로의 진입 • eax레지스터에 시스템 콜 번호를 로딩한다. • __kernel_vsyscall() 함수는 ecx, edx, ebp레지스터 값을 스택에push한다. • esp(사용자 스택 포인터)를 ebp에 복사한다. • sysenter명령어를 수행한다. • CPU는 현재 모드를 커널 모드로 전환한다. • SYSENTER_EIP_MSR 레지스터가 가리키는 sysenter_entry()함수를 호출한다. • 커널스택 포인터를 설정한다. • 지역 인터럽트를 허용한다. • 다음을 스택에push한다. • 사용자 데이터 세그먼트(__USER_DS) • 사용자 스택 포인터 • 사용자 코드 세그먼트의 세그먼트 셀렉터 • 리턴시 수행될 명령어 주소 • 래퍼 루틴이 전달한 레스터 초기 값을 ebp레지스터에 복구한다.

  15. 시스템 콜에서 빠져 나오기 • eax레지스터에 시스템 콜의 반환 값을 저장한다. • 지역 인터럽트를 금지한다. • 현재 thread_info의 flag를 검사한다. ebp sysenter sysexit edx ecx

  16. sysexit명령어 • 커널 모드에서 사용자 모드로 전환한다. • sysexit명령어 수행시CPU는, • SYSENTER_CS_MSR 레지스터 값에 16을 더해서 cs레지스터에 로딩한다. • 사용자 코드의 세그멘트셀렉터 로딩 • edx레지스터 값을 eip레지스터에 복사한다. • SYSENTER_CS_MSR 레지스터에 24를 더해서 ss레지스터에 로딩한다. • 사용자 데이터 세그먼트의 세그먼트 셀렉터 로딩 • ecx레지스터 값을 esp레지스터에 복사한다.

  17. SYSENTER_RETURN 코드 • sysenter로 시작된 시스템 콜이 iret이나 sysexit명령에 의해 종료중일때 수행된다. • vsyscall페이지에 저장되어 있다. • 스택에 저장된 레지스터의 값을 복구한 후, 표준 라이브러리의 래퍼 루틴으로 제어권을 반환한다.

  18. 매개 변수 전달 • 매개변수의 형식 • 실제 값(숫자), 사용자 주소 공간의 변수, 사용자 공간의 자료구조 주소 • 필수 매개 변수 • eax레지스터로 전달하는 시스템 콜 번호 • 예) fork()를 호출하면, int $0x80 or sysenter를 실행하기 전에 eax레지스터를 __NR_fork로 설정한다. • 일반적인 C프로그램에서 매개변수는 스택을 통하여 전달된다. • 그러나 시스템 콜은 모드가 변경되는 특별한 함수이기 때문에 양쪽 어느 곳의 스택도 사용할 수 없다. • 시스템 콜 서비스 루틴 수행 전 매개 변수를 CPU 레지스터에 저장한다. • 저장된 매개 변수를 커널 모드의 스택으로 복사한다. • 사용자 모드의 스택을커널 모드의 스택으로 직접 복사는 난해하므로 사용하지 않는다.

  19. 매개 변수 전달 • 매개 변수를 레지스터로 전달하기 위한 두가지 조건 • 각 매개 변수는 레지스터 크기인 32비트를 넘을 수 없다. : 32비트 CPU의 경우에만 해당 • 레지스터의 수는 제한적이므로 6개를 넘길 수 없다.(eax포함) • 6개를 초과하는 매개 변수 전달법 • 하나의 레지스터를 매개 변수 값을 저장하고 있는 프로세스 주소 공간 내의 메모리 영역을 가르키게 한다. • 사용되는 레지스터의 종류 • eax, ebx, ecx, edx, esi, edi, ebp

  20. 매개변수 확인 • 공통적인 검사 유형 • 매개 변수가 주소인 경우 커널은 이 주소가 프로세스 주소 공간 내에 있는지 검사해야 한다. • 선형 주소가 프로세스 주소 공간에 속하는지, 속하면 주소를 포함하는 메모리영역이 해당 접근 권한에 있는지 확인한다. • 초기 커널의 형태 : 전달된 매개 변수를 모두 검사하므로 시간이 오래 걸림. • 선형 주소가 PAGE_OFFSET보다 낮은지 확인한다. • 즉, 커널용으로 예약한 주소 범위에 들어가지 않는지.. • 커널2.2 이후 부터 사용

  21. 프로세스 주소 공간 접근 • 프로세스 주소 공간에 접근을 위한 매크로 제공

  22. 동적 주소 검사 – 수선 코드 (The Fix-up Code) • 커널 모드에서 페이지 폴트가 일어날 수 있는 네 가지 경우 • 해당 페이지 프레임이 존재하지 않거나읽기 전용 페이지에 쓰려고 한 경우. • 해당 페이지 테이블 엔트리가 초기화되지 않은 경우 • 커널함수의 버그 또는 일시적인 H/W에러 • 시스템 콜에 전달한 주소의 메모리 영역에 읽기/쓰기를 할 때 해당 주소가 프로세스 주소 공간에 들어 있지 않은 경우

  23. 예외 테이블 • 사용자 공간에 접근 하는 명령어 개수는 매우 적다. • 프로세스 주소 공간에 접근하는 각 커널 명령의 주소를 ‘예외 테이블(Exception Table)’ 구조체로 모은다. • 만일 페이지 폴트 예외가 발생하면, do_page_fault핸들러를 이용해 예외 테이블을 검사한다. • 예외를 일으킨 명령의 주소를 찾으면 시스템 콜 매개 변수가 원인이 되고, 그렇지 않으면 다른 버그 때문이다. • 예외 테이블의 엔트리 • insn : 프로세스 주소 공간에 접근하는 명령어의 주소 • fixup : 예외가 발생할 때 호출할 어셈블리 코드 주소

  24. 예외 테이블 • 예외 테이블은 커널을컴파일할 때 링크된다. • 예외 테이블 항목은 __ex_table섹션에 저장된다. • 예외가 발생했을 때 처리 코드는 커널 코드 세그먼트 중 .fixup섹션에 저장된다. • search_exception_table() 함수 • 예외 테이블에 지정한 주소가 있는지 찾는다. • 주소가 테이블에 있으면 해당 exception_table_entry의 포인트를, • 없으면 0을 반환한다.

  25. 커널래퍼 루틴 • 시스템 콜은 주로 사용자 모드 프로세스에서 사용한다. • 하지만 커널스레드에서도 사용할 수 있도록 래퍼 루틴(Wrapper Routine) 선언을 위해 _syscall0 ~ _syscall6 까지 매크로를 선언하고 있다. • 매크로의 숫자는 시스템 콜이 사용하는 매개변수의 개수이다. • 여기서는 6개가 넘는 매개변수는 사용할 수 없다.

  26. 커널래퍼 루틴 • 각 매크로는 (2 + 2xn)개의 매개변수를 받는다. • 예 • _syscall0(int, fork) • int : 반환타입 • fork : 시스템 콜 이름 • _syscall3(int, write, int, fd, const char*, buf, unsigned int, count) • int : 반환타입 • write : 시스템 콜 이름 • int : type, fd : 첫번째 매개 변수 • const char * : type, buf: 두번째매개 변수 • unsigned int: type, count : 세번째매개 변수 • int write(intfd, const char *buf, unsigned int count)

More Related