OS, Kernel

Kern Koh Kernel of Linux System Call 정리

msh1307 2022. 7. 18. 14:12

Why protection is necessary in Linux

 

Linux :

  • Multi-user
  • Protection - Yes
  • Resource - minimize

- Text mode CUI(Character User Interface)

 

Windows

  • Single-user
  • Protection - Little
  • Resource - user them all

- Windows, GUI(Graphical User Interface)

- Shows everything 

ex) History, State, Command, Option...

 

참고) Windows도 XP 이후부턴 multi-user Operating System이라고 한다. 

Resource Usage & OS User Interface

  • Windows에선 programs를 확인 가능하고, active process들도 확인 가능하다. 자원도 많이 먹는다. 
  • Linux에선 ps command를 통해서 active process를 확인할 수 있고, man으로 menu를 확인할 수 있다. $_ 만 출력하면 되니 2 bytes 정도의 적은 자원을 먹는다. 

Multi-user system -- Protection

  • 만약 process P1이 bug나 virus라서 P2의 정보에 illegal access가 가능해서 read/write가 가능하다면 문제가 발생함

  • illegal access를 그때그때 잡아내는 데에는 한계가 존재해서 방지해야 함

  • 그래서 나온게 protection임

 

How does protection work

  • Kernel 제외 모든 I/O instruction들은 허용되지 않음
  • System call을 통해 kernel에게 I/O instruction의 처리를 요청
  • kernel이 access를 검증하고 I/O functions를 통해 I/O 작업을 처리해줌

 

  • system call의 동작을 도와주기 위해서 cpu hardware에 하나의 binary bit를 도입함
  • 도입한 binary bit를 여기선 mode bit이라고 부름

  • instruction을 가져와서 opcode를 보고 CPU가 작업을 처리하게 됨

  • mode bit가 1이 돼서 kernel mode를 가리키면 모든 memory에 접근할 수 있고, 모든 instruction들을 사용가능함
  • mode bit이 0이라 User mode를 가리키면 모든 instruction을 할 수 없고 자신의 local address space만 접근할 수 있음
  • 결론적으로 privileged op-code 수행을 mode bit에 따라 제한받는다고 볼 수 있음
  • privileged op-code는 I/O instruction이나 special-register access나 어떤 것이든 다른 것을 해칠 수 있는 op-code를 의미함

Memory address 검증

  • CPU의 instruction cycle에서 CPU가 instruction fetch를 하기 위해서는 memory에 접근을 해야 됨 
  • operands 가져올때도 memory 접근은 필수

  • 이렇게 CPU가 계속 memory에 address로 access 할 때, cpu와 memory 사이 memory bus에 있는 MMU(Memory Management Unit)가 mode bit으로 kernel mode인지 user mode인지 확인함

 

  • User mode일 때

1) MMU가 CPU가 user mode인 것을 확인했다면 address를 보고 그 프로세스의 address space range안에 들어가는지 확인함

2) address space range 벗어나면 거부시킴

 

  • kernel mode일 때 

1) kernel 이 돌아가고 있다면 제약이 없음

 

참고) MMU는 logical address를 physical address로 바꿔주는 역할을 주로 함

 

Execute단에서의 검증

  • execute 할 때 op-code도 검증함
  • User mode일 때

1) privileged op-code 라면 실행 못 시키게 함

2) privileged op-code가 아니면 그냥 실행시킴

 

  • kernel mode일 때

1) op-code가 뭐가 되던 상관없음

2) 제한 없음

 

얻을 수 있는 효과 : illegal access 차단 가능

 

How do programs handling I/O

  • Source: I/O statement를 가지고 있음
  • Binary: compiler가 I/O statement를 없애고 parameter를 준비하고 execute chmodk(change mode kernel) instruction 같은 것으로 바꿈

  • Binary가 실행되는 Run time

- program이 chmodk를 실행함

- chmodk는 privileged instruction임

- CPU는 user-mode 상태에서 더 이상 진행할 수 없음

