CPU의 보호 레벨은 0~ 3, 4개로 실제로 쓰이는 것은 0과, 3 2개입니다. (숫자가 아닌 보안 수준이)낮은 레벨의 태스크가 높은 레벨의 데이터를 참조(3 레벨의 태스크가 0 레벨 태스크) 하면 일반 보호 에러(#GP)가 발생하게 됩니다.

1. CPU 보호 레벨

 

1) CPL(Current Priviliege level)

현재 실행되고 있는 태스크의 특권 레벨로, CS, SS 셀렉터 레지스터의 0, 1번째 비트에 있는 수 입니다. 프로그램이 다른 특권 레벨의 코드 세그먼트로 제어가 바뀌면 CPU는 CPL을 변경하게 됩니다.

 

2) DPL(Description Privilege Level)

디스크립터를 통해서 세그먼트 영역으로 접근할 때, 항상 CPL과 DPL을 비교하여 접근이 가능한지 불가능한지 판단이 이루어 지게 됩니다.

 

3) RPL(Requested Privilege Level)

콜게이트(낮은 특권 레벨에서 높은 특권 레벨의 루틴을 사용할 수 있게 하는 관문)을 통해 레벨 3인 프로세스가 특권 레벨 0에 해당하는 루틴을 실행할 때, 일시적으로 특권 레벨 0에 해당하는 데이터 영역에 접근할 수 있습니다. 이러한 현상을 사용하여 악용하는 것을 막기 위해 OS는 RPL 값을 사용합니다.

어떤 레벨의 프로세스가 루틴을 불러들였는지 기록하여, 낮은 특권 레벨이 루틴을 불렀을 때 높은 특권 레벨의 데이터 영역을 보호합니다.

 

2. 콜 게이트

콜게이트는 인터럽트, 예외와 마찬가지로 낮은 특권 레벨의 프로그램이 높은 특권 레벨로 변경되는 수단으로 사용됩니다. 하드웨어 인터럽트와 예외는 응용 프로그램과 상관 없이 특권 레벨이 변경되지만, 소프트웨어 인터럽트와 콜게이트는 낮은 특권 레벨의 프로그램에 따라 높은 특권 레벨의 루틴을 사용할 수 있습니다.

컴퓨터의 RAM, 하드디스크에 들어 있는 자료, 그리고 하드웨어 입출력 장치등은 커널에 의해서 관리되고 유저 프로그램은 커널의 루틴의 도움을 받아 이러한 자료들을 잠시 일부분 사용할 수 있습니다.

콜게이트도 GDT 테이블의 디스크립터로 처리되며, 낮은 특권 레벨의 프로그램이 높은 특권 레벨의 프로그램의 일부분을 사용하기 위한 창구입니다.

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

커널 루틴의 오프셋 15 - 0비트

핸들러의 코드 세그먼트 셀렉터

P

DPL

0

1

1

0

0

 

사용안함

인수의 개수

커널 루틴의 오프셋 31 - 16

63

62

61

60

59

58

57

56

55

54

53

52

51

50

49

48

 

이 디스크립터를 GDT에 지정하고, 유저 프로그램은 코드 셀렉터와 마찬가지로 디스크립터를 셀렉터로 선택하여 JMP나 CALL 명열을 내릴 수 있습니다.

 

3. 코드와 데이터의 특권 레벨 관계

CALL 명령어는 낮은 특권 레벨에서 높은 특권 레벨로, RET 명령은 높은 특권 레벨에서 낮은 특권 레벨로 이동하는 명령어 이기 때문에 이 명령어를 사용합니다. JMP 는 특권 레벨 간의 이동이 불가능 하며 JMP를 이용하여 특권 레벨의 이동을 사용해야 한다면 콜게이트 사용하여야 합니다.

 

(1) CALL 과 RET의 특권 레벨 변화

Q : CALL 명령어로 특권 레벨 0의 루틴을 불러 낼 때

A : CS 셀렉터의 0, 1 비트에 00이 들어가고 CPL은 0이 됩니다.

Q : RET 명령어로 다시 특권 레벨 3으로 돌아갈 때

A : CS 셀렉터의 0, 1비트에 11이 들어가고 CPL은 1이 됩니다.

 

코드 세그먼트 영역의 특권 레벨 DPL과 CPL은 어떤 상황에서 든 기본적으로 값이 같습니다.

예외 >> Conforming 세그먼트

특권 레벨 0의 루틴을 불러내도 CPL의 값은 그대로 3인 채 실행되었다 IRET으로 돌아옵니다. (Call gate와 관련)

 

(2) 특권 레벨과 접근 권한

