System Call Interface & Privilege Switching
사용자 프로그램이 하드웨어 자원을 요청할 때 거치는 공식 관문인 시스템 콜의 생성 원리와, CPU 실행 권한을 전환하는 트랩 메커니즘을 다루는 학습 노드입니다.
Article
M
Me
hyunyoun's Blog
operating-systems-system-mechanicsoperating-systemssystem-mechanicskernelsystem-interface-physicssystem-call-interfaceprivilege-switchingos-kernel-architecture9 min read
1. Overview
시스템 콜 인터페이스와 특권 전환(System Call Interface & Privilege Switching)은 사용자 프로그램(User Program)이 디스크, 네트워크, 메모리 같은 하드웨어 자원을 직접 다루지 못하도록 하고, 필요한 작업을 커널(Kernel)에 안전하게 요청하게 만드는 운영체제의 공식 경계면입니다.
학습자는 사용자 앱이 직접 디스크를 읽으려 할 때 보호 모드(Protected Mode)의 **권한 링(Ring 0 vs Ring 3)**이 어떻게 접근을 제한하는지 살핍니다. 이어 open(), read() 같은 C 함수들이 내부적으로 인터럽트 명령(int 0x80 또는 syscall)을 통해 커널 모드로 진입하고, 하드웨어 작업 결과를 다시 사용자 공간으로 돌려받는 모드 스위칭(Mode Switching)의 어셈블리 흐름을 이해합니다.
2. Scope & Boundaries
In-Scope
- 권한 계층 (Privilege Rings): Ring 0(커널 모드)와 Ring 3(유저 모드)의 CPU 보호 격리, 특권 명령어(Privileged Instructions).
- 인터페이스 궤적 (Interface Mechanics): POSIX API (libc 래퍼), 소프트웨어 인터럽트(Software Interrupt), 고속 시스템 콜(
sysenter,syscall). - 모드 스위칭 (Mode Switching): 유저 스택(User Stack) 커널 스택(Kernel Stack) 전환, 레지스터 백업, CPU 모드 플래그 변경.
- 파라미터 전달 (Parameter Passing): 레지스터를 통한 인자 전달, 포인터 검증(Copy-from-user, Copy-to-user 보안 장벽).
Out-of-Scope
- 하드웨어 디바이스 드라이버 로직: 하드디스크 모터 제어나 GPU 렌더링 펌웨어 자체 02-05-01. Embedded Systems & Controllers 영역.
- 멀티프로세스 스케줄링: 시스템 콜로 커널에 진입한 뒤 다른 프로세스로 CPU를 넘겨버리는 문맥 교환 이론 03-02-03. CPU Scheduling Algorithms 영역.
Boundaries
- Mode Switch vs. Context Switch (03-02-01): 모드 스위치(System Call)는 태스크 A가 사용자 모드에서 커널 모드로 전환해 자기 작업을 계속 수행하는 과정입니다. 반면 컨텍스트 스위치(03-02-01)는 태스크 A의 실행 문맥을 저장하고 태스크 B의 문맥을 CPU에 올리는 완전히 다른 실행 흐름으로의 전환입니다. 일반적으로 모드 스위치가 더 가볍습니다.
3. Counterexample
- 직접 하드웨어 조작의 오해 (Bypassing Kernel Trap): C 코드에서 속도를 높이려고 포인터를 하드디스크의 물리 레지스터
0x8000번지에 직접 연결해*ptr = data;로 쓰려는 접근은 사용자 모드(Ring 3)에서 허용되지 않습니다. 최신 CPU는 특권 메모리 접근 시 트랩(Trap, Segmentation Fault)을 발생시켜 해당 프로세스를 종료(Kill)합니다. 리눅스 환경에서 하드웨어 조작은 커널(Ring 0)을 통해서만 수행되며, 사용자 프로그램은 시스템 콜을 사용해야 합니다. - 버퍼 검증 없는 포인터 신뢰 (Blind Pointer Dereference): 시스템 콜을 직접 구현할 때(Kernel Module), 사용자가 전달한 구조체 포인터 주소(
char *buf)를 커널 내부에서 바로 역참조(Dereference)하면 보안 문제가 생깁니다. 악의적인 사용자가buf주소를 커널 전용 메모리 영역인0xC0000000으로 조작해 전달하면, 커널 정보가 사용자 공간으로 노출될 수 있습니다. 시스템 콜은copy_from_user()같은 검증 경로를 거쳐 사용자 메모리만 복사해야 합니다.
4. Prerequisites
- 어셈블리 레지스터 구조 (Basic): 레지스터
eax에 번호를 넣고 인터럽트를 부른다는 개념을 위해 CPU 구조 기초가 필요합니다. (02-01-02 CPU Architecture) - 운영체제의 메모리 격리 (Recommended): 커널 메모리와 사용자 메모리가 어떻게 나뉘어 있는지 가상 메모리 구조를 알아야 합니다. (03-03-01 Virtual Memory)
5. Learning Map
6. Learning Topics
Basic
Core Topic 01: 하드웨어 권한 경계, Ring 0와 Ring 3 (Privilege Rings)
- Why to Learn: 잘못된 C 코드가 무한 루프를 돌거나 메모리를 잘못 다뤄도 시스템 전체가 멈추지 않고 해당 프로세스만 종료할 수 있는 CPU 권한 구조를 이해하기 위해서입니다.
- What to Learn:
- Concepts: 권한 링(Protection Rings), 커널 모드(Ring 0 / Supervisor), 유저 모드(Ring 3), 특권 명령어(Privileged Instruction).
- Skills: CPU 상태 레지스터(CPL, Current Privilege Level) 파악.
- Tools: 리눅스 커널 패닉 vs 유저 Segfault 로그.
- Trade-offs: 모든 권한을 커널 모드 하나로 통일하면 권한 체크 비용은 줄지만, 애플리케이션 결함이 시스템 전체 장애로 이어질 수 있습니다. Ring 0~3로 권한 경계를 두면 멀티태스킹 샌드박스가 가능하지만 권한 경계를 넘을 때마다 스위칭 오버헤드가 발생합니다.
- How to Learn:
- 1단계: CPU의 권한 상태(CPL)가 3일 때 하드디스크 I/O Port 제어나 메모리 테이블 변경(CR3 레지스터) 같은 특권 명령어를 실행하면 General Protection Fault가 발생하는 이유를 확인합니다.
- 2단계: 웹 브라우저가 디스크에 파일을 저장하려면 직접 디스크 핀을 조작하는 대신, CPL 0에서 실행되는 커널에 시스템 콜(System Call)로 작업을 요청해야 하는 구조를 살핍니다.
- Implement: 파이썬
CPU객체 시뮬레이터를 만듭니다.CPL = 3상태에서CPU.execute("OUT 0x80, DATA")(특권 I/O 명령)을 호출하면Exception: GPF (Ring 3 cannot execute OUT)를 출력하고,CPL = 0일 때만 가짜 하드웨어 콘솔에 데이터가 기록되도록 구현합니다.
Recommended
Core Topic 02: 소프트웨어 트랩과 시스템 콜 (Software Trap & Syscall)
- Why to Learn:
printf("Hello")같은 코드가 화면 출력으로 이어질 때, 내부에서 어떻게 Trap을 통해 커널 모드로 진입하는지 이해하기 위해서입니다. - What to Learn:
- Concepts: 트랩(Trap), 소프트웨어 인터럽트(
int 0x80), 고속 시스템 콜(syscall,sysenter), libc(C 표준 라이브러리 래퍼). - Skills: 시스템 콜 번호(System Call Number) 맵핑(ex:
sys_write = 4), 레지스터 세팅. - Tools: 리눅스
strace유틸리티. - Trade-offs: 과거의
int 0x80방식은 인터럽트 게이트를 거치므로 오버헤드가 크지만 범용성이 좋습니다. 최신 CPU의syscall명령어는 더 빠른 커널 진입 경로를 제공하지만 x86-64 아키텍처에 더 강하게 종속됩니다.
- Concepts: 트랩(Trap), 소프트웨어 인터럽트(
- How to Learn:
- 1단계: 개발자가
write()함수를 부르면, C 라이브러리(libc)가 CPU의EAX레지스터에 시스템 콜 번호(4번)를 넣고EBX, ECX에 버퍼 포인터와 길이를 배치하는 래퍼(Wrapper) 역할을 확인합니다. - 2단계: 레지스터 설정이 끝나면 libc가
syscall또는int 0x80명령을 실행하고, CPU가 사용자 모드에서 커널 모드(Ring 0)로 전환해 시스템 콜 테이블의 4번 주소(sys_write)로 이동하는 흐름을 추적합니다.
- 1단계: 개발자가
- Implement: C/C++ 소스코드(
hello.c) 컴파일 파일에 대해strace ./hello명령을 실행하여, 프로그램이 내부적으로execve,mmap,write(1, "Hello", 5)같은 시스템 콜을 호출하는 과정을 관찰합니다. 필요하면 파이썬으로strace형태의 텍스트 트레이서를 모사합니다.
Practical
Core Topic 03: 모드 스위칭과 스택 교체 (Mode Switching & Stack Swap)
- Why to Learn: 커널에 진입할 때 사용자 앱이 쓰던 스택(Stack)과 커널 전용 스택이 어떻게 분리되고, 실행 문맥이 어떻게 저장·복원되는지 이해하기 위해서입니다.
- What to Learn:
- Concepts: 모드 스위치(Mode Switch), 유저 스택(User Stack) vs 커널 스택(Kernel Stack), 레지스터 백업(Save/Restore).
- Skills: 커널 스택 오버플로우 방어(8KB 한계), 링 트랜지션(Ring Transition) 딜레이.
- Tools: 어셈블리
SAVE_ALL,RESTORE_ALL매크로. - Trade-offs: 커널에 진입할 때 CPU 레지스터를 커널 스택에 저장(Push)하고 다시 복원(Pop)하면 원래 코드로 안전하게 돌아올 수 있습니다. 하지만 짧은 시스템 콜이 매우 자주 발생하면 저장·복원 비용이 레이턴시로 누적됩니다.
- How to Learn:
- 1단계: 사용자 프로그램이 커널에 들어오면 커널은 사용자 스택 주소(
ESP) 사용을 중지하고, 프로세스마다 할당된 커널 스택으로 전환합니다. 이때 하드웨어 스위치(TSS참조)가 어떤 역할을 하는지 확인합니다. - 2단계: 커널 작업이 끝나고 사용자 모드로 돌아갈 때(
iret또는sysret), 백업해 둔 사용자 레지스터와 스택 주소를 복원하고 권한을 Ring 3로 낮춘 뒤 복귀하는 흐름을 살핍니다.
- 1단계: 사용자 프로그램이 커널에 들어오면 커널은 사용자 스택 주소(
- Implement:
User_Task객체가System_Call()을 호출했을 때,User_Stack_Ptr와 5개의Register값을Kernel_Stack리스트에append(백업)하고, 커널 작업을 수행(Print)한 뒤 역순으로pop(복구)해Instruction_Pointer를 재개하는 시뮬레이터를 만듭니다.
Advanced
Core Topic 04: 커널-사용자 메모리 장벽과 포인터 검증 (Parameter Passing & Validation)
- Why to Learn: 사용자가 전달한 메모리 포인터 주소를 커널이 그대로 믿으면 커널 메모리 노출이나 권한 상승 취약점으로 이어질 수 있으므로, 포인터 검증과 안전한 복사 경로를 이해하기 위해서입니다.
- What to Learn:
- Concepts:
copy_from_user(),copy_to_user(), 페이지 결함(Page Fault), 포인터 유효성 검증(Pointer Validation). - Skills: 메모리 스매싱 방어, 커널 패닉 핸들링.
- Tools: 리눅스 VFS 레이어 구조 분석.
- Trade-offs: 사용자 메모리를 커널 내부 버퍼로 복사(Copy)하면 보안 경계는 명확해지지만, 큰 파일을 다룰 때 메모리 복사 비용이 커질 수 있습니다. 이를 줄이기 위해
mmap같은 방식이 사용됩니다.
- Concepts:
- How to Learn:
- 1단계: 악의적인 사용자가
write(fd, 0xC0000000, 100)처럼 커널 전용 영역을 가리키는 주소를 전달했을 때, 커널이 이 주소가 Ring 3 사용자 공간에 속하는지 경계(Boundary) 검사를 수행하고 거부하는 과정을 확인합니다. - 2단계: 검사를 통과해도 사용자 포인터가 가리키는 주소가 실제로 메모리에 올라와 있지 않을 수(Page Fault) 있으므로, 커널이 직접 포인터를 역참조하지 않고
copy_from_user()안에서 데이터를 커널 버퍼로 복사하는 흐름을 살핍니다.
- 1단계: 악의적인 사용자가
- Implement:
System_Call_Write(user_ptr, size)함수의 파이썬 구현체를 만듭니다.user_ptr값이0x8000_0000이상(커널 스페이스 영역)이면return -EFAULT (Bad Address)를 반환하고, 정상 주소 범위일 때만Kernel_Buffer리스트로 데이터를 복사(Copy)합니다.
7. Terminology
8. References
Primary
- [P1] CS2023 - OS/Operating System Principles (Interface) — Core requirements.
- [P3] CyBOK v1.1 - Hardware Security / Privilege Management — Security foundations.
Secondary
- [The Linux Programming Interface] Michael Kerrisk — The definitive guide to system calls.
- [Intel 64 and IA-32 Architectures Software Developer's Manual] — Hardware switching details.
Industry
- [POSIX.1 Standard] — The industry standard for system call APIs.
- [Microsoft Windows: Internal Architecture of System Calls] — NT-based syscall mechanics.
9. Final Checklist
Primary
- 사용자 프로그램에서 하드웨어로 직접 명령을 보낼 수 없는 이유를 'Privilege Level'과 'Memory Protection' 관점에서 설명 가능한가? (P1)
- 시스템 콜이 발생했을 때 CPU가 사용자 프로세스의 현재 상태를 왜 '커널 스택'에 따로 저장해야 하는지 설명할 수 있는가? (P1)
Secondary
- 'Trap Gate'가 미리 설정되어 있지 않을 경우, 사용자가
SYSCALL명령을 내렸을 때 CPU가 어떤 오류 경로를 거치는지 설명할 수 있는가? - 대량의 데이터를
write()시스템 콜로 보낼 때, '사용자 공간 -> 커널 공간 -> 장치 드라이버'로 이어지는 데이터 복사 횟수가 성능에 미치는 영향을 도출할 수 있는가?
Industry
- 고성능 트레이딩 시스템 설계 시, 빈번한 'gettimeofday' 시스템 콜 오버헤드를 줄이기 위한 'vDSO' 활용 방안을 아키텍처 관점에서 제안할 수 있는가? (SFIA)
- 리눅스 커널 취약점 분석 시, 사용자가 조작된 포인터를 시스템 콜 인자로 넘겨 커널 메모리를 읽는 'Confused Deputy' 공격의 방어 기작을 기술할 수 있는가?