- trap 걸림 -> interrupt랑 비슷함

- 이때 trap handler routine에 따라서 kernel 안으로 들어감

- 세팅된 parameter들을 보고 어떤 이유로 trap이 걸렸는지 확인함

- 확인했으면 자기가 갖고 있는 kernel 내 function으로 신호 보냄

- 끝나면 user-mode로 되돌리고 interrupted location으로 return

 

-> 이게 system call

- kernel이 I/O를 대신해줄 때 permission을 체크함

- permission보고 만족하면 해주고 아니면 안 해줌

 

  • ex) 

1) 어떤 program이 disk sector에 대해서 write를 해달라고 요청함

2) kernel이 그 disk sector에 대해서 program이 write permission이 있는지 확인

3) 있으면 해 주고 없으면 안 해줌

 

1) compile 된 파일이 chmodk를 실행시키면 trap이 걸림

2) trap이 걸리고 kernel mode 바뀜

3) kernel 안에 있는 trap의 trap handler가 왜 trap 걸렸는지 확인하고 적당한 function으로 보내줌

4) permission check 하고 맞는 거 실행시켜줌

5) 끝나면 user mode 바뀜

6) return

 

-> system call 과정에서 kernel function에 접근해야 되니 왜 kernel 이 항상 memory resident인지 알 수 있음

system call에서 어떤 kernel function을 부를지 모르니 memory에 항상 있어야됨

  • main memory에서 보면 이렇게 됨

  • program은 local variable이나 sfp(saved frame pointer)나 ret(return addresss) 같은 것들이 저장되는 stack이 필요함
  • kernel function 호출 하고 local variable 같은 것도 쓰고 return도 하니까 kernel stack도 당연히 필요함
  • stack 필요성) function call 했을 때 함수가 끝나면 필요 없는 local variable들을 저장할 memory 영역을 항상 할당해놓으면 memory 낭비라서

  • 프로세스마다 할당받는 가상 메모리에서 위에 1GB Kernel 영역 안에 Kernel stack이 있는 것 같음

  • 이런 식의 흐름

 

Invoking a system call

  • printf ibrary function을 call 하면 그 library function 실행됨
  • library function이 실행되다가 I/O를 해야 되면 wrapping 해주는 function call
  • parameter를 미리 세팅해주고 chmodk를 해주는 function을 system call wrapper routine이라고 부름
  • wrapper routine이 필요한 이유는 read 때문에 가는지, write 때문에 가는지 구분하고 필요한 parameter 전달하려고
  • trap 걸려서 kernel이 받으면 받은 parameter 보고 적절한 function으로 보냄
  • function 실행되고 리턴

  • Wrapper routine안에서 보면 eax로 sys call number 세팅해주고 argument를 push 해줌
  • 여기선 x86_32에서의 syscall을 예시로 보여줌
  • x86_64는 interrupt 0x80 대신에 syscall 사용하고 레지스터에 넣어서 세팅함

  • sys_call이 현재 process의 context save
  • 앞에서 말한 trap handler임 
  • valid 검사
  • eax에 들어간 sys call number를 sys_call에서 보고 나서 sys_call_table이라는 array를 참조해서 sys call number에 맞는 function의 start address를 받아서 실행
  • 끝나면 return

  • Naming convention은 sys_  +  syscall name

  • 만약 읽으면 kernel process가 요청한 process한테 읽은걸 줘야 됨
  • 근데 그 둘은 독립적인 process임
  • 그래도 kernel은 모든 memory access 가능
  • user space로 데이터 가져오고 주는 게 가능함
  • 당연히 user space에서 kernel space 건드는건 안됨
  • sys call number는 Architecture 의존적이고 바뀔 수 없음
  • syscall table은 kernel trap handler가 갖고 있음

  • syscall을 맘대로 추가해버리면 platform dependent program들이 안 돌아갈 수 있음
  • = 비효율적

  • 새로운 file descriptor 만들어서 쓰라는 말