CPU의 체크 포인트
Limit 체크
Limit 체크를 하지 않으면 다른 세그먼트에 있는 코드나 데이터가 overwrite 될 염려가 있음
일반 보호 예외(#GP)를 발생시키는 경우
- 오프셋이 유효 Limit보다 큰 바이트
- 오프셋이 유호 Limit-1바이트보다 큰 워드
- 오프셋이 유효 Limit-3바이트보다 큰 더블워드
- 오프셋이 유효 Limit-7바이트보다 큰 쿼드워드
GDT, IDT : GDTR, IDTR의 6바이트 중 2바이트에 해당하는 Limit 값을 사용
TSS : TR 레지스터 6바이트 중 Limit를 나타내는 2바이트를 사용
Type 체크
세그먼트 디스크립터의 S 비트가 0이면 System Type, 1이면 Code/Data Segment Type
S 비트가 0일 때의 타입
Type | 게이트 종류 |
---|---|
0x0 | 예약됨 |
0x1 | 16비트 |
0x2 | LDT |
0x3 | Busy 16비트 TSS |
0x4 | 16비트 콜게이트 |
0x5 | 태스크 게이트 |
0x6 | 16비트 인터럽트 게이트 |
0x7 | 16비트 트랩 게이트 |
0x8 | 예약됨 |
0x9 | 32비트 TSS |
0xA | 예약됨 |
0xB | Busy 32비트 TSS |
0xC | 32비트 콜게이트 |
0xD | 예약됨 |
0xE | 32비트 인터럽트 게이트 |
0xF | 32비트 트랩 게이트 |
CPU는 세그먼트 셀렉터와 디스크립터를 조작할 때 Type 정보를 조사
- 세그먼트 셀렉터가 세그먼트 레지스터에 로드될 때 CS에는 코드 세그먼트 셀렉터만 로드 가능
- 디스크립터가 세그먼트 레지스터에 이미 로드되어 있는 세그먼트에 명령이 액세스할 때
- 코드 세그먼트 영역 : 데이터 쓰기 금지
- 읽기 전용 데이터 세그먼트 : 데이터 쓰기 금지
- 코드 세그먼트에 읽기 가능 플래그 설정 X : 읽기 금지
- CALL JMP 명령 인자에 셀렉터가 있을 때 해당 셀렉터의 Type 필드 조사
- TSS 셀렉터를 인자로 한 명령에서는 디스크립터가 TSS 용인지 확인
- IRET 명령일 때 NT 비트가 1이면 back link가 TSS 용인지 확인
- GDT 맨 처음 NULL 디스크립터를 CS나 SS에 로드하려할 때 - 일반 보호 예외(#GP)
- DS, ES, FS, GS에 로드는 가능하나 로드된 셀렉터를 사용하여 세그먼트 영역에 접근 시도 - #GP
특권 레벨
낮은 레벨 태스크가 높은 레벨의 데이터를 참조하려 하면 일반 보호 예외(#GP) 발생
CPL(Current Privilege Level)
- 현재 실행되고 있는 태스크의 권한 레벨
- CS, SS 셀렉터 레지스터의 0, 1번째 비트에 있는 수
- 다른 권한 레벨의 코드 세그먼트로 제어 이행되면 CPU가 CPL을 변경함
DPL(Description Privilege Level)
- 디스크립터에 기재된 DPL 값
- 디스크립터를 통한 세그먼트 영역으로의 모든 접근에서 CPL과 DPL 관계가 체크됨
- 낮은 레벨의 CPL을 가지고 높은 레벨의 데이터 세그먼트에 접근 시 CPL과 DPL 값을 비교
RPL(Requested Privilege Level)
- 콜게이트를 통해 낮은 특권 레벨이 일시적으로 특권 레벨 0으로 들어갈 때 데이터 영역 접근하는 상황을 막기 위해 사용하는 값
- 어떤 레벨에서 불러졌는지
- 콜게이트 이외의 대부분의 경우 RPL과 CPL은 같음
콜게이트
- 낮은 특권 레벨의 프로그램이 실행 중 높은 특권 레벨로 변경되는 수단
- 인터럽트와 예외는 의지가 관계 없이 권한 레벨이 올라가지만 콜게이트는 의지에 의해 높은 권한 사용
코드와 데이터의 특권 레벨 관계
특권 레벨 간의 JMP 명령은 불가능
CALL 명령은 낮은 레벨에서 높은 레벨에 대하여 이루어져야 함
RET 명령은 높은 레벨에서 낮은 레벨에 대하여 이루어져야 함
특권 레벨 간의 JMP를 굳이 사용해야 한다면 콜게이트 사용
CALL 명령이 내려졌을 때 스택
유저 태스크가 콜게이트 등으로 커널 모드 루틴을 불러내는 경우
- 이 태스크의 TSS 영역에 SS0, ESP0의 값을 참조하여 커널 모드 스택에 현재 유저 태스크가 사용하고 있는 SS, ESP, 현재 진행 중인 루틴의 주소인 CS, EIP를 차례로 push
- CPU의 SS, ESP 레지스터에 SS0, ESP0 값 넣음
- 콜게이트에 지정된 커널 모드의 루틴 주소로 점프하고 실행
- ret 명령이 내려지면 커널 모드 스택에 SS, ESP, CS, EIP를 pop하여 각 레지스터에 복원 후 유저 모드 태스크로 돌아감
인터럽트 예외가 발생하였을 때 스택
특권 레벨 0에서 인터럽트가 걸렸을 때 스택 변경이 일어나지 않음
유저 레벨 태스크의 동작 중 인터럽트나 예외 발생
- 유저 레벨 태스크의 TSS 영역에서 SS0, ESP0을 CPU의 SS, ESP 레지스터에 복사
- 콜게이트와 같이 사용하던 SS, ESP, CS, EIP 등 레지스터 push
- iret을 사용하여 돌아오면 스택에 있는 값들을 pop하여 레지스터 복원