왜 유저모드와 커널모드를 구분해야 하나요?
신뢰할 수 없는 사용자 프로그램으로부터 커널과 하드웨어 자원을 보호하고, 프로세스 간 격리를 보장하여 시스템 전체의 안정성과 보안을 유지하기 위해서입니다. ** 사용자 모드 ** 커널 모드
구분하지 않으면 생기는 문제
[모드 구분이 없는 경우]
악성 프로그램 → 디스크 포맷 명령 직접 실행 → 전체 데이터 손실
버그 프로그램 → 커널 메모리 덮어쓰기 → 시스템 크래시
일반 프로그램 → 다른 프로세스 메모리 접근 → 데이터 유출·변조
무한루프 → CPU 독점 → 다른 프로세스 실행 불가
[모드 구분이 있는 경우]
악성 프로그램 → 디스크 포맷 시도 → CPU가 차단 → 해당 프로세스만 종료
버그 프로그램 → 커널 메모리 접근 → MMU가 차단 → 해당 프로세스만 종료
일반 프로그램 → 다른 프로세스 접근 → 페이지 테이블 격리 → 접근 불가
무한루프 → 타이머 인터럽트 → 커널이 강제 선점 → 다른 프로세스 실행
구분이 필요한 4가지 이유
1. 하드웨어 보호
사용자 프로그램이 하드웨어를 직접 제어하면 시스템이 파괴될 수 있습니다.
| 위협 | 모드 구분 없을 때 | 모드 구분 있을 때 |
|---|---|---|
| 디스크 직접 쓰기 | 파일 시스템 파괴 가능 | I/O 명령어가 특권 명령 → 차단 |
| 인터럽트 비활성화 | 시스템 먹통 가능 | cli 명령이 특권 명령 → 차단 |
| NIC 직접 제어 | 네트워크 스니핑 가능 | 시스템 콜로만 접근 가능 |
사용자 프로그램이 in/out 명령어로 디스크 직접 제어 시도
│
▼
CPU: 모드 비트 = 1 (사용자 모드) → 특권 명령어!
│
▼
General Protection Fault → 프로세스 강제 종료
│
▼
시스템은 안전하게 유지
2. 메모리 보호 (프로세스 격리)
각 프로세스가 독립된 가상 주소 공간을 가지므로 서로의 메모리에 접근할 수 없습니다.
[모드 구분 없을 때]
프로세스 A ──→ 물리 주소 0x1000 직접 접근 ──→ 프로세스 B 데이터 변조
[모드 구분 있을 때]
프로세스 A 프로세스 B
┌─────────────┐ ┌─────────────┐
│ 가상 주소 공간 │ │ 가상 주소 공간 │
│ 0x0000~0xFFFF│ │ 0x0000~0xFFFF│
└──────┬──────┘ └──────┬──────┘
│ MMU │ MMU
▼ ▼
물리 주소 0x1000 물리 주소 0x5000
(서로 다른 물리 영역 → 접근 불가)
3. 커널 무결성 보호
커널 코드와 데이터를 사용자 프로그램이 변조할 수 없도록 보호합니다.
[모드 구분 없을 때]
악성 프로그램 → sys_call_table 주소를 조작
→ read() 호출 시 악성 코드 실행
→ 루트킷 설치 완료
[모드 구분 있을 때]
악성 프로그램 → 커널 메모리 영역 접근 시도
→ 페이지 테이블: User/Supervisor 비트 = Supervisor
→ Page Fault 발생 → 프로세스 종료
4. CPU 보호 (독점 방지)
타이머 인터럽트와 커널의 스케줄러가 협력하여 하나의 프로세스가 CPU를 독점하는 것을 방지합니다.
[모드 구분 없을 때]
프로그램: while(true) {} + cli(인터럽트 비활성화)
→ 타이머 인터럽트도 차단 → CPU 영원히 독점 → 시스템 먹통
[모드 구분 있을 때]
프로그램: while(true) {}
→ cli 실행 시도 → 특권 명령 → 차단
→ 타이머 인터럽트 정상 발생
→ 커널이 강제 선점 → 다른 프로세스에 CPU 할당
Dual Mode가 제공하는 보호 체계 종합
| 보호 대상 | 위협 | 보호 메커니즘 | 커널 모드에서만 가능한 이유 |
|---|---|---|---|
| I/O 장치 | 직접 제어로 장치 파괴 | I/O 명령어를 특권 명령으로 지정 | in/out 명령이 특권 명령 |
| 메모리 | 다른 프로세스·커널 영역 접근 | MMU + 페이지 테이블 | 페이지 테이블 수정이 특권 명령 |
| CPU | 무한루프로 독점 | 타이머 인터럽트 + 선점 스케줄링 | 인터럽트 제어가 특권 명령 |
| 커널 코드 | 시스템 콜 테이블 변조 | 커널 메모리 영역 접근 차단 | CR3 변경이 특권 명령 |
만약 단일 모드라면? — MS-DOS 사례
MS-DOS (단일 모드)
┌────────────────────────────────────┐
│ 응용 프로그램 │
│ - 하드웨어 직접 접근 가능 │
│ - 다른 프로그램 메모리 접근 가능 │
│ - 시스템 파일 자유롭게 수정 가능 │
├────────────────────────────────────┤
│ DOS 커널 │
│ - 보호 기능 없음 │
│ - 악성 프로그램에 무방비 │
└────────────────────────────────────┘
→ 바이러스가 쉽게 시스템 전체를 감염시킬 수 있었음
현대 OS (Dual Mode)
┌────────────────────────────────────┐
│ 응용 프로그램 (사용자 모드) │
│ - 제한된 권한 │
│ - 시스템 콜로만 커널 기능 사용 │
├──────────── 모드 경계 ──────────────┤
│ OS 커널 (커널 모드) │
│ - 완전한 권한 │
│ - 자원 접근을 중재·검증 │
└────────────────────────────────────┘
→ 한 프로그램의 오류가 시스템 전체에 영향을 주지 않음
Java에서 체감하는 Dual Mode의 효과
// 1. 메모리 보호 — 다른 프로세스 메모리 접근 불가
// Java에서는 포인터 자체가 없지만, C에서 임의 주소 접근 시도 시
// MMU가 차단 → Segmentation Fault
// 2. 안전한 파일 접근 — 커널이 권한 검사
try {
// 커널이 파일 권한을 확인한 후 접근 허용/거부
new FileInputStream("/etc/shadow");
} catch (IOException e) {
// 권한 없음 → 커널이 -EACCES 반환 → IOException
System.out.println("접근 거부: " + e.getMessage());
}
// 3. CPU 독점 방지 — 무한루프도 다른 프로세스에 영향 없음
new Thread(() -> {
while (true) {} // 이 스레드가 CPU를 독점해도
}).start();
// 타이머 인터럽트 → 커널이 선점 → 다른 스레드 정상 실행
System.out.println("정상 출력됨");
핵심 정리
유저모드와 커널모드를 구분하는 이유
= 신뢰할 수 없는 프로그램으로부터 시스템을 보호하기 위해
┌────────────────────────────────────────────┐
│ 1. I/O 보호 → 하드웨어 직접 접근 차단 │
│ 2. 메모리 보호 → 프로세스 간 격리 │
│ 3. CPU 보호 → 독점 방지 (타이머 인터럽트) │
│ 4. 커널 보호 → 커널 코드·데이터 변조 방지 │
└────────────────────────────────────────────┘
→ 한 프로그램의 오류나 악의가 시스템 전체에 영향을 주지 않음