콘텐츠로 바로가기

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) \rightarrow 커널 스택(Kernel Stack) 전환, 레지스터 백업, CPU 모드 플래그 변경.
  • 파라미터 전달 (Parameter Passing): 레지스터를 통한 인자 전달, 포인터 검증(Copy-from-user, Copy-to-user 보안 장벽).

Out-of-Scope

  • 하드웨어 디바이스 드라이버 로직: 하드디스크 모터 제어나 GPU 렌더링 펌웨어 자체 \rightarrow 02-05-01. Embedded Systems & Controllers 영역.
  • 멀티프로세스 스케줄링: 시스템 콜로 커널에 진입한 뒤 다른 프로세스로 CPU를 넘겨버리는 문맥 교환 이론 \rightarrow 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

Sequence Core Cluster Objective & Description Evidence (BoK)
1 Ring 0 vs Ring 3 커널(Kernel)과 사용자(User)를 나누는 하드웨어 권한 경계와 특권 명령어를 이해합니다. P1
2 The Trap (int 0x80) 사용자가 하드웨어 서비스를 요청할 때 거치는 소프트웨어 인터럽트(Trap)의 흐름을 살핍니다. P5
3 Context & Stack Swap 커널 진입 시 사용자 스택에서 커널 스택으로 전환되는 모드 스위칭 과정을 이해합니다. Industry
4 The Parameter Barrier 사용자가 전달한 포인터를 커널이 copy_from_user로 검증하고 복사하는 보안 경계를 이해합니다. Industry

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일 때만 가짜 하드웨어 콘솔에 데이터가 기록되도록 구현합니다.

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 아키텍처에 더 강하게 종속됩니다.
  • How to Learn:
    • 1단계: 개발자가 write() 함수를 부르면, C 라이브러리(libc)가 CPU의 EAX 레지스터에 시스템 콜 번호(4번)를 넣고 EBX, ECX에 버퍼 포인터와 길이를 배치하는 래퍼(Wrapper) 역할을 확인합니다.
    • 2단계: 레지스터 설정이 끝나면 libc가 syscall 또는 int 0x80 명령을 실행하고, CPU가 사용자 모드에서 커널 모드(Ring 0)로 전환해 시스템 콜 테이블의 4번 주소(sys_write)로 이동하는 흐름을 추적합니다.
  • 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로 낮춘 뒤 복귀하는 흐름을 살핍니다.
  • 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 같은 방식이 사용됩니다.
  • How to Learn:
    • 1단계: 악의적인 사용자가 write(fd, 0xC0000000, 100)처럼 커널 전용 영역을 가리키는 주소를 전달했을 때, 커널이 이 주소가 Ring 3 사용자 공간에 속하는지 경계(Boundary) 검사를 수행하고 거부하는 과정을 확인합니다.
    • 2단계: 검사를 통과해도 사용자 포인터가 가리키는 주소가 실제로 메모리에 올라와 있지 않을 수(Page Fault) 있으므로, 커널이 직접 포인터를 역참조하지 않고 copy_from_user() 안에서 데이터를 커널 버퍼로 복사하는 흐름을 살핍니다.
  • Implement: System_Call_Write(user_ptr, size) 함수의 파이썬 구현체를 만듭니다. user_ptr 값이 0x8000_0000 이상(커널 스페이스 영역)이면 return -EFAULT (Bad Address)를 반환하고, 정상 주소 범위일 때만 Kernel_Buffer 리스트로 데이터를 복사(Copy)합니다.

7. Terminology

Term (EN / ko, abbr) 1문장 정의 단계(기본/권장/실무/심화) 역할/맥락 관련 개념 유사/대비/함께 사용 오해 포인트 Evidence(Primary/Secondary/Industry) Flags(core)
System Call 사용자 모드 프로그램이 커널에 특정 서비스를 요청하기 위해 사용하는 하드웨어 게이트 기법입니다. 기본 사용자 인터페이스 API / Trap Library Call '단순 함수'가 아닌 권한 경계 진입 P1:CS2023 core
Privilege Level CPU가 현재 실행 중인 코드의 동작 범위를 제한하기 위해 사용하는 하드웨어 상태 값입니다. 기본 하드웨어 보안 Ring 0 / CPL Mode 소프트웨어 설정이 아닌 CPU 상태 값 P3:CyBOK core
Trap 시스템 콜이나 프로그램 오류 시 하드웨어가 미리 정의된 커널 코드로 이동하는 이벤트입니다. 추천 실행권 이양 Interrupt / Fault Exception '에러'뿐만 아니라 '의도된 진입' 포함 P1:CS2023 core
Mode Switch CPU의 동작 상태가 권한이 낮은 모드에서 높은 모드로(또는 반대로) 바뀌는 전환 과정입니다. 실무 성능 오버헤드 Context / Register Context Switch '프로세스 교체'와는 다른 '권한 교체' P2:SWEBOK core

8. References

Primary

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' 공격의 방어 기작을 기술할 수 있는가?

OS Kernel Architecture & Interface

3 / 4