[WIL] Pintos Project 2

jw3215·2022년 11월 28일
1

argument passing

  • 기존코드에서는 파일을 실행하면, 파일이름과 인자가 모두 파일이름에 문자열로 같이 들어온다.
    - ex) gcc -o hello.out hello.c 를 실행하면 gcc -o hello.out hello.c 전체가 file_name 변수에 문자열로 잡힘.
  • 따라서, 문자열을 공백을 separator로 하여 문자열을 parsing하고, ABI 규약에 맞게 인자를 유저 프로그램이 전달하는 작업이 필요함.
  • strtok_r 함수를 사용하여, 문자열 parsing을 보다 간편하게 할 수 있었다.
  • parsing된 문자열은 유저스택에 쌓는다.
  • interrupt frame을 세팅하고 do_iret함수를 실행하여, 유저프로그램으로 분기한다.

system call

왜 system call을 사용하는가?

  • Protection
    - 시스템 콜이 없다면, 유저 프로그램이 하드웨어를 직접 조작하게 됨.
    - 안정적인 시스템 운영이 아니다.
    - 하나의 프로세스가 다른 프로세스의 입출력 작업을 하는 등 시스템에서 의도하지 않은 동작을 하는 것을 방지함.
  • 제한적 직접 실행 원리(LDE)
  • Privilege Escalation Attack
    - 권한 상승 공격
    - 공격자가 시스템 콜을 실행할 수 있는 권한을 얻음
    - Kernel Exploit

시스템 콜의 종류

  • 파일 시스템 접근
  • 프로세스 생성 및 제거
  • 다른 프로세스와의 통신
  • 메모리 할당
  • 기타 등등...

상세

  • User 모드와 Kernel 모드를 분리함
  • 시스템 콜은 Kernel 모드에서만 실행됨
  • Trap 루틴을 통해 진입
  • 대부분의 운영체제는 수백개의 시스템 콜을 제공한다.
  • 유저 모드
    - 접근할 수 있는 영역이 제한적
    - 유저 어플리케이션이 실행되는 모드
    - Intel Architecture 기준 Protection Ring 3
  • 커널 모드
    - 컴퓨터의 모든 자원에 접근할 수 있음
    - 커널이 실행되는 모드
    - Intel Architecture 기준 Protection Ring 0

예시

  1. stdioprintf() 호출 User mode
  2. glibcprintf() 함수에서 write() wrapper 함수 호출 User mode
  3. write() 구현부에서 트랩을 발생 User mode
    • Architecture의 호출부 규약에 맞에 인자를 맞춘다
    • int 0x80 (asm: 0x80 인터럽트 발생)
  4. 커널에서 트랩 핸들러 system_call() 호출 Kernel mode
    • IDT(Interrupt Descripter Table) 에서 트랩번호인 0x80을 참조하여 system_call() 호출
    • system_call()
      - EAX의 값을 인덱스로 함(시스템 콜 번호)
      - 시스템 콜 테이블에서 적절한 시스템콜 함수를 호출 (여기서는 sys_write() )
  5. 실제 write()함수인 sys_write()호출 Kernel mode
    • 시스템 콜은 sys_ 로 시작함
    • EAX에 반환할 값 저장
    • 역으로 수행하여 결과 return

왜 시스템 콜은 rcx 대신 r10을 사용하는가?

  • 일반적인 procedure call
  • rdi, rsi, rdx, rcx, r8, r9
    system call
  • rdi, rsi, rdx, r10, r8, r9

일반적인 procedure call은 되돌아갈 ripstack에 push 하지만,
시스템 콜은 트랩 루틴을 마친 후 되돌아갈 주소를 rcx에 저장하기 때문.

rcxrip
ripIA32_LSTAR

  • IA32_LSTAR는 MSR(Model-Specific Register)이며, 범용 레지스터가 아님
  • syscall 명령어는 rflags를 r11에 저장하기 때문에, r11도 사용할 수 없음.

Task

  • 리눅스 커널에서는 프로세스와 쓰레드를 구분하지 않는다.
  • 태스크로 동등하게 관리함
  • 쓰레드 그룹의 종속여부, 자원 할당 차이
  • 프로세스와 쓰레드를 생성하는 모든 함수는 do_fork() 함수를 거침
  • do_fork() 함수의 결과로 task_struct 구조체가 생성됨
  • 태스크가 생성되면, 커널 스택task_struct 가 할당됨
  • 자식 프로세스를 생성하는 fork() 함수
    - 데이터, 코드, 힙, 스택이 새로 할당됨
  • 쓰레드를 생성하는 pthread_create() 함수
    - 스택을 제외한 대부분의 자원을 부모쓰레드와 공유함
  • 커널 입장에서는 둘을 구분하지 않음
  • 커널 스택과 task_struct 할당함

0개의 댓글