특권 레벨 0에서는 모든 특권 레벨의 데이터 세그먼트 영역에 접근이 가능하지만 낮은 특권 레벨의 프로세스에서는 높은 특권 레벨의 데이터에 접근이 금지됩니다.

 

4. 특권 레벨 변동 시의 스택의 변화

 

스택 스위칭은 높은 특권 레벨의 루틴이 스택 공간의 부족 때문에 크래시 되지 않게 하기 위해서, 그리고 낮은 특권 레벨의 루틴이 스택을 통해 높은 특권 레벨의 루틴에 간섭하지 못하게 하기 위해 사용 됩니다.

핸들러나 커널 루틴으로 들어가기 전에 스택에 돌아올 주소 등을 넣어 두었다가 핸들러나 커널 루틴이 끝나고 다시 유저 모드 태스크로 돌아오기 위해 스택에 넣어 두었던 값들을 사용합니다.

 

(1) CALL 명령 – 유저 태스크 가 콜 게이트를 이용하여 커널 모드의 루틴

1) 호출 구문에 인수가 없는 경우

이 태스크 TSS 영역의 SS0, ESP0의 값을 참조하여 커널 모드의 스택에 현재 유저 태스크가 사용하고 있는 SS, ESP, 그리고 유저 태스크가 현재 진행중인 루틴의 주소, CS, EIP를 PUSH ( 스택방향 )

SS

 

ESP

CS

 

EIP

 

콜게이트에 지정된 커널 모드의 루틴 주소로 점프하고 실행

루틴을 마치고 RET 명령을 실행하여 커널 모드의 스택에 저장된 SS, ESP, CS, EIP를 POP(CS 를 먼저 검사한 후, 현재 커널 모드 보다 낮은 특권 레벨이면(콜게이트를 통한 특권레벨 이동일 경우???) SS와 ESP를 POP 합니다.)

2) 호출 구문에 인수가 있는 경우

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

커널 루틴의 오프셋 15 - 0비트

핸들러의 코드 세그먼트 셀렉터

P

DPL

0

1

1

0

0

 

사용안함

인수의 개수

커널 루틴의 오프셋 31 - 16

63

62

61

60

59

58

57

56

55

54

53

52

51

50

49

48

 

콜게이트를 통한 커널 루틴에서 사용할 인수의 개수를 미리 기입함

유저 레벨의 SS, ESP의 주소에 인수들을 PUSH 하고 콜게이트를 통하여 커널 레벨(특권 레벨 0) 루틴으로 들어가도 커널 레벨의 루틴에서는 스택 주소가 SS0, ESP0로 변경되어 pop 하여도 관련 없는 값을 참조하게 될 것입니다.

 

GDT 디스크립터의 인수의 개수 항목에 2가 들어있다면 유저 레벨의 스택에서 2개를 커널 모드의 스택에 복사합니다.

(스택의 방향은 원래 위에서 아래로 자라지만 여기서는 작성자의 착각으로;;; 반대로 표시했습니다. 반대로 뒤집으시면 거꿀로 자라는 스택이 됩니다)

Param1

스택 진행 방향

 

Param2

 

ESP

 

←SS

 
  

 

Param1과 Param2를 복사합니다.

 

SS

 

스택 진행 방향

ESP

Param1

Param2

 

CS

  
 

EIP

 

ESP0

 

←SS0

 
  

 

(2) 인터럽트 예외가 발생하였을 때의 스택

EFLAGS가 추가된 것을 제외하면 콜 게이트와 흡사합니다

1) 커널 모드에서 인터럽트가 걸렸을 때

특권 레벨 0에서 진행 되므로 SS, ESP 그대로 값을 사용하고, 스택에 EFLAGS, CS, EIP를 PUSH 합니다.

 

EFLAGS

↑스택 진행 방향

 

CS

  
 

EIP

 

ESP

 

←SS

 
  

 

2) 유저 레벨 에서 인터럽트가 발생했을 때

유저 레벨 태스크의 TSS 영역에서 SS0, ESP0를 CPU의 SS, ESP 레지스터에 복사하여, 콜게이트 경우에는 유저 모드의 태스크가 사용하던 SS, ESP, CS, EIP등의 레지스터의 값을 PUSH하여 저장합니다. IRET으로 유저 모드로 돌아갈때는 스택에 있는 값을 POP하여 CPU의 각각의 레지스터에 복원합니다.

 

스택 진행 방향

 
 
 
  
 
  

ESP

 

←SS

 
  

 

SS

 

스택 진행 방향

ESP

EFLAGS

 

CS

  
 

EIP

 

ESP0

 

←SS0

 
  

+ Recent posts