시스템 콜(System Call) 레퍼런스 (System Call Reference)

x86_64 Linux 시스템 콜 386개를 12개 카테고리(파일 I/O, 프로세스(Process), 메모리, 네트워크, 시그널, IPC, 시간, 보안, 비동기 I/O 등)로 정리합니다. 각 시스콜은 레지스터(Register) 기반 호출 규약(Calling Convention)으로 전달되며, 어셈블리(Assembly)에서 직접 호출하거나 glibc 래퍼로 접근할 수 있고 실시간(Real-time) 관련 제어 시스콜도 포함됩니다. 각 항목마다 syscall 번호, 이름, C 함수 시그니처, 한국어 설명을 제공하여 빠른 조회가 가능합니다. 동작 원리와 진입 경로는 시스템 콜 (System Call) 문서를 참고하세요.

전제 조건: 시스템 콜 (System Call) 문서를 먼저 읽으세요. SYSCALL/SYSRET 명령어, 특권 링(Privilege Ring), 진입 경로(entry_SYSCALL_64), vDSO, seccomp 등 동작 원리가 상세히 설명되어 있습니다. 이 페이지는 "무엇이 있는가"를 빠르게 조회하는 레퍼런스이며, "어떻게 동작하는가"는 해당 문서를 참고하세요.
일상 비유: 시스템 콜은 도서관 사서에게 책을 요청하는 것과 같습니다. 독자(사용자 프로그램)는 서가(하드웨어·커널 자원)에 직접 손을 댈 수 없고, 반드시 정해진 창구(syscall 인터페이스)를 통해 사서(커널)에게 부탁해야 합니다. 사서는 이용 규정(권한·유효성 검사)을 확인한 뒤 허가된 작업만 수행하고 결과를 돌려줍니다. 창구 번호(syscall 번호)가 어떤 서비스를 요청하는지 결정하고, 이름(직접 책 이름 전달)이나 주소(포인터)는 인자로 전달합니다.

핵심 요약

  • 파일 디스크립터(File Descriptor, fd) — 열린 파일·소켓·파이프를 가리키는 정수 번호. 0(stdin), 1(stdout), 2(stderr)는 기본 할당되며, 프로세스마다 독립적인 테이블로 관리됩니다.
  • errno — syscall 실패 시 커널이 rax에 넣는 음수 오류 코드. glibc 래퍼가 -errno를 errno 전역 변수에 양수로 변환하고 -1을 반환합니다. 성공 시 rax ≥ 0입니다.
  • syscall 번호 — rax 레지스터에 넣는 정수로 어떤 syscall을 호출할지 결정합니다. arch/x86/entry/syscalls/syscall_64.tbl에 정의됩니다. Linux 6.11부터 새 아키텍처용 공용 표 scripts/syscall.tbl이 도입되었지만, x86_64는 지금도 자체 syscall_64.tbl을 사용합니다.
  • 블로킹(Blocking) vs 비블로킹(Non-blocking) I/O — 블로킹은 데이터가 준비될 때까지 프로세스가 슬립합니다. 비블로킹(O_NONBLOCK)은 즉시 EAGAIN을 반환하며, epoll/poll과 함께 이벤트 루프에서 활용합니다.
  • vDSO(virtual Dynamic Shared Object) — clock_gettime 등 자주 호출되는 읽기 전용 syscall을 커널 진입 없이 사용자 공간에서 직접 실행하는 최적화 기법. syscall 진입/복귀 오버헤드를 없애 일반 syscall보다 대체로 더 빠릅니다.

단계별 이해 — write() 한 번이 일어나는 일

  1. 프로그램이 출력을 요청합니다
    printf("hello\n")를 호출하면 glibc 내부 버퍼에 데이터가 쌓입니다. 버퍼가 가득 차거나 명시적으로 플러시(Flush)하면 write(1, buf, n) syscall로 이어집니다.
  2. glibc 래퍼가 레지스터를 설정합니다
    rax=1(write 번호), rdi=1(stdout fd), rsi=버퍼주소, rdx=n(길이)를 설정하고 SYSCALL 명령어를 실행합니다. 인자가 6개를 초과하면 구조체 포인터로 전달합니다.
  3. CPU가 커널 모드로 전환됩니다
    SYSCALL 명령어가 링 3(사용자) → 링 0(커널)으로 특권을 상승시키고 entry_SYSCALL_64로 점프합니다. 커널은 sys_call_table[1]에서 sys_write() 함수 포인터를 찾아 호출합니다.
  4. 커널이 작업을 수행합니다
    sys_write()가 사용자 버퍼를 검증(copy_from_user)하고, VFS를 거쳐 페이지 캐시(Page Cache)에 데이터를 기록합니다. 실제 스토리지 쓰기는 보통 비동기로 수행됩니다(writeback 스레드).
  5. 커널이 결과를 반환합니다
    실제로 쓴 바이트 수를 rax에 넣고 SYSRET으로 사용자 공간에 복귀합니다. 반환값이 요청보다 적으면(부분 쓰기) 루프로 재시도해야 합니다. rax가 음수이면 glibc가 errno = -rax로 설정합니다.
참고: 이 페이지(Page)는 "무엇이 있는가"를 다루는 레퍼런스입니다. "어떻게 동작하는가"(SYSCALL/SYSRET 진입 경로, SYSCALL_DEFINE, vDSO, seccomp 등)는 시스템 콜 (System Call)을 참고하세요. syscall 번호는 arch/x86/entry/syscalls/syscall_64.tbl(Linux 7.3 기준, x86_64) 기준이며 커널 버전에 따라 달라질 수 있습니다. 7.0에서 rseq_slice_yield(471)가, 7.3에서 fchroot(472)가 추가되었습니다.

개요

사용자 프로그램은 CPU의 특권 링 3(링 3, Ring 3)에서 실행되며 하드웨어·메모리·파일 등 운영체제 자원에 직접 접근할 수 없습니다. 커널은 이러한 자원을 보호하고 여러 프로세스 간 안전한 공유를 위해 특권 링 0(링 0, Ring 0)에서 실행됩니다. 시스템 콜(System Call)은 사용자 공간에서 커널 서비스를 요청하는 유일하게 허가된 경계 통과 방법입니다 — 사용자 프로그램이 링 3에서 링 0 기능이 필요할 때마다 SYSCALL 명령어를 통해 커널에 요청하고, 커널이 검증 후 처리한 뒤 SYSRET으로 복귀합니다. 동작 원리의 상세 설명은 시스템 콜 (System Call)을 참고하세요.

x86_64 Linux 커널에는 386개의 시스템 콜이 정의되어 있습니다. 번호는 0~472 범위에 할당되어 있으나 337~423 구간은 비어 있어 실제 항목 수는 386개입니다. 최신 mainline인 Linux 7.3(2026년 10월 19일 릴리스)에서 번호 472까지 할당되었고 fchroot가 마지막 항목입니다. 7.0에서 rseq_slice_yield(471)가 추가된 뒤 7.1·7.2에서는 번호가 늘지 않았습니다. Linux 6.11부터 새 아키텍처의 번호는 공용 표 scripts/syscall.tbl로 관리되며, 각 아키텍처의 arch/<arch>/kernel/Makefile.syscalls가 syscall_abis_* 변수로 이 표의 abis 필드를 골라 테이블·헤더를 생성합니다. x86_64는 이 공용 표를 쓰지 않고 arch/x86/entry/syscalls/syscall_64.tbl을 그대로 유지합니다. 이 페이지의 표에는 386개 고유 번호를 빠짐없이 실었습니다(391행, 중복 게재 5개). 아래 카테고리별 분포와 호출 규약을 참고하세요.

최근 추가 (2023-2026): futex_wake/futex_wait/futex_requeue(6.7, 454~456), statmount/listmount(6.8, 457~458), lsm_get_self_attr/lsm_set_self_attr/lsm_list_modules(6.8, 459~461), mseal(6.10, 462), setxattrat/getxattrat/listxattrat/removexattrat(6.13, 463~466), open_tree_attr(6.15, 467), file_getattr/file_setattr(6.17, 468~469), listns(6.19, 470), rseq_slice_yield(7.0, 471), fchroot(7.3, 472)가 각 카테고리에 정리되어 있습니다.
x86_64 syscall 호출 규약 — 인자 레지스터와 진입 경로 사용자 공간 (링 3) rax syscall 번호 (NR) rdi 1번째 인자 rsi 2번째 인자 rdx 3번째 인자 r10 4번째 인자 (rcx 아님) r8 5번째 인자 r9 6번째 인자 SYSCALL 명령어 링 3 → 링 0 커널 공간 (링 0) entry_SYSCALL_64 pt_regs 구성: rcx→ip, r11→flags do_syscall_64(regs, nr) syscall_enter_from_user_mode: seccomp·ptrace do_syscall_x64: 범위 검사 x64_sys_call switch 디스패치 + array_index_nospec __x64_sys_write(regs) 핸들러 regs->ax = 반환값 (실패 시 -errno) SYSRET 또는 IRET — 레지스터 상태 검사에 실패하면 IRET 경로로 복귀합니다 6개를 넘는 인자는 구조체 포인터로 전달하며, 실패 시 rax는 -errno(-4095 ~ -1)입니다. rcx·r11은 SYSCALL이 복귀 주소·RFLAGS로 덮어씁니다 — 4번째 인자에 r10을 쓰는 이유입니다.
x86_64 Linux syscall 호출 규약. rax에 번호, rdi·rsi·rdx·r10·r8·r9에 인자를 넣고 SYSCALL/SYSRET으로 링을 전환합니다 (개념 개요).
syscall 전체 흐름 — 호출부터 결과 반환까지 응용 프로그램 read(fd, buf, n) glibc 래퍼 번호·인자를 레지스터에 적재 SYSCALL 링 3 → 링 0 커널 핸들러 x64_sys_read → vfs_read SYSRET rax = 결과 직접 syscall() 호출도 가능 SYS_read 상수 사용 MSR로 진입점 전환 seccomp·ptrace 훅 통과 실패 시 -errno SYSRET 복귀 후 rax가 결과이며, 실패하면 glibc 래퍼가 errno를 설정하고 -1을 반환합니다.
응용 프로그램 호출부터 결과 반환까지의 syscall 전체 흐름입니다. glibc 래퍼가 번호와 인자를 레지스터에 적재하고, SYSCALL로 커널에 진입해 핸들러를 실행한 뒤 SYSRET으로 복귀합니다 (개념 개요).
카테고리별 시스템 콜 분포 — 12개 카테고리, 고유 번호 386개 파일 I/O 36개 파일 디스크립터 관리 11개 디렉터리 & 파일시스템 79개 프로세스 관리 58개 메모리 관리 32개 네트워크 소켓 20개 시그널 15개 IPC (프로세스 간 통신) 26개 시간 & 타이머 24개 보안 & 권한 27개 비동기 I/O & 이벤트 22개 기타 시스템 콜 41개 막대는 카테고리별 행 수(합계 391행)이며, 두 카테고리에 걸친 5개를 제외한 고유 번호는 386개입니다.
x86_64 Linux syscall 호출 규약. rax에 번호, rdi·rsi·rdx·r10·r8·r9에 인자를 넣고 SYSCALL/SYSRET으로 링을 전환합니다 (개념 개요).
카테고리대표 syscall이 페이지 섹션
파일 I/Oread, write, open, close, stat§ 파일 I/O
파일 디스크립터(File Descriptor) 관리dup, fcntl, ioctl, fsync§ FD 관리
디렉터리 & 파일시스템(Filesystem)mkdir, link, mount, statfs, openat2, fanotify_init§ 디렉터리/FS
프로세스 관리fork, clone, execve, exit, wait4§ 프로세스
메모리 관리(Memory Management)mmap, munmap, mprotect, brk§ 메모리
네트워크 소켓(Socket)socket, bind, connect, sendto§ 네트워크
시그널(Signal)kill, rt_sigaction, sigaltstack§ 시그널
IPCpipe, futex, shmget, eventfd2§ IPC
시간 & 타이머(Timer)clock_gettime, nanosleep, timerfd_create§ 시간
보안 & 권한setuid, capset, seccomp, unshare§ 보안
비동기 I/O & 이벤트epoll_create1, io_uring_setup, select§ 비동기 I/O
기타uname, getrlimit, bpf, reboot§ 기타

주요 errno 오류 코드 참조

syscall이 실패하면 커널은 -errno를 rax로 반환하고, glibc 래퍼가 errno 전역 변수에 양수 값을 설정한 뒤 -1을 반환합니다.

errno 이름번호의미자주 발생하는 syscall
EPERM1권한 없음 (Operation not permitted)setuid, capset, seccomp
ENOENT2파일/디렉터리 없음open, stat, unlink
ESRCH3프로세스 없음kill, waitpid
EINTR4시그널에 의해 중단됨read, write, nanosleep
EIO5I/O 오류read, write, fsync
ENXIO6장치 없음open (디바이스)
EACCES13접근 거부open, chmod, execve
EFAULT14잘못된 주소 (user space 포인터 문제)read, write, 대부분
EBUSY16장치/리소스 사용 중umount, rmdir
EEXIST17파일이 이미 존재함open(O_CREAT|O_EXCL), mkdir
ENOTDIR20디렉터리가 아님chdir, mkdir, openat
EISDIR21디렉터리임open(쓰기 모드), unlink
EINVAL22잘못된 인자ioctl, fcntl, mmap
ENFILE23시스템 전체 fd 한계 초과open, socket
EMFILE24프로세스가 열 수 있는 fd 한계 초과open, socket, pipe
ENOTTY25터미널 장치가 아님ioctl (tty 전용 명령)
EPIPE32파이프 끊김 (읽는 쪽이 닫힘)write (파이프/소켓)
ERANGE34결과가 범위 초과getxattr, readlink
EDEADLK35잠금(Lock) 데드락 발생fcntl(F_SETLKW)
ENAMETOOLONG36경로명이 너무 김 (PATH_MAX=4096)open, stat, rename
ENOSYS38syscall이 구현되지 않음미구현/아키텍처 불일치
ENOTEMPTY39디렉터리가 비어 있지 않음rmdir
ELOOP40심볼릭 링크 순환open, stat
EAGAIN / EWOULDBLOCK11잠시 후 재시도 (비블로킹 I/O)read, accept, recv
ENOMEM12메모리 부족mmap, fork, malloc 내부
EADDRINUSE98주소(포트)가 이미 사용 중bind
ECONNREFUSED111연결 거부됨connect
ETIMEDOUT110연결 타임아웃connect, sendto
ENOBUFS / ENOMEM105/12버퍼(Buffer)/메모리 부족socket, sendmsg

syscall 기초 용어 정리

용어한 줄 설명
syscall 번호 (NR)rax에 넣는 정수. 어떤 서비스를 요청할지 결정합니다. <sys/syscall.h>의 SYS_write 등 매크로로 참조합니다.
파일 디스크립터 (fd)커널 내 struct file에 대한 프로세스별 인덱스. open()이 반환하고 close()로 해제합니다.
errno실패 시 커널이 설정하는 오류 코드. perror()나 strerror(errno)로 사람이 읽을 수 있는 메시지로 변환합니다.
블로킹 (Blocking)조건(데이터 수신, 잠금 해제 등)이 충족될 때까지 프로세스가 슬립합니다. 기본 동작입니다.
비블로킹 (Non-blocking)O_NONBLOCK 설정 시 준비되지 않으면 즉시 EAGAIN을 반환합니다. 이벤트 루프 구현에 사용합니다.
원자적 (Atomic)중간 상태 없이 완전히 성공하거나 실패합니다. O_CREAT|O_EXCL, rename() 등이 원자적 보장을 제공합니다.
부분 읽기/쓰기 (Partial I/O)요청한 바이트보다 적게 읽거나 쓸 수 있습니다. 실제 처리 바이트 수를 반환값으로 확인하고 루프로 재시도해야 합니다.
vDSO커널 진입 없이 사용자 공간에서 직접 실행되는 가상 공유 라이브러리(Shared Library). clock_gettime, gettimeofday 등이 이 경로로 가속됩니다.
AT_FDCWDopenat 등 *at() 계열 syscall에서 현재 작업 디렉터리(cwd)를 기준점으로 사용하라는 특수 상수입니다.
TOCTOU시간차 공격 (Time-Of-Check Time-Of-Use) 취약점. stat() 후 open() 사이에 파일이 교체될 수 있으므로 openat()으로 한 번에 처리합니다.

파일 I/O

모든 사용자 데이터는 결국 파일을 통해 저장·전송됩니다. Linux는 모든 것이 파일(Everything is a file) 철학을 따르므로 일반 파일뿐 아니라 소켓·파이프·디바이스·/proc 가상 파일 모두 동일한 read()/write() 인터페이스로 접근합니다. read()/write() 호출은 커널 내부에서 VFS → 페이지 캐시(Page Cache) → 파일시스템 드라이버 순으로 처리됩니다. 자세한 VFS 경로는 VFS 계층을 참고하세요.

read() 커널 내부 처리 경로 — VFS와 페이지 캐시 read(fd, buf, count) 사용자 프로그램 (링 3) ksys_read → vfs_read rw_verify_area: 권한·파일 위치 검사 new_sync_read → call_read_iter file->f_op->read_iter 디스패치 generic_file_read_iter → filemap_read 페이지 캐시에서 folio 조회 copy_folio_to_iter 커널 페이지를 사용자 buf로 복사 페이지 캐시 (Page Cache) 파일 데이터 folio 보관 파일시스템 드라이버 ext4·XFS·Btrfs 등 조회 miss 시 readahead 반환값은 복사한 바이트 수이며, 실패하면 -EFAULT·-EBADF 같은 오류 코드입니다.
read()가 사용자 공간에서 커널로 진입해 vfs_read → read_iter → filemap_read 순으로 처리되고, 페이지 캐시의 folio를 사용자 버퍼로 복사해 바이트 수를 반환하는 흐름입니다 (개념 개요).
관련 문서: VFS 계층 — VFS 연산 디스패치(Dispatch), 페이지 캐시, writeback | inode 구조 — inode/file 객체 모델 | 시스템 콜 동작 원리 | Direct I/O & Buffered I/O
번호이름시그니처설명
0readssize_t read(int fd, void *buf, size_t count)fd에서 최대 count 바이트를 읽어 buf에 저장합니다. 실제 읽은 바이트 수 반환 (0 = EOF(End of File), 음수 = 오류). 부분 읽기(partial read) 가능하므로 루프 필요.
1writessize_t write(int fd, const void *buf, size_t count)buf의 데이터를 fd에 count 바이트 씁니다. 실제 쓴 바이트 수 반환. 파이프/소켓에서 부분 쓰기(partial write) 가능. O_SYNC 없으면 페이지 캐시에 쓰고 즉시 반환합니다.
2openint open(const char *path, int flags, mode_t mode)경로명을 열고 파일 디스크립터를 반환합니다. 현재는 레거시 — openat(AT_FDCWD, ...)로 대체 구현됩니다. flags에 O_CREAT 포함 시 mode 인자 필요.
3closeint close(int fd)fd를 닫고 struct file의 참조 카운트(Reference Count)를 감소시킵니다. 마지막 참조자가 닫으면 flushing 발생. EINTR 오류 시 fd는 이미 닫혀있으므로 재시도하지 마세요.
4statint stat(const char *path, struct stat *st)경로명의 파일 메타데이터(크기, 권한, 타임스탬프, inode 번호 등)를 가져옵니다. 심볼릭 링크를 따라갑니다.
5fstatint fstat(int fd, struct stat *st)이미 열린 fd의 파일 메타데이터를 가져옵니다. 경로 조회 없이 inode에서 직접 읽으므로 stat보다 빠릅니다.
6lstatint lstat(const char *path, struct stat *st)심볼릭 링크 자체의 메타데이터를 가져옵니다. stat과 달리 링크를 따라가지 않습니다 (st_mode에서 S_ISLNK 확인 가능).
7pollint poll(struct pollfd *fds, nfds_t nfds, int timeout)여러 fd의 이벤트를 감시합니다. select보다 fd 수 제한이 없으며, 이벤트는 POLLIN/POLLOUT/POLLERR/POLLHUP 플래그로 지정합니다.
8lseekoff_t lseek(int fd, off_t offset, int whence)파일 오프셋(Offset)을 변경합니다. SEEK_SET(절대), SEEK_CUR(현재+offset), SEEK_END(파일끝+offset). 파이프/소켓에는 ESPIPE 오류 발생.
17pread64ssize_t pread64(int fd, void *buf, size_t count, off_t offset)파일 오프셋을 변경하지 않고 지정 위치에서 읽습니다. 멀티스레드 환경에서 lseek+read 대신 사용합니다 (원자적(Atomic) 위치 지정).
18pwrite64ssize_t pwrite64(int fd, const void *buf, size_t count, off_t offset)파일 오프셋을 변경하지 않고 지정 위치에 씁니다. O_APPEND 플래그와 함께 사용 시 offset이 무시됩니다.
19readvssize_t readv(int fd, const struct iovec *iov, int iovcnt)분산된 버퍼 배열(scatter)로 읽기를 수행합니다. 헤더+바디 분리 처리 시 syscall 횟수를 줄일 수 있습니다.
20writevssize_t writev(int fd, const struct iovec *iov, int iovcnt)분산된 버퍼 배열(gather)로 쓰기를 수행합니다. 소켓에서 헤더+페이로드(Payload)를 하나의 syscall로 전송할 때 유용합니다.
21accessint access(const char *pathname, int mode)pathname에 대한 접근 가능 여부를 확인합니다. mode는 F_OK 또는 R_OK·W_OK·X_OK의 조합이며, 호출 프로세스의 실제 사용자 ID(Real UID)·실제 그룹 ID 기준으로 검사합니다. 검사와 사용 사이에 상태가 바뀌는 경쟁(TOCTOU)이 있어 권한 판정 용도로는 신뢰할 수 없습니다.
40sendfilessize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count)파일을 소켓으로 zero-copy 전송합니다. 커널이 직접 파일 → 소켓 버퍼로 복사하여 유저 공간 왕복을 생략합니다. nginx/Apache의 정적 파일 전송에 사용합니다.
76truncateint truncate(const char *path, off_t length)파일 크기를 length로 자릅니다. 크게 하면 스파스 파일(hole)이 됩니다.
77ftruncateint ftruncate(int fd, off_t length)이미 열린 fd의 파일 크기를 변경합니다. 쓰기 권한으로 열려 있어야 합니다.
85creatint creat(const char *pathname, mode_t mode)O_CREAT|O_WRONLY|O_TRUNC로 open()하는 단축 형태입니다. 파일을 항상 잘라내므로 기존 내용을 보존해야 하면 open()에 O_CREAT를 직접 지정합니다.
95umaskmode_t umask(mode_t mask)새 파일·디렉터리 생성에 적용할 권한 마스크를 설정하고 이전 값을 반환합니다. 실제 권한은 요청 권한에서 마스크 비트를 제거한 값(mode & ~umask)이며, fork() 시 자식에게 상속됩니다.
162syncint sync(void)시스템 전체의 더티 페이지(Dirty Page)와 메타데이터를 디스크로 내려씁니다. fsync()가 특정 파일만 대상으로 하는 것과 달리 전역 동작이며, 호출자는 완료까지 기다립니다.
187readaheadint readahead(int fd, loff_t offset, size_t count)fd의 지정 구간을 미리 page cache로 읽어 들입니다. 이후 읽기 지연을 줄이는 용도로 사용합니다.
257openatint openat(int dirfd, const char *path, int flags, mode_t mode)dirfd를 기준으로 상대 경로의 파일을 엽니다. AT_FDCWD를 넣으면 cwd 기준. TOCTOU 취약점(Vulnerability) 방지에 권장됩니다 (POSIX.1-2008).
275splicessize_t splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags)파이프를 경유하여 두 fd 간 zero-copy 데이터 전송. sendfile보다 범용적이며 SPLICE_F_MOVE|SPLICE_F_NONBLOCK 플래그 사용.
276teessize_t tee(int fd_in, int fd_out, size_t len, unsigned int flags)파이프 간 데이터를 복제합니다 (원본 유지). 로그 분기(tee 명령어)의 기반.
277sync_file_rangeint sync_file_range(int fd, loff_t offset, loff_t nbytes, unsigned int flags)파일의 지정 구간에 대해 writeback을 시작하거나 완료를 기다립니다. SYNC_FILE_RANGE_WRITE·WAIT_* 플래그로 범위를 세밀하게 제어합니다.
278vmsplicessize_t vmsplice(int fd, const struct iovec *iov, unsigned long nr_segs, unsigned int flags)사용자 공간(User Space) 메모리 → 파이프로 zero-copy 전송. SPLICE_F_GIFT로 페이지 소유권 이전.
285fallocateint fallocate(int fd, int mode, off_t offset, off_t len)파일에 디스크 공간을 미리 할당하거나 구멍(hole)을 만듭니다. FALLOC_FL_KEEP_SIZE로 파일 크기 유지, FALLOC_FL_PUNCH_HOLE로 스파스 홀을 만듭니다.
295preadvssize_t preadv(unsigned long fd, const struct iovec *vec, unsigned long vlen, unsigned long pos_l, unsigned long pos_h)여러 버퍼에 readv처럼 읽되 파일 오프셋을 인자로 받아 fd의 위치를 변경하지 않습니다.
296pwritevssize_t pwritev(unsigned long fd, const struct iovec *vec, unsigned long vlen, unsigned long pos_l, unsigned long pos_h)여러 버퍼의 내용을 모아 쓰되 오프셋을 명시해 fd의 위치를 바꾸지 않습니다.
326copy_file_rangessize_t copy_file_range(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags)두 파일 사이에 데이터를 커널 내에서 복사합니다. Btrfs/XFS의 reflink를 활용하면 실제 복사 없이 메타데이터만 변경합니다.
327preadv2ssize_t preadv2(unsigned long fd, const struct iovec *vec, unsigned long vlen, unsigned long pos_l, unsigned long pos_h, rwf_t flags)preadv에 offset·flags를 추가한 형태로, RWF_HIPRI·RWF_DSYNC·RWF_NOWAIT 같은 힌트를 전달합니다.
328pwritev2ssize_t pwritev2(unsigned long fd, const struct iovec *vec, unsigned long vlen, unsigned long pos_l, unsigned long pos_h, rwf_t flags)pwritev에 flags를 추가해 하이브리드 폴링·동기화 완료 조건을 지정합니다.
463setxattratint setxattrat(int dirfd, const char *pathname, int at_flags, const char *name, const struct xattr_args *args, size_t size)dirfd 기준 상대 경로 또는 FD-only(AT_EMPTY_PATH)로 확장 속성(Extended Attribute)을 설정합니다 (Linux 6.13+). struct xattr_args로 값·크기·XATTR_CREATE/REPLACE를 한 번에 전달하여 syscall 6-인자 한계를 우회합니다.
464getxattratssize_t getxattrat(int dirfd, const char *pathname, int at_flags, const char *name, struct xattr_args *args, size_t size)dirfd 기준으로 확장 속성을 조회합니다 (Linux 6.13+). /proc/<pid>/fd 우회 없이 FD로 바로 xattr을 읽을 수 있어 SELinux·Smack 등 보안 모듈 도구의 race 조건을 제거합니다.
465listxattratssize_t listxattrat(int dirfd, const char *pathname, int at_flags, char *list, size_t size)dirfd 기준으로 확장 속성 이름 목록을 조회합니다 (Linux 6.13+).
466removexattratint removexattrat(int dirfd, const char *pathname, int at_flags, const char *name)dirfd 기준으로 확장 속성을 제거합니다 (Linux 6.13+).
Linux 6.18 fallocate 확장: FALLOC_FL_WRITE_ZEROES 플래그가 추가되어 SCSI WRITE SAME·NVMe Write Zeroes 명령을 커널이 표준 경로로 발행합니다. 기존 FALLOC_FL_ZERO_RANGE가 파일시스템별 구현에 의존한 반면, 새 플래그는 디바이스가 지원하면 실제 쓰기 없이 "영역을 0으로 채운다"는 의도를 그대로 전달합니다.

open() / openat() 플래그 (flags 인자)

플래그값(8진수)설명
O_RDONLY0읽기 전용(Read-Only)으로 엽니다.
O_WRONLY01쓰기 전용으로 엽니다.
O_RDWR02읽기/쓰기 모두 가능하게 엽니다.
O_CREAT0100파일이 없으면 생성합니다. mode 인자로 권한을 지정합니다.
O_EXCL0200O_CREAT와 함께 사용 시 파일이 이미 있으면 EEXIST로 실패합니다 (원자적 생성).
O_TRUNC01000파일을 열면서 길이를 0으로 자릅니다.
O_APPEND02000쓸 때마다 파일 끝으로 이동합니다 (원자적, 로그 파일에 적합).
O_NONBLOCK04000비블로킹 모드로 엽니다. 데이터 없을 때 EAGAIN 반환.
O_SYNC04010000write마다 스토리지에 동기적으로 플러시(Flush)합니다 (데이터+메타데이터).
O_DSYNC010000데이터만 동기적으로 플러시합니다 (메타데이터 제외, O_SYNC보다 빠름).
O_CLOEXEC02000000execve() 시 fd를 자동으로 닫습니다 (fd 누수 방지, 권장).
O_DIRECTORY0200000디렉터리만 열고, 파일이면 ENOTDIR 반환합니다.
O_NOFOLLOW0400000심볼릭 링크를 따라가지 않습니다 (보안 목적).
O_TMPFILE020200000이름 없는 임시 파일을 생성합니다. linkat()로 나중에 이름을 붙일 수 있습니다.
O_PATH010000000파일을 열지 않고 경로 참조용 fd만 얻습니다 (fstat, openat 등에만 사용 가능).
O_DIRECT040000페이지 캐시를 우회하여 직접 I/O를 수행합니다. 정렬 제약 있음.

기본 파일 I/O 패턴

/* open → read → write → close 기본 패턴 */
int fd = openat(AT_FDCWD, "file.txt", O_RDONLY | O_CLOEXEC);
if (fd < 0) { perror("openat"); exit(1); }

char buf[4096];
ssize_t n;
while ((n = read(fd, buf, sizeof(buf))) > 0) {
    /* 부분 쓰기 처리: write는 요청보다 적게 쓸 수 있음 */
    ssize_t written = 0;
    while (written < n) {
        ssize_t w = write(STDOUT_FILENO, buf + written, n - written);
        if (w < 0) { perror("write"); break; }
        written += w;
    }
}
if (n < 0) perror("read");
close(fd);   /* EINTR에도 fd는 닫혀있으므로 재시도 금지 */

/* sendfile: 파일 → 소켓 zero-copy */
off_t off = 0;
sendfile(sock_fd, file_fd, &off, file_size);

/* pread/pwrite: 멀티스레드에서 안전한 위치 지정 I/O */
ssize_t r = pread64(fd, buf, 512, offset);  /* lseek 불필요 */

write() 커널 내부 경로

write() 커널 내부 처리 경로 — VFS와 페이지 캐시 write(fd, buf, count) 사용자 프로그램 (링 3) ksys_write → vfs_write rw_verify_area + file_start_write new_sync_write → call_write_iter file->f_op->write_iter 디스패치 generic_file_write_iter generic_perform_write: iov_iter 복사 페이지 캐시 folio에 기록 dirty 표시 후 바이트 수 반환 페이지 캐시 (Page Cache) dirty folio 누적 writeback (kworker) 블록 디바이스로 지연 기록 기록 dirty 페이지 flush write()는 캐시에 복사한 뒤 반환하며, 디스크 기록은 이후 writeback이 수행합니다.
write()가 vfs_write → write_iter → generic_perform_write 순으로 페이지 캐시에 데이터를 복사하고 dirty로 표시하면, 이후 writeback이 블록 디바이스로 기록하는 흐름입니다 (개념 개요).
흔한 실수:
  • 부분 읽기/쓰기 미처리 — read()/write()는 요청보다 적게 처리할 수 있습니다. 반드시 루프로 전체 바이트를 처리하세요.
  • close() 후 EINTR 재시도 — close()가 EINTR을 반환해도 fd는 이미 닫혀있습니다. 재시도하면 다른 스레드(Thread)가 열어둔 fd를 닫을 위험이 있습니다.
  • O_APPEND 없이 다중 프로세스 로그 쓰기 — 여러 프로세스가 같은 파일에 쓸 때 O_APPEND 없으면 데이터가 뒤섞입니다.
  • sendfile의 in_fd 제약 — in_fd는 반드시 mmap() 가능한 파일이어야 합니다 (파이프/소켓 불가).

파일 디스크립터 관리

파일 디스크립터(fd)는 단순한 정수이지만, 그 뒤에는 커널 내부의 복잡한 자료구조 계층이 있습니다: fd → struct file(파일 오프셋·플래그·참조 카운트) → struct inode(메타데이터·실제 데이터 위치) → 블록 장치(Block Device). 프로세스마다 고유한 fd 테이블을 가지며 0(stdin), 1(stdout), 2(stderr)는 기본 할당됩니다. fd 관리 syscall을 이해하면 셸 리다이렉션(2>&1은 내부에서 dup2(2, 1)), 파이프라인(Pipeline)(pipe() 후 자식에서 dup2()), fd 누수(Leak) 방지(O_CLOEXEC로 exec 시 자동 닫기), 멀티스레드 안전 복제(dup3·F_DUPFD_CLOEXEC의 원자적 처리)를 올바르게 구현할 수 있습니다. fork() 시 fd 테이블이 복사되고, execve() 시 O_CLOEXEC 설정된 fd는 자동으로 닫힙니다.

파일 디스크립터 테이블 구조 — fd에서 블록 장치까지 fd 정수 = fd_array 인덱스 fd 테이블 files_struct.fdtab struct file f_pos·f_flags·f_count struct inode 메타데이터·데이터 위치 블록 장치 실제 데이터 fd 0 stdin fd 1 stdout fd 2 stderr fd 3 파일 A fd 4 빈 슬롯 fd는 fd_array의 인덱스이며, 각 항목은 struct file을 가리킵니다 fork()는 테이블을 복사하고, execve()는 O_CLOEXEC fd를 자동으로 닫습니다
fd 정수는 files_struct.fdtab.fd_array의 인덱스이고, 항목이 struct file → struct inode → 블록 장치로 이어지는 계층 구조입니다. 0·1·2는 기본 할당되며 O_CLOEXEC fd는 execve() 시 닫힙니다 (개념 개요).
번호이름시그니처설명
16ioctlint ioctl(int fd, unsigned long request, ...)디바이스 드라이버와 특수 파일에 대한 제어 명령을 전달합니다. 파일시스템(FIOCLEX, FIONREAD), 터미널(TIOCGWINSZ), 네트워크(SIOCGIFADDR), 블록장치(BLKGETSIZE64) 등에 광범위하게 사용됩니다.
32dupint dup(int oldfd)fd를 복제하여 사용 가능한 가장 낮은 번호의 새 fd를 반환합니다. 두 fd는 같은 struct file을 참조하므로 f_pos와 플래그를 공유합니다.
33dup2int dup2(int oldfd, int newfd)oldfd를 지정한 newfd로 복제합니다. newfd가 이미 열려있으면 원자적으로 닫고 덮어씁니다. 셸 리다이렉션(2>&1)에 사용합니다.
72fcntlint fcntl(int fd, int cmd, ...)fd의 속성 조회/변경(F_GETFL/F_SETFL), fd 플래그(F_GETFD/F_SETFD), fd 복제(F_DUPFD), POSIX 파일 잠금(File Lock)(F_SETLK/F_GETLK), 시그널(F_SETOWN/F_SETSIG) 등 다용도 제어 syscall입니다.
73flockint flock(int fd, int operation)파일 전체에 advisory 잠금(LOCK_SH=공유/LOCK_EX=배타/LOCK_UN=해제)을 설정합니다. NFS에서는 동작하지 않습니다. LOCK_NB로 비블로킹 시도 가능.
74fsyncint fsync(int fd)파일의 데이터와 메타데이터(크기, 타임스탬프 등)를 스토리지에 플러시합니다. 데이터베이스의 내구성(durability) 보장에 필수입니다.
75fdatasyncint fdatasync(int fd)데이터만 스토리지에 플러시합니다 (크기 변경이 없으면 메타데이터 플러시 생략). fsync보다 빠르고, 저널 기반 파일시스템에서 특히 효율적입니다.
221fadvise64int fadvise64(int fd, off_t offset, off_t len, int advice)파일 접근 패턴을 커널에 힌트로 제공합니다. POSIX_FADV_SEQUENTIAL(readahead 증가), POSIX_FADV_RANDOM(readahead 끄기), POSIX_FADV_DONTNEED(페이지 캐시 해제).
292dup3int dup3(int oldfd, int newfd, int flags)dup2의 확장으로 O_CLOEXEC 플래그를 원자적으로 설정합니다. oldfd==newfd이면 EINVAL 반환합니다 (dup2와 차이점).
319memfd_createint memfd_create(const char *name, unsigned int flags)이름 없는 익명 파일을 생성합니다. tmpfs 기반이며 ftruncate+mmap으로 공유 메모리로 활용합니다 (MFD_CLOEXEC, MFD_ALLOW_SEALING).
436close_rangeint close_range(unsigned int fd, unsigned int max_fd, unsigned int flags)fd 번호 범위를 한 번에 닫습니다. CLOSE_RANGE_CLOEXEC·CLOSE_RANGE_UNSHARE 플래그로 exec 시 자동 닫기나 테이블 분리를 지정합니다.

fcntl() 주요 명령 (cmd 인자)

cmd설명
F_DUPFDarg 이상의 가장 낮은 번호로 fd를 복제합니다.
F_DUPFD_CLOEXECF_DUPFD + O_CLOEXEC 플래그를 원자적으로 설정합니다.
F_GETFDfd 플래그(FD_CLOEXEC) 를 가져옵니다.
F_SETFDfd 플래그를 설정합니다. arg에 FD_CLOEXEC=1 또는 0.
F_GETFL파일 상태 플래그(O_NONBLOCK, O_APPEND 등)를 가져옵니다.
F_SETFL파일 상태 플래그를 변경합니다. O_NONBLOCK, O_ASYNC만 변경 가능.
F_GETLK파일 잠금 상태를 확인합니다 (POSIX advisory lock).
F_SETLK파일 잠금을 설정/해제합니다. 즉시 실패 가능 (비블로킹).
F_SETLKW파일 잠금을 설정합니다. 잠금 가능할 때까지 대기합니다 (블로킹).
F_OFD_SETLKOpen File Description 잠금 설정 (Linux 3.15+, 스레드(Thread) 간 안전).
F_SETOWNSIGIO/SIGURG를 받을 프로세스/그룹을 설정합니다.
F_SETSIG비동기 I/O 알림에 사용할 시그널 번호를 변경합니다.
F_ADD_SEALSmemfd에 sealing을 추가합니다 (F_SEAL_WRITE 등, 불변성 보장).

디렉터리 & 파일시스템

파일시스템(Filesystem)은 파일과 디렉터리의 계층 구조를 디스크에 저장하고 조회하는 방법을 정의합니다. Linux는 VFS(Virtual File System) 추상화 계층을 통해 ext4·Btrfs·XFS·NFS 등 다양한 파일시스템을 단일 인터페이스로 지원합니다. 디렉터리 항목(dentry)은 파일 이름과 inode 번호의 매핑이며, 하드 링크(Hard Link)는 같은 inode를 가리키는 여러 이름, 심볼릭 링크(Symbolic Link)는 다른 경로를 가리키는 파일입니다. 경로 기반 syscall보다 *at() 변형(openat, linkat, mkdirat, renameat2 등)이 TOCTOU 경쟁 조건(Race Condition)을 방지하고 O_CLOEXEC를 원자적으로 설정할 수 있어 보안이 중요한 코드에서 권장됩니다. 마운트(Mount)는 특정 디렉터리(마운트 포인트)에 파일시스템을 연결하는 작업으로, CAP_SYS_ADMIN 권한 또는 사용자 네임스페이스가 필요합니다.

관련 문서: VFS 계층 — namei 경로 탐색, dentry 캐시(Cache) | ext4 파일시스템 | Btrfs 파일시스템
Unix 파일 권한 비트 — 특수 비트 3개와 rwx 9비트 setuid 4000 setgid 2000 sticky 1000 r 400 w 200 x 100 r 040 w 020 x 010 r 004 w 002 x 001 특수 비트 소유자 (Owner) 그룹 (Group) 기타 (Other) 예) 4755 → -rwsr-xr-x setuid·setgid는 실행 시 파일 소유자·그룹 권한으로 동작합니다. sticky는 디렉터리에서 파일 소유자·디렉터리 소유자·root만 삭제할 수 있게 합니다 (/tmp). 8진수 한 자리가 rwx 3비트에 대응하며, 맨 앞자리가 특수 비트입니다.
12비트 권한 구조입니다. 앞 3비트가 setuid·setgid·sticky이고, 이어서 소유자·그룹·기타의 rwx 3비트가 각각 8진수 한 자리를 이룹니다 (개념 개요).

하드 링크 vs 심볼릭 링크 비교

특성하드 링크 (link)심볼릭 링크 (symlink)
inode원본과 동일한 inode 공유별도 inode 생성 (파일 타입: S_IFLNK)
파일시스템 경계동일 파일시스템 내에서만 가능다른 파일시스템, 다른 마운트도 가능
디렉터리 링크불가 (슈퍼유저도 기본 금지)가능 (디렉터리 심링크 생성 가능)
원본 삭제 시링크 카운트 감소, 0이 되면 inode 삭제dangling symlink (깨진 링크)
stat() 결과원본과 동일한 크기/inode 번호링크 파일 자체의 정보 (lstat)
권한 변경chmod 효과 동일하게 적용chmod는 target에 적용 (링크 자체는 lchown)
용도백업, 중복 파일 참조 (같은 파티션)경로 별명, 버전 관리(/usr/bin/python)

mount() 주요 플래그

플래그값설명
MS_RDONLY1읽기 전용으로 마운트
MS_NOSUID2setuid/setgid 비트 무시
MS_NODEV4장치 파일 접근 금지
MS_NOEXEC8실행 파일 실행 금지
MS_SYNCHRONOUS16모든 쓰기를 동기식으로
MS_REMOUNT32기존 마운트 옵션 변경
MS_BIND4096바인드 마운트(Bind Mount) (디렉터리를 다른 위치에 노출)
MS_SHARED1<<20피어 그룹과 마운트 이벤트를 공유 (컨테이너(Container) 네트워크)
MS_SLAVE1<<19상위에서만 전파받고 하위로는 전파 안함
MS_PRIVATE1<<18마운트 이벤트 전파 없음 (완전 격리(Isolation))
MS_NOATIME1024접근 시각(atime) 업데이트 안함 (성능 향상)
MS_STRICTATIME1<<24atime을 POSIX 표준대로 항상 업데이트
번호이름시그니처설명
78getdentsint getdents(unsigned int fd, struct linux_dirent *dirp, unsigned int count)디렉터리 fd에서 항목을 읽는 원시 syscall입니다. 64비트 환경에서는 d_ino·d_off 폭이 다른 구조체를 쓰므로 getdents64(217)를 사용합니다. glibc readdir()는 getdents64를 직접 호출합니다.
79getcwdchar *getcwd(char *buf, size_t size)현재 작업 디렉터리의 절대 경로를 가져옵니다. /proc/self/cwd 심볼릭 링크로도 확인 가능합니다.
80chdirint chdir(const char *path)현재 작업 디렉터리를 변경합니다. fchdir(fd)로도 가능하며, chroot 환경에서는 제한됩니다.
81fchdirint fchdir(int fd)열린 디렉터리 fd를 기준으로 작업 디렉터리를 변경합니다. 경로 기반보다 안전합니다.
82renameint rename(const char *oldpath, const char *newpath)파일이나 디렉터리 이름을 원자적으로 변경합니다. 같은 파일시스템 내에서만 가능하며, 대상이 존재하면 교체합니다.
83mkdirint mkdir(const char *path, mode_t mode)새 디렉터리를 생성합니다. mode는 umask에 의해 마스킹됩니다 (실제 권한 = mode & ~umask).
84rmdirint rmdir(const char *path)비어 있는 디렉터리를 삭제합니다. 내용이 있으면 ENOTEMPTY를 반환합니다.
86linkint link(const char *oldpath, const char *newpath)기존 파일에 하드 링크를 생성합니다. inode 링크 카운트가 증가하며, 같은 파일시스템 내에서만 가능합니다.
87unlinkint unlink(const char *path)파일 이름을 디렉터리에서 제거하고 inode 링크 카운트를 감소시킵니다. 카운트가 0이 되고 fd 참조도 없으면 실제로 삭제됩니다.
88symlinkint symlink(const char *target, const char *linkpath)심볼릭 링크를 생성합니다. target은 상대/절대 경로 모두 가능하며, 존재하지 않는 경로도 지정할 수 있습니다.
89readlinkssize_t readlink(const char *path, char *buf, size_t bufsiz)심볼릭 링크가 가리키는 경로 문자열을 읽습니다. NUL 종료 문자가 없으므로 직접 추가해야 합니다.
90chmodint chmod(const char *path, mode_t mode)파일 권한 비트를 변경합니다. 파일 소유자 또는 CAP_FOWNER만 가능합니다.
91fchmodint fchmod(int fd, mode_t mode)열린 파일 디스크립터의 권한을 변경합니다.
92chownint chown(const char *path, uid_t owner, gid_t group)파일의 소유자와 그룹을 변경합니다. 심볼릭 링크를 따라갑니다 (링크 자체 변경은 lchown).
93fchownint fchown(unsigned int fd, uid_t user, gid_t group)열린 fd가 가리키는 파일의 소유자와 그룹을 바꿉니다.
94lchownint lchown(const char *filename, uid_t user, gid_t group)심볼릭 링크를 따라가지 않고 링크 자체의 소유자를 바꿉니다.
133mknodint mknod(const char *filename, umode_t mode, unsigned dev)경로에 디바이스 노드·FIFO·소켓 파일을 만듭니다. dirfd를 받는 mknodat(259)이 이후 추가되었습니다.
136ustatint ustat(unsigned dev, struct ustat *ubuf)마운트된 파일시스템의 통계를 struct ustat로 반환하는 레거시 콜입니다. statfs(2)와 statvfs(3)로 대체되었습니다.
137statfsint statfs(const char *path, struct statfs *buf)파일시스템의 타입, 블록 크기, 총 블록/여유 블록, inode 수 등 통계를 가져옵니다.
138fstatfsint fstatfs(unsigned int fd, struct statfs *buf)fd가 가리키는 파일이 속한 파일시스템의 통계를 반환합니다.
161chrootint chroot(const char *path)프로세스의 루트 디렉터리를 path로 바꿉니다(CAP_SYS_CHROOT 필요). 루트 변경은 권한 검사를 없애지 않으며 탈출 경로도 존재하므로 보안 격리 수단이 아닙니다. 격리에는 마운트 네임스페이스와 pivot_root(155)를 사용합니다.
165mountint mount(const char *src, const char *tgt, const char *fstype, unsigned long flags, const void *data)파일시스템을 마운트합니다. CAP_SYS_ADMIN 또는 user namespace mount 권한이 필요합니다.
166umount2int umount2(const char *target, int flags)마운트를 해제합니다. MNT_FORCE로 강제 해제, MNT_DETACH로 지연(Latency) 해제가 가능합니다.
179quotactlint quotactl(unsigned int cmd, const char *special, qid_t id, void *addr)경로가 속한 파일시스템의 쿼터(Quota)를 조회·설정합니다. Q_GETQUOTA·Q_SETQUOTA 같은 명령과 특수 블록 디바이스 경로를 인자로 받습니다.
188setxattrint setxattr(const char *path, const char *name, const void *value, size_t size, int flags)경로가 가리키는 파일(심볼릭 링크는 대상 파일)의 확장 속성을 설정합니다. flags는 XATTR_CREATE(이미 있으면 실패)·XATTR_REPLACE(없으면 실패)입니다.
189lsetxattrint lsetxattr(const char *path, const char *name, const void *value, size_t size, int flags)setxattr()와 같지만 심볼릭 링크를 따라가지 않고 링크 자체에 확장 속성을 설정합니다.
190fsetxattrint fsetxattr(int fd, const char *name, const void *value, size_t size, int flags)열린 fd가 가리키는 파일에 확장 속성을 설정합니다. 경로 해석이 없어 경쟁 조건에 안전합니다.
191getxattrssize_t getxattr(const char *path, const char *name, void *value, size_t size)확장 속성 값을 읽습니다. size가 0이면 필요한 버퍼 크기만 반환하므로 크기 조회 후 다시 호출하는 패턴을 사용합니다.
192lgetxattrssize_t lgetxattr(const char *path, const char *name, void *value, size_t size)getxattr()와 같지만 심볼릭 링크를 따라가지 않고 링크 자체의 확장 속성을 읽습니다.
193fgetxattrssize_t fgetxattr(int fd, const char *name, void *value, size_t size)열린 fd가 가리키는 파일의 확장 속성 값을 읽습니다.
194listxattrssize_t listxattr(const char *path, char *list, size_t size)설정된 확장 속성 이름 목록을 NUL로 구분해 반환합니다. size가 0이면 필요한 버퍼 크기를 반환하며, 파일시스템이 확장 속성을 지원하지 않으면 -EOPNOTSUPP입니다.
195llistxattrssize_t llistxattr(const char *path, char *list, size_t size)listxattr()와 같지만 심볼릭 링크를 따라가지 않고 링크 자체의 확장 속성 이름을 나열합니다.
196flistxattrssize_t flistxattr(int fd, char *list, size_t size)열린 fd가 가리키는 파일의 확장 속성 이름을 나열합니다.
197removexattrint removexattr(const char *path, const char *name)확장 속성을 제거합니다. 해당 속성이 없으면 -ENODATA를 반환합니다.
198lremovexattrint lremovexattr(const char *path, const char *name)removexattr()와 같지만 심볼릭 링크를 따라가지 않고 링크 자체의 확장 속성을 제거합니다.
199fremovexattrint fremovexattr(int fd, const char *name)열린 fd가 가리키는 파일의 확장 속성을 제거합니다.
217getdents64int getdents64(int fd, struct linux_dirent64 *dirp, int count)디렉터리 fd에서 항목들을 읽습니다. ls, find, opendir()/readdir() glibc 함수의 기반입니다.
258mkdiratint mkdirat(int dirfd, const char *path, mode_t mode)dirfd 기준으로 디렉터리를 생성합니다. dirfd=AT_FDCWD이면 mkdir과 동일합니다.
259mknodatint mknodat(int dirfd, const char *pathname, mode_t mode, dev_t dev)dirfd 기준 경로에 디바이스 노드·FIFO·소켓 파일을 생성합니다. S_IFCHR·S_IFBLK 유형에는 CAP_MKNOD가 필요합니다.
260fchownatint fchownat(int dfd, const char *filename, uid_t user, gid_t group, int flag)dirfd 기준 경로의 소유자를 바꿉니다. AT_SYMLINK_NOFOLLOW로 링크 자체를 대상으로 삼을 수 있습니다.
262newfstatatint newfstatat(int dirfd, const char *path, struct stat *st, int flags)dirfd 기준 경로의 파일 메타데이터를 가져옵니다. AT_EMPTY_PATH|AT_SYMLINK_NOFOLLOW로 fd 자체 또는 링크 자체 정보 조회.
263unlinkatint unlinkat(int dirfd, const char *path, int flags)AT_REMOVEDIR 플래그로 디렉터리 삭제도 가능한 통합 unlink/rmdir입니다.
264renameatint renameat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath)두 dirfd를 기준으로 이름을 바꾸거나 이동합니다. 같은 파일시스템 안에서 원자적으로 수행되며, 대상 경로가 이미 있으면 교체합니다.
265linkatint linkat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath, int flags)dirfd 기준으로 하드 링크를 생성합니다. AT_EMPTY_PATH로 fd를 직접 링크할 수 있습니다.
266symlinkatint symlinkat(const char *target, int newdirfd, const char *linkpath)newdirfd 기준으로 심볼릭 링크를 생성합니다.
267readlinkatssize_t readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz)심볼릭 링크가 가리키는 경로를 buf에 복사합니다. 문자열을 NUL로 종료하지 않고 실제로 복사한 바이트 수를 반환하며, bufsiz보다 길면 잘립니다.
268fchmodatint fchmodat(int dirfd, const char *pathname, mode_t mode)dirfd 기준 경로의 권한 비트를 바꿉니다. flags 인자가 없어 AT_SYMLINK_NOFOLLOW 같은 동작은 fchmodat2(452)에서 지원합니다.
269faccessatint faccessat(int dfd, const char *filename, int mode)dirfd 기준 경로의 접근 권한을 확인합니다. flags를 받는 faccessat2(439)가 이후 추가되었습니다.
280utimensatint utimensat(int dirfd, const char *pathname, const struct timespec times[2], int flags)접근 시각과 수정 시각을 나노초 해상도로 설정합니다. times에 UTIME_NOW·UTIME_OMIT를 넣어 일부만 갱신할 수 있고, AT_SYMLINK_NOFOLLOW로 링크 자체의 시각을 바꿉니다.
300fanotify_initint fanotify_init(unsigned int flags, unsigned int event_f_flags)파일시스템 전체 이벤트를 감시하는 fanotify 그룹을 만들고 fd를 반환합니다(CAP_SYS_ADMIN 필요).
301fanotify_markint fanotify_mark(int fanotify_fd, unsigned int flags, unsigned int mask_1, unsigned int mask_2, int dfd, const char * pathname)fanotify 그룹에 감시할 마운트·파일과 이벤트 마스크를 추가하거나 제거합니다.
303name_to_handle_atint name_to_handle_at(int dfd, const char *name, struct file_handle *handle, void *mnt_id, int flag)경로에 대응하는 파일 핸들과 마운트 ID를 얻습니다.
304open_by_handle_atint open_by_handle_at(int mountdirfd, struct file_handle *handle, int flags)name_to_handle_at()으로 얻은 파일 핸들로 파일을 엽니다(CAP_DAC_READ_SEARCH 필요).
306syncfsint syncfs(int fd)fd가 속한 파일시스템 하나만 writeback합니다. sync(162)보다 범위가 좁습니다.
316renameat2int renameat2(int olddirfd, const char *oldpath, int newdirfd, const char *newpath, unsigned int flags)RENAME_EXCHANGE로 두 파일을 원자적으로 교환하거나, RENAME_NOREPLACE로 대상이 있으면 실패합니다.
332statxint statx(int dirfd, const char *path, int flags, unsigned int mask, struct statx *statxbuf)확장된 파일 메타데이터 조회 (Linux 4.11+). 생성 시각(stx_btime), 마운트 ID, 속성 플래그 등 기존 stat에 없는 정보를 제공합니다.
428open_treeint open_tree(int dfd, const char *path, unsigned flags)마운트를 복제(OPEN_TREE_CLONE)하거나 경로 참조용 fd로 엽니다.
429move_mountint move_mount(int from_dfd, const char *from_path, int to_dfd, const char *to_path, unsigned int ms_flags)마운트를 다른 위치로 옮기거나 붙입니다. 경로 대신 fd로 출발지·도착지를 지정할 수 있습니다.
430fsopenint fsopen(const char *fs_name, unsigned int flags)파일시스템 종류를 지정해 새 마운트 컨텍스트 fd를 만듭니다.
431fsconfigint fsconfig(int fs_fd, unsigned int cmd, const char *key, const void *value, int aux)fsopen() 컨텍스트에 옵션을 설정하거나 생성·재구성 명령을 실행합니다.
432fsmountint fsmount(int fs_fd, unsigned int flags, unsigned int ms_flags)설정이 끝난 컨텍스트로 실제 마운트 객체를 만들어 fd로 반환합니다.
433fspickint fspick(int dfd, const char *path, unsigned int flags)기존 마운트를 재구성 대상으로 선택해 fd를 반환합니다.
437openat2int openat2(int dfd, const char *filename, struct open_how *how, size_t size)openat에 resolve 플래그(RESOLVE_NO_SYMLINKS·RESOLVE_BENEATH 등)와 구조체 크기 검증을 더한 확장 인터페이스입니다.
439faccessat2int faccessat2(int dfd, const char *filename, int mode, int flags)faccessat에 flags(AT_EACCESS·AT_SYMLINK_NOFOLLOW)를 추가한 형태입니다.
442mount_setattrint mount_setattr(int dfd, const char *path, unsigned int flags, struct mount_attr *uattr, size_t usize)마운트 속성을 fd 기반으로 변경하며, AT_RECURSIVE로 하위 마운트에 일괄 적용할 수 있습니다.
443quotactl_fdint quotactl_fd(unsigned int fd, unsigned int cmd, qid_t id, void *addr)경로 대신 fd로 대상 파일시스템을 지정하는 quotactl(179)입니다.
451cachestatint cachestat(unsigned int fd, struct cachestat_range *cstat_range, struct cachestat *cstat, unsigned int flags)fd의 페이지 캐시 통계(캐시된 바이트·더티 페이지 등)를 struct cachestat로 반환합니다.
452fchmodat2int fchmodat2(int dfd, const char *filename, umode_t mode, unsigned int flags)fchmodat에 flags(AT_SYMLINK_NOFOLLOW·AT_EMPTY_PATH)를 추가한 형태입니다.
457statmountint statmount(const struct mnt_id_req *req, struct statmount *buf, size_t bufsize, unsigned int flags)64비트 마운트 ID로 특정 마운트의 상세 속성을 조회합니다 (Linux 6.8+). listmount()로 얻은 마운트 ID와 함께 사용합니다. 기존 /proc/<pid>/mountinfo 파싱 없이 커널 직접 조회가 가능하며, idmapping 정보 조회도 지원합니다 (6.15 확장).
458listmountssize_t listmount(const struct mnt_id_req *req, uint64_t *mnt_ids, size_t nr_mnt_ids, unsigned int flags)특정 마운트의 자식 마운트 ID 배열을 반환합니다 (Linux 6.8+). 루트 마운트에서 시작하여 마운트 트리를 순회할 수 있습니다. 컨테이너 런타임, lsblk 등 마운트 토폴로지(Topology) 분석 도구에서 사용합니다.
467open_tree_attrint open_tree_attr(int dirfd, const char *path, unsigned int flags, struct mount_attr *attr, size_t attr_size)open_tree()의 확장 버전으로 struct mount_attr를 선택적으로 전달합니다 (Linux 6.15+). 이미 idmapped된 마운트에서 새 idmapped 마운트를 생성하는 중첩 idmapping 시나리오에서 사용합니다.
468file_getattrint file_getattr(int dirfd, const char *pathname, struct file_attr *fa, size_t size, unsigned int at_flags)chattr/lsattr류 속성(FS_XFLAG_IMMUTABLE, APPEND, project ID, extent 크기 등)을 race-free로 조회합니다 (Linux 6.17+). 기존 ioctl(FS_IOC_GETFLAGS)의 파일시스템별 상이한 동작을 표준화합니다.
469file_setattrint file_setattr(int dirfd, const char *pathname, const struct file_attr *fa, size_t size, unsigned int at_flags)file_attr 구조체 기반으로 확장 파일 속성을 설정합니다 (Linux 6.17+). 구조체 크기 인자로 향후 필드 추가 시 전·후방 호환을 보장합니다.
470listnsssize_t listns(const struct ns_id_req *req, uint64_t *ns_ids, size_t nr_ns_ids, unsigned int flags)시스템 내 네임스페이스를 직접 열거합니다 (Linux 6.19+). struct ns_id_req(size/spare/ns_id/ns_type/spare2/user_ns_id)로 ns_type 비트마스크(MNT_NS, NET_NS, USER_NS 등) 필터, user_ns_id 소유자 필터, ns_id 기반 페이지네이션을 지정합니다. 기존에는 모든 프로세스의 /proc/<pid>/ns/를 스캔해야 했으나 이 syscall로 커널이 직접 네임스페이스 목록을 반환하며, listmount()와 유사한 인터페이스로 컨테이너 런타임, nsenter 도구에서 활용됩니다.
472fchrootint fchroot(int fd, unsigned int flags)fd가 가리키는 디렉터리를 루트로 바꿉니다(Linux 7.3+). 경로를 다시 해석하지 않아 chroot()의 경쟁 조건을 없앨 수 있습니다. flags는 0이어야 하고, 대상은 디렉터리여야 하며 CAP_SYS_CHROOT가 필요합니다.

Linux 6.8부터: statmount()와 listmount()가 추가되어 /proc/<pid>/mountinfo 파싱 없이 마운트 토폴로지를 직접 조회할 수 있습니다. Linux 6.15에서 statmount()에 idmapping 조회 기능과 마운트 토폴로지 변경 알림 API가 추가되었으며, open_tree_attr()로 중첩 idmapped 마운트 생성이 가능해졌습니다.

파일 변경 감시 (inotify)

inotify는 파일시스템 이벤트를 fd 기반으로 모니터링하는 메커니즘입니다. 파일 생성, 삭제, 수정, 이동 등을 감시하며, IDE의 자동 새로고침, 로그 모니터링, 빌드 도구의 파일 감시 등에 사용됩니다.

번호이름시그니처설명
253inotify_initint inotify_init(void)inotify 인스턴스를 만들어 fd를 반환합니다. flags를 받는 inotify_init1(294)이 이후 추가되었습니다.
254inotify_add_watchint inotify_add_watch(int fd, const char *pathname, uint32_t mask)감시할 경로와 이벤트 마스크를 등록합니다. IN_CREATE|IN_DELETE|IN_MODIFY|IN_MOVED_FROM|IN_MOVED_TO 등의 이벤트를 조합합니다.
255inotify_rm_watchint inotify_rm_watch(int fd, int wd)감시 대상을 제거합니다. 제거 시 IN_IGNORED 이벤트가 발생합니다.
294inotify_init1int inotify_init1(int flags)inotify 인스턴스를 생성합니다. IN_NONBLOCK|IN_CLOEXEC 플래그 권장. 반환된 fd를 epoll에 등록하여 이벤트 루프(Event Loop)에서 처리합니다.

프로세스 관리

프로세스(Process)는 실행 중인 프로그램의 인스턴스로, 커널이 각 프로세스에게 독립된 가상 주소 공간·파일 디스크립터 테이블·자격증명(Credentials)을 부여하여 서로 격리합니다. 프로그램을 실행하거나 종료하는 행위 자체가 커널 자원을 생성·해제하는 과정이므로 반드시 syscall을 통해 이루어집니다. Linux에서는 프로세스와 스레드(Thread)가 clone()이라는 하나의 syscall로 통합 생성되며, 어떤 자원(메모리 공간, fd 테이블, 시그널 핸들러 등)을 공유할지 플래그로 결정합니다. fork()는 내부적으로 clone(SIGCHLD, ...)와 동일하고, pthread_create()는 clone(CLONE_VM|CLONE_FILES|CLONE_THREAD|...)를 사용합니다.

프로세스 생명주기 — fork에서 회수까지 부모 프로세스 fork()·clone() 호출 자식 태스크 copy_process: task_struct 복사 execve() mm 교체 · 새 프로그램 적재 exit_group() do_exit → 좀비(EXIT_ZOMBIE) wait4() release_task 고아 → init·subreaper 부모가 먼저 종료한 경우 부모가 먼저 종료하면 좀비는 회수 전까지 task_struct와 PID를 유지하므로 wait4()·waitid()로 반드시 회수해야 합니다.
부모의 fork()·clone()으로 자식이 생성되고, execve()가 주소 공간을 새 프로그램으로 교체하며, exit_group() 호출 뒤 좀비로 남은 자식은 부모의 wait4()로 회수됩니다. 부모가 먼저 종료되면 고아는 init·subreaper로 재부모화됩니다 (개념 개요).
관련 문서: 프로세스 관리 — task_struct, fork/clone/execve 경로, CFS | 네임스페이스(Namespace) — PID/mount/user 격리 | cgroups v1/v2 — 리소스 제어
번호이름시그니처설명
24sched_yieldint sched_yield(void)호출 스레드가 CPU를 자발적으로 내놓고 같은 우선순위의 다른 실행 가능 스레드를 스케줄합니다. 실행 가능한 다른 스레드가 없으면 즉시 복귀하므로 락 대기·폴링(Polling)에 남용하면 비용만 늘어납니다.
34pauseint pause(void)시그널 핸들러가 실행될 때까지 호출 스레드를 잠듭니다. sigsuspend()와 달리 시그널 마스크를 바꾸지 않으므로 대기 중인 시그널이 있으면 즉시 처리됩니다.
39getpidpid_t getpid(void)현재 프로세스의 PID(=TGID)를 반환합니다. vDSO로 가속되는 경우가 있습니다.
56clonelong clone(unsigned long flags, void *stack, int *ptid, int *ctid, unsigned long tls)세밀한 격리 플래그로 새 실행 단위를 생성합니다. CLONE_VM|CLONE_THREAD 조합이면 스레드, 아니면 프로세스입니다. 컨테이너 생성에는 CLONE_NEWPID|CLONE_NEWNS 등을 사용합니다.
57forkpid_t fork(void)현재 프로세스를 COW 방식으로 복제합니다. 부모에는 자식 PID, 자식에는 0을 반환합니다. 내부적으로 clone(SIGCHLD)입니다.
58vforkpid_t vfork(void)주소 공간(Address Space) 복사 없이 자식을 생성합니다. 자식이 execve/exit 호출 전까지 부모는 블록됩니다. 페이지 테이블(Page Table) 복사가 없어 fork보다 빠르지만 사용이 제한적입니다.
59execveint execve(const char *path, char *const argv[], char *const envp[])현재 프로세스 이미지를 새 프로그램으로 교체합니다. 성공 시 반환하지 않습니다. argv[0]은 관례상 프로그램 이름, envp는 환경 변수 목록입니다.
60exitvoid exit(int status)현재 스레드만 종료합니다. 커널 내부적으로는 do_exit()를 호출합니다. atexit 핸들러(Handler)는 glibc 수준에서 호출됩니다.
61wait4pid_t wait4(pid_t pid, int *wstatus, int options, struct rusage *rusage)자식 프로세스의 상태 변화를 기다립니다. pid=-1이면 임의 자식, WNOHANG으로 비블로킹 확인 가능. rusage로 자원 사용량도 조회합니다.
107geteuiduid_t geteuid(void)프로세스의 유효(effective) UID를 반환합니다. 권한 판단에 사용됩니다.
109setpgidint setpgid(pid_t pid, pid_t pgid)프로세스의 프로세스 그룹 ID를 설정합니다. pid와 pgid가 같으면 새 그룹을 만들고, 세션 리더의 그룹은 변경할 수 없습니다.
110getppidpid_t getppid(void)부모 프로세스의 PID를 반환합니다. 부모가 죽으면 init(PID=1)이 됩니다.
111getpgrppid_t getpgrp(void)현재 프로세스의 프로세스 그룹 ID를 반환합니다.
112setsidpid_t setsid(void)새 세션을 생성하고 제어 터미널에서 분리됩니다. daemon 프로세스 구현 시 사용합니다.
113setreuidint setreuid(uid_t ruid, uid_t euid)실제 사용자 ID와 실효 사용자 ID를 함께 설정합니다. 인자에 -1을 넣으면 해당 ID는 그대로 둡니다(CAP_SETUID 필요).
114setregidint setregid(gid_t rgid, gid_t egid)실제 그룹 ID와 실효 그룹 ID를 함께 설정합니다(CAP_SETGID 필요).
115getgroupsint getgroups(int size, gid_t list[])프로세스의 보조 그룹 ID 목록을 반환합니다. size가 0이면 필요한 항목 수만 반환합니다.
116setgroupsint setgroups(size_t size, const gid_t *list)보조 그룹 ID 목록을 설정합니다(CAP_SETGID 필요). 컨테이너 초기화에서 gid_map을 쓰기 전에 호출하는 대표 사례가 있습니다.
121getpgidpid_t getpgid(pid_t pid)지정한 프로세스의 프로세스 그룹 ID를 반환합니다. pid가 0이면 호출 프로세스를 대상으로 합니다.
122setfsuidint setfsuid(uid_t fsuid)파일 접근 판정에만 쓰이는 파일 시스템 사용자 ID(FSUID)를 바꿉니다. 오류를 반환하지 않고 이전 FSUID를 반환하므로, 성공 여부는 같은 값을 다시 설정해 반환값을 비교해 확인합니다.
123setfsgidint setfsgid(gid_t fsgid)파일 접근 판정에 쓰이는 파일 시스템 그룹 ID(FSGID)를 바꿉니다. setfsuid()와 같은 방식으로 결과를 확인합니다.
124getsidpid_t getsid(pid_t pid)지정한 프로세스가 속한 세션 ID를 반환합니다. pid가 0이면 호출 프로세스를 대상으로 합니다.
135personalityint personality(unsigned int personality)프로세스의 실행 도메인(personality) 플래그를 조회·설정합니다. ADDR_NO_RANDOMIZE로 ASLR을 끄는 용도로 알려져 있습니다.
140getpriorityint getpriority(int which, int who)PRIO_PROCESS·PRIO_PGRP·PRIO_USER 단위의 nice 값을 조회합니다. 커널은 20-nice를 반환하므로 glibc 래퍼가 이를 되돌려 주며, 오류 판정은 반환값이 아니라 errno로 합니다.
141setpriorityint setpriority(int which, int who, int niceval)PRIO_PROCESS·PRIO_PGRP·PRIO_USER 단위의 nice 값을 설정합니다. nice 값을 낮추려면 CAP_SYS_NICE가 필요합니다.
142sched_setparamint sched_setparam(pid_t pid, const struct sched_param *param)스케줄링 정책은 그대로 두고 우선순위 파라미터만 바꿉니다. 실시간 정책의 우선순위 변경에는 CAP_SYS_NICE가 필요합니다.
143sched_getparamint sched_getparam(pid_t pid, struct sched_param *param)스레드에 적용된 스케줄링 우선순위 파라미터를 반환합니다.
144sched_setschedulerint sched_setscheduler(pid_t pid, int policy, const struct sched_param *param)스케줄링 정책(SCHED_OTHER·FIFO·RR·BATCH·IDLE·DEADLINE)과 우선순위를 함께 바꿉니다. 실시간 정책 지정에는 CAP_SYS_NICE가 필요합니다.
145sched_getschedulerint sched_getscheduler(pid_t pid)스레드에 적용된 스케줄링 정책을 반환합니다.
146sched_get_priority_maxint sched_get_priority_max(int policy)스케줄링 정책별 최대 정적 우선순위를 반환합니다.
147sched_get_priority_minint sched_get_priority_min(int policy)스케줄링 정책별 최소 정적 우선순위를 반환합니다.
148sched_rr_get_intervalint sched_rr_get_interval(pid_t pid, struct __kernel_timespec *interval)SCHED_RR 스레드의 타임 슬라이스 길이를 timespec으로 반환합니다.
154modify_ldtint modify_ldt(int func, void *ptr, unsigned long bytecount)x86 전용으로 LDT 엔트리를 읽거나 씁니다. 16비트 세그먼트 기반 코드나 호환 계층에서 사용합니다.
155pivot_rootint pivot_root(const char *new_root, const char *put_old)루트 파일시스템을 교체합니다. 컨테이너 초기화 시 initramfs → 실제 루트 전환에 사용합니다.
157prctlint prctl(int option, unsigned long arg2, ...)프로세스 속성을 제어합니다. PR_SET_NAME(이름 설정), PR_SET_DUMPABLE(코어 덤프(Core Dump)), PR_SET_SECCOMP(seccomp 활성화), PR_SET_NO_NEW_PRIVS(권한 상승 방지), PR_SET_CHILD_SUBREAPER 등.
158arch_prctlint arch_prctl(int code, unsigned long addr)x86_64 전용 아키텍처 제어로 FS·GS 베이스(TLS), CPUID faulting, XCOMP 상태 등을 설정·조회합니다. ARCH_SET_FS·ARCH_GET_FS가 대표적인 명령입니다.
186gettidpid_t gettid(void)호출 스레드의 TID(커널 스케줄 단위 ID)를 반환합니다. getpid()가 스레드 그룹 ID를 반환하는 것과 대비되며, glibc 2.30 이후 래퍼가 제공됩니다.
203sched_setaffinityint sched_setaffinity(pid_t pid, size_t cpusetsize, const cpu_set_t *mask)스레드(pid)의 CPU 선호도(Affinity) 마스크를 설정합니다. pid가 0이면 호출 스레드이며, 커널은 마스크에 포함된 CPU 중 하나에서 실행합니다.
204sched_getaffinityint sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask)스레드(pid)에 허용된 CPU 마스크를 반환합니다. cgroup cpuset이 적용된 결과가 반영되므로 nproc(1)이 보는 CPU 수와 일치합니다.
205set_thread_areaint set_thread_area(struct user_desc *u_info)x86 32비트 호환용으로 TLS 세그먼트(user_desc)를 설정합니다.
211get_thread_areaint get_thread_area(struct user_desc *u_info)set_thread_area()로 설정한 TLS 세그먼트 정보를 조회합니다.
218set_tid_addressint set_tid_address(int *tidptr)스레드 종료 시 커널이 *tidptr을 0으로 만들고 futex로 깨우도록 등록합니다. glibc pthread가 스레드 조인을 구현할 때 사용합니다.
219restart_syscallint restart_syscall(void)시그널로 중단된 syscall을 재시작할 때 커널이 반환하는 재개용 진입점입니다. 응용 프로그램이 직접 호출하지 않습니다.
231exit_groupvoid exit_group(int status)프로세스 내 모든 스레드를 종료합니다. glibc의 exit()가 실제로 이 syscall을 호출합니다.
247waitidint waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options, struct rusage *ru)wait4보다 세밀한 옵션을 제공합니다. idtype으로 P_PID/P_PGID/P_ALL 선택, WNOWAIT으로 상태를 소비하지 않고 조회만 가능합니다.
251ioprio_setint ioprio_set(int which, int who, int ioprio)프로세스·스레드·cgroup의 I/O 우선순위 클래스와 등급을 설정합니다.
252ioprio_getint ioprio_get(int which, int who)I/O 우선순위 클래스와 등급을 조회합니다.
273set_robust_listint set_robust_list(struct robust_list_head *head, size_t len)스레드가 뮤텍스를 잡은 채 종료했을 때 커널이 락을 정리하도록 robust futex 리스트를 등록합니다. glibc pthread가 초기화 시 호출합니다.
274get_robust_listint get_robust_list(int pid, struct robust_list_head **head_ptr, size_t *len_ptr)다른 스레드에 등록된 robust futex 리스트를 조회합니다. 디버거·검사 도구가 사용합니다.
309getcpuint getcpu(unsigned *cpu, unsigned *node, void *cache)호출 스레드가 실행 중인 CPU 번호와 NUMA 노드를 반환합니다. vDSO로 처리될 수 있습니다.
312kcmpint kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2)두 프로세스가 파일·VM·futex 등을 공유하는지 비교합니다. 주로 검사 도구가 사용합니다.
314sched_setattrint sched_setattr(pid_t pid, struct sched_attr *attr, unsigned int flags)sched_setscheduler를 확장해 struct sched_attr과 SCHED_DEADLINE 파라미터를 한 번에 설정합니다.
315sched_getattrint sched_getattr(pid_t pid, struct sched_attr *attr, unsigned int size, unsigned int flags)struct sched_attr로 스케줄링 속성을 조회합니다.
322execveatint execveat(int dirfd, const char *path, char *const argv[], char *const envp[], int flags)dirfd 기준 상대 경로로 execve를 수행합니다. AT_EMPTY_PATH 플래그로 fd를 직접 실행할 수 있습니다. Linux 6.14+: AT_EXECVE_CHECK 플래그 추가 — 실제 실행 없이 해당 파일의 실행 허용 여부(커널 보안 정책 기준)만 확인합니다. 스크립트 인터프리터나 dlopen()이 파일 형식과 무관하게 보안 정책을 사전 확인할 때 사용합니다.
424pidfd_send_signalint pidfd_send_signal(int pidfd, int sig, siginfo_t *info, unsigned int flags)pidfd를 통해 시그널을 전송합니다. PID 재사용 경쟁 없이 안전하며, sig=0으로 프로세스 존재 확인에 사용합니다.
434pidfd_openint pidfd_open(pid_t pid, unsigned int flags)프로세스를 fd로 참조합니다 (Linux 5.3+). PID 재사용 경쟁 조건을 완전히 제거하며, waitid(P_PIDFD)로 안전한 대기, pidfd_send_signal로 안전한 시그널 전송이 가능합니다.
435clone3long clone3(struct clone_args *args, size_t size)구조체(Struct)로 인자를 전달하는 clone의 확장 버전입니다 (Linux 5.3+). CLONE_INTO_CGROUP으로 생성 즉시 cgroup에 넣거나, set_tid로 PID를 지정할 수 있습니다.
438pidfd_getfdint pidfd_getfd(int pidfd, int targetfd, unsigned int flags)다른 프로세스의 fd를 복제합니다 (Linux 5.6+). ptrace 없이 fd를 가져올 수 있으며, 컨테이너 디버깅(Debugging)에 유용합니다.

clone() 주요 플래그 (flags 인자)

플래그설명사용 예
CLONE_VM가상 주소 공간 공유 (스레드 핵심)pthread_create 내부
CLONE_FScwd/root/umask 공유스레드
CLONE_FILES파일 디스크립터 테이블 공유스레드 (fork는 미사용)
CLONE_SIGHAND시그널 핸들러 공유스레드
CLONE_THREAD같은 스레드 그룹(TGID)에 추가 — CLONE_VM|CLONE_SIGHAND 필요pthread_create
CLONE_NEWPID새 PID 네임스페이스 생성컨테이너
CLONE_NEWNET새 네트워크 네임스페이스 생성컨테이너
CLONE_NEWNS새 마운트 네임스페이스 생성컨테이너, unshare
CLONE_NEWUSER새 사용자 네임스페이스 생성 (UID/GID 매핑(Mapping))rootless 컨테이너
CLONE_NEWUTS새 UTS(hostname/domainname) 네임스페이스컨테이너
CLONE_NEWIPC새 IPC(SysV, POSIX MQ) 네임스페이스컨테이너
CLONE_NEWCGROUP새 cgroup 네임스페이스컨테이너
CLONE_VFORKvfork처럼 부모 실행 정지vfork 구현
CLONE_PTRACEptrace 연결 유지 (디버거)strace, gdb
CLONE_SETTLS스레드 로컬 스토리지(TLS) 포인터 설정pthread_create (fs/gs 기반)
CLONE_CHILD_CLEARTID자식 종료 시 ctid 주소를 0으로 클리어 후 futex 깨움pthread_join 구현

fork/exec 기본 패턴

/* fork → exec → wait 기본 패턴 */
pid_t pid = fork();
if (pid < 0) { perror("fork"); exit(1); }
if (pid == 0) {
    /* 자식: 새 프로그램 실행 */
    execve("/usr/bin/ls", (char*[]){"ls", "-la", NULL},
           (char*[]){"PATH=/usr/bin", NULL});
    _exit(127);  /* execve 실패 시 — exit() 아닌 _exit() 사용 */
}
/* 부모: 자식 종료 대기 */
int status;
waitpid(pid, &status, 0);
if (WIFEXITED(status))
    printf("종료 코드: %d\n", WEXITSTATUS(status));

/* 데몬 프로세스 생성 패턴 (POSIX) */
if (fork() > 0) _exit(0);  /* 부모 종료 → init 입양 */
setsid();                       /* 새 세션, 제어 터미널 분리 */
if (fork() > 0) _exit(0);  /* 세션 리더 아닌 프로세스로 */
chdir("/");                   /* 마운트 해제 방지 */
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
흔한 실수:
  • 좀비 프로세스 방치 — wait()/waitpid()를 호출하지 않으면 자식이 ZOMBIE 상태로 남습니다. SIGCHLD를 SIG_IGN으로 설정하면 자동 수거됩니다.
  • 멀티스레드 프로세스에서 fork() — fork()는 호출한 스레드만 복제합니다. 자식에서 다른 스레드가 잡고 있던 뮤텍스(Mutex)는 영원히 잠긴 채 남습니다. fork 후 즉시 exec만 하세요.
  • execve 실패 후 exit() 사용 — exit()는 atexit 핸들러와 stdio 버퍼(Buffer)를 플러시합니다. fork 자식에서는 _exit()를 사용해야 부모 stdio 버퍼가 이중 플러시되는 것을 방지합니다.
  • PID 재사용 경쟁 — kill(pid)와 waitpid(pid) 사이에 PID가 재사용될 수 있습니다. Linux 5.3+에서는 pidfd_open()을 사용하세요.

메모리 관리

현대 운영체제는 각 프로세스에게 독립된 가상 주소 공간(Virtual Address Space)을 제공합니다. 프로세스는 물리 메모리(Physical Memory) 주소를 알 필요 없이 가상 주소(Virtual Address)만 사용하고, 커널의 메모리 관리 유닛(MMU)이 페이지 테이블(Page Table)을 통해 가상 → 물리 주소(Physical Address)를 변환합니다. 이 가상 주소 공간을 할당·해제·보호하는 작업이 커널의 핵심 책임이므로 반드시 syscall을 통해 이루어집니다. glibc의 malloc()은 내부적으로 작은 할당(≤128KB)에는 brk()를, 큰 할당에는 mmap(MAP_ANONYMOUS)를 사용하며, 직접 syscall을 호출하지 않고 glibc 메모리 풀을 경유합니다. 파일을 메모리에 매핑(mmap)하면 파일 I/O 없이 포인터 접근만으로 파일 내용을 읽고 쓸 수 있어 데이터베이스·인터프리터 등에서 광범위하게 활용됩니다.

x86_64 프로세스 가상 주소 공간 — 높은 주소에서 낮은 주소로 커널 공간 링 0 전용 — 사용자 접근 시 SIGSEGV 스택 (Stack) 지역 변수·복귀 주소 · 상단 0x00007ffffffff000 (4-level) 빈 공간 (ASLR) 매 실행마다 배치가 달라지는 미할당 영역 mmap 영역 공유 라이브러리·파일 매핑·vDSO·스레드 스택 힙 (Heap) malloc 영역 — brk()로 위로 확장 BSS 초기화되지 않은 전역 변수 (0으로 채움) 데이터 (Data) 초기화된 전역·정적 변수 텍스트 (Text) 실행 코드 — 읽기 전용 (r-x) 높은 주소 낮은 주소 아래로 성장 위로 성장 구체적 주소 범위는 페이징 단계(4-level/5-level)와 ASLR 설정에 따라 달라집니다.
x86_64 프로세스의 가상 주소 공간을 높은 주소에서 낮은 주소 순으로 나타냈습니다. 커널 공간(Kernel Space) 아래로 스택·ASLR 빈 공간·mmap·힙·BSS·데이터·텍스트가 배치되며, 스택은 아래로 힙은 위로 성장합니다 (개념 개요).
관련 문서: 메모리 관리 — Buddy, SLUB, OOM | 메모리 — mmap, VMA, 페이지 폴트(Page Fault) | VMA/mmap — MAP_SHARED vs MAP_PRIVATE, userfaultfd
번호이름시그니처설명
9mmapvoid *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset)파일이나 익명 메모리를 가상 주소 공간에 매핑합니다. 성공 시 매핑된 주소 반환, 실패 시 MAP_FAILED((void*)-1). 페이지 경계(4KB) 정렬 필요.
10mprotectint mprotect(void *addr, size_t len, int prot)메모리 영역의 접근 보호를 변경합니다. PROT_READ|PROT_WRITE|PROT_EXEC 조합. JIT 컴파일러에서 PROT_WRITE → PROT_EXEC 전환에 사용합니다.
11munmapint munmap(void *addr, size_t len)mmap으로 생성된 매핑을 해제합니다. 중간 영역만 해제하면 원래 영역이 분할됩니다.
12brkint brk(void *addr)힙 세그먼트 끝 주소(program break)를 변경합니다. addr=NULL이면 현재 끝 주소를 반환합니다. glibc malloc이 내부에서 사용합니다.
25mremapvoid *mremap(void *old_addr, size_t old_len, size_t new_len, int flags, ...)기존 매핑의 크기나 위치를 변경합니다. MREMAP_MAYMOVE로 이동 허용, MREMAP_FIXED로 목적지 지정. realloc의 큰 블록 처리에 활용됩니다.
26msyncint msync(void *addr, size_t len, int flags)mmap 매핑의 변경 내용을 파일에 반영합니다. MS_SYNC(동기), MS_ASYNC(비동기), MS_INVALIDATE(다른 매핑 무효화(Invalidation)).
27mincoreint mincore(void *addr, size_t len, unsigned char *vec)각 페이지의 RAM 상주 여부를 확인합니다. vec[i]의 최하위 비트가 1이면 상주. 프리패치 판단이나 메모리 pressure 분석에 사용합니다.
28madviseint madvise(void *addr, size_t len, int advice)메모리 사용 패턴을 커널에 힌트로 전달합니다. 아래 표 참조.
149mlockint mlock(const void *addr, size_t len)지정 영역을 RAM에 고정합니다 (swap 불가). 실시간 처리, 암호화(Encryption) 키 보호에 사용합니다. RLIMIT_MEMLOCK 제한 있음.
150munlockint munlock(const void *addr, size_t len)mlock 잠금을 해제합니다. 해당 영역은 다시 swap 대상이 됩니다.
151mlockallint mlockall(int flags)현재 및 미래의 모든 매핑을 잠급니다. MCL_CURRENT(현재)+MCL_FUTURE(미래). 실시간 프로세스에 사용합니다.
152munlockallint munlockall(void)mlockall()로 잠근 모든 페이지의 잠금을 해제합니다.
216remap_file_pagesint remap_file_pages(void *addr, size_t size, int prot, size_t pgoff, int flags)VMA의 페이지를 파일 오프셋에 직접 매핑합니다. Linux 3.16 이후 커널이 소프트웨어로 에뮬레이션하며 폐기 절차가 진행되었습니다.
237mbindlong mbind(void *addr, unsigned long len, int mode, const unsigned long *nodemask, ...)NUMA 메모리 정책(Memory Policy)을 설정합니다. MPOL_BIND(특정 노드 강제), MPOL_PREFERRED, MPOL_INTERLEAVE(노드 간 분산).
238set_mempolicyint set_mempolicy(int mode, const unsigned long *nodemask, unsigned long maxnode)스레드의 NUMA 메모리 정책(MPOL_BIND·MPOL_PREFERRED·MPOL_INTERLEAVE 등)을 설정합니다.
239get_mempolicyint get_mempolicy(int *mode, unsigned long *nodemask, unsigned long maxnode, void *addr, unsigned long flags)스레드 또는 주소 범위에 적용된 NUMA 메모리 정책을 조회합니다.
256migrate_pagesint migrate_pages(pid_t pid, unsigned long maxnode, const unsigned long *from, const unsigned long *to)프로세스의 페이지를 지정한 노드 집합으로 옮깁니다(CAP_SYS_NICE 필요).
279move_pagesint move_pages(pid_t pid, unsigned long nr_pages, const void * *pages, const int *nodes, int *status, int flags)개별 페이지를 지정 노드로 이동하고 각 페이지의 현재 위치를 조회합니다.
310process_vm_readvssize_t process_vm_readv(pid_t pid, const struct iovec *local, unsigned long liovcnt, const struct iovec *remote, unsigned long riovcnt, unsigned long flags)다른 프로세스의 가상 메모리(Virtual Memory)를 직접 읽습니다. ptrace보다 빠르며 strace, 디버거, CRIU에 사용됩니다.
311process_vm_writevssize_t process_vm_writev(pid_t pid, const struct iovec *local, unsigned long liovcnt, const struct iovec *remote, unsigned long riovcnt, unsigned long flags)다른 프로세스의 가상 메모리에 직접 씁니다.
323userfaultfdint userfaultfd(int flags)사용자 공간에서 페이지 폴트(Page Fault)를 처리하는 fd를 생성합니다 (Linux 4.3+). 라이브 마이그레이션(Live Migration), 체크포인팅, CRIU에 핵심적입니다. UFFD_USER_MODE_ONLY 플래그 권장.
324membarrierint membarrier(int cmd, unsigned int flags, int cpu_id)프로세스 내 스레드 사이에 메모리 배리어(Memory Barrier)를 커널에 요청합니다. MEMBARRIER_CMD_GLOBAL·REGISTER_PRIVATE_EXPEDITED 같은 명령으로 실행 중인 스레드에 배리어를 강제합니다.
325mlock2int mlock2(unsigned long start, size_t len, int flags)mlock에 MLOCK_ONFAULT 플래그를 추가해 접근 시점에 페이지를 잠급니다.
329pkey_mprotectint pkey_mprotect(unsigned long start, size_t len, unsigned long prot, int pkey)메모리 보호 키(PKEY)를 지정해 mprotect합니다.
330pkey_allocint pkey_alloc(unsigned long flags, unsigned long init_val)보호 키를 할당하고 초기 접근 권한을 설정합니다.
331pkey_freeint pkey_free(int pkey)할당한 보호 키를 해제합니다.
440process_madviseint process_madvise(int pidfd, const struct iovec *iovec, size_t vlen, int advice, unsigned int flags)다른 프로세스의 메모리에 madvise 힌트를 적용합니다 (Linux 5.10+). Android의 메모리 관리자가 백그라운드 앱의 페이지를 cold/pageout 처리할 때 사용합니다.
447memfd_secretint memfd_secret(unsigned int flags)다른 프로세스와 커널 매핑에서 숨겨지는 비밀 메모리 영역을 만듭니다.
448process_mreleaseint process_mrelease(int pidfd, unsigned int flags)종료 중인 프로세스의 메모리를 즉시 회수합니다.
450set_mempolicy_home_nodeint set_mempolicy_home_node(unsigned long start, unsigned long len, unsigned long home_node, unsigned long flags)VMA의 홈 노드를 지정해 할당 시 해당 노드를 우선 사용하게 합니다.
453map_shadow_stackint map_shadow_stack(unsigned long addr, unsigned long size, unsigned int flags)x86 Shadow Stack(CET)용 그림자 스택을 매핑합니다.
462msealint mseal(unsigned long start, size_t len, unsigned long flags)VMA 범위를 봉인하여 이후 mprotect/munmap/mmap/mremap 변경을 -EPERM으로 차단합니다 (Linux 6.10+). 동적 링커(Linker)가 R-X 세그먼트를 로드한 직후 적용하여 메모리 손상 공격 경로를 봉쇄합니다. flags는 모두 예약되어 0이어야 합니다. mseal syscall 자체는 MMU를 쓰는 아키텍처에 공통이며, v7.0 기준 x86-64/arm64/loongarch/s390/riscv는 시스템 매핑(vDSO 등)까지 봉인하는 ARCH_SUPPORTS_MSEAL_SYSTEM_MAPPINGS를 선택합니다.

mmap() prot / flags 인자

인자값/상수설명
prot
(보호)
PROT_NONE접근 불가 (가드 페이지, NULL 역참조(Dereference) 감지)
PROT_READ읽기 가능
PROT_WRITE쓰기 가능
PROT_EXEC실행 가능 (W^X 정책: PROT_WRITE와 동시 사용 지양)
flags
(매핑 유형)
MAP_SHARED파일 변경이 다른 프로세스에게도 보임 (msync로 플러시)
MAP_PRIVATECOW 사본 — 변경이 파일에 반영되지 않음
MAP_ANONYMOUS파일과 무관한 익명 메모리 (fd=-1 필요)
MAP_FIXEDaddr을 정확히 사용 (기존 매핑 덮어씀 — 위험)
MAP_FIXED_NOREPLACEaddr이 이미 사용 중이면 EEXIST 반환 (Linux 4.17+)
MAP_HUGETLBHugePage(2MB/1GB) 사용. 대량 데이터 성능 향상.
MAP_POPULATE매핑 즉시 페이지 테이블을 채움 (나중의 페이지 폴트 방지)
MAP_LOCKEDmmap+mlock 효과 (mlockall 대신)
MAP_NORESERVEswap 예약 없이 오버커밋 허용

madvise() 힌트 (advice 인자)

advice설명
MADV_NORMAL기본 동작 (보통 readahead 적용)
MADV_SEQUENTIAL순차 접근 예상 — readahead 크게 증가
MADV_RANDOM임의 접근 예상 — readahead 끄기
MADV_WILLNEED곧 접근 예정 — 미리 읽기(prefault)
MADV_DONTNEED더 이상 필요 없음 — 페이지 캐시 해제 가능 (메모리 즉시 반납)
MADV_FREElazy 해제 — 메모리 압박 시에만 반납 (zero 초기화 보장 안 됨)
MADV_HUGEPAGETHP(Transparent Huge Page) 사용 요청
MADV_NOHUGEPAGETHP 사용 금지
MADV_DONTFORKfork 시 자식에게 매핑 상속하지 않음
MADV_DONTDUMP코어 덤프에서 이 영역 제외 (민감한 데이터 보호)
MADV_COLDLRU 리스트에서 cold 위치로 이동 (Linux 5.4+)
MADV_PAGEOUT즉시 swap out 요청 (Linux 5.4+)
MADV_POPULATE_READ읽기 권한으로 페이지 미리 채움 — 폴트 없이 접근 가능 (Linux 5.14+)

mmap 페이지 폴트(Page Fault) 처리 흐름

mmap 페이지 폴트 처리 흐름 — 파일·익명·COW 분기 사용자 메모리 접근 VMA가 있는 주소 페이지 폴트 (#PF) exc_page_fault do_user_addr_fault VMA 조회 후 처리 분기 handle_mm_fault PTE 검사와 경로 선택 do_read_fault filemap_fault: 페이지 캐시 do_anonymous_page 0으로 채운 익명 페이지 do_wp_page COW: 새 folio 복사 파일 매핑 익명 매핑 쓰기 보호 파일 매핑은 페이지 캐시에 folio가 없으면 파일시스템 readahead로 채운 뒤 매핑합니다. 쓰기 보호 폴트는 do_wp_page가 folio를 복사해 사적 매핑을 만듭니다 (COW). 처리 후 PTE를 채우고 폴트를 일으킨 명령을 재실행하면 접근이 완료됩니다.
mmap 영역 접근 시 페이지 폴트 처리 흐름입니다. handle_mm_fault가 VMA 종류와 PTE 상태를 보고 파일 매핑(do_read_fault), 익명 매핑(do_anonymous_page), 쓰기 보호(Write Protection, do_wp_page) 경로로 분기합니다 (개념 개요).

mmap 활용 패턴

/* 파일 전체를 메모리 매핑하여 읽기 */
int fd = open("data.bin", O_RDONLY);
struct stat st;
fstat(fd, &st);
void *map = mmap(NULL, st.st_size, PROT_READ,
                  MAP_PRIVATE, fd, 0);
close(fd);  /* fd는 즉시 닫아도 매핑은 유지됨 */
madvise(map, st.st_size, MADV_SEQUENTIAL);
/* map[0] ~ map[st.st_size-1] 직접 접근 가능 */
munmap(map, st.st_size);

/* 익명 mmap: 큰 메모리 할당 (malloc 내부 방식) */
void *big = mmap(NULL, 1 << 20,  /* 1MB */
                  PROT_READ | PROT_WRITE,
                  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);

/* 공유 메모리: 프로세스 간 통신 */
int mfd = memfd_create("shm", MFD_CLOEXEC);
ftruncate(mfd, 4096);
void *shared = mmap(NULL, 4096,
    PROT_READ | PROT_WRITE, MAP_SHARED, mfd, 0);
/* fork 후 자식과 공유됨, 또는 Unix socket으로 mfd 전달 */
흔한 실수:
  • MAP_FIXED로 기존 매핑 덮어쓰기 — MAP_FIXED는 지정 주소의 기존 매핑을 경고 없이 덮어씁니다. Linux 4.17+에서는 MAP_FIXED_NOREPLACE를 사용하세요.
  • munmap 크기 불일치 — munmap() 크기가 원래 매핑과 다르면 일부만 해제되어 VMA가 분할됩니다. 정확한 크기를 전달하세요.
  • mmap 후 close 안함 — fd를 닫아도 매핑은 유지되므로 즉시 close()해야 fd 누수를 방지합니다.
  • PROT_WRITE|PROT_EXEC 동시 사용 — W^X 보안 정책 위반입니다. JIT 컴파일러는 먼저 PROT_WRITE로 코드를 쓰고, mprotect()로 PROT_EXEC로 전환해야 합니다.

네트워크 소켓

네트워크 통신도 파일 디스크립터(fd) 기반으로 추상화됩니다. socket()이 반환한 fd는 read()/write()로 데이터를 보내고 받을 수 있어 파일 I/O와 같은 인터페이스로 다룰 수 있습니다. 소켓의 핵심 특성인 프로토콜 패밀리(AF_INET=IPv4, AF_INET6=IPv6, AF_UNIX=같은 머신 내 IPC), 타입(SOCK_STREAM=TCP 연결형, SOCK_DGRAM=UDP 비연결형), 프로토콜은 socket()을 생성할 때 결정됩니다. 이후 TCP 서버는 bind → listen → accept, 클라이언트는 connect 순서로 연결을 수립하고, UDP는 connect 없이 sendto/recvfrom을 직접 사용합니다. 소켓 옵션(setsockopt)으로 재사용 허가(SO_REUSEADDR), 버퍼 크기, keep-alive 등을 세밀하게 제어합니다.

TCP 서버·클라이언트 시퀀스 — 3단계 핸드셰이크 서버 프로세스 socket·bind·listen 클라이언트 프로세스 socket·connect listen(fd, backlog) connect(fd, addr) SYN (seq=x) SYN + ACK (seq=y, ack=x+1) ACK (ack=y+1) accept4() → 새 연결 fd 데이터 교환 (read / write) 핸드셰이크는 커널 TCP 스택이 처리하며, 응용 프로그램은 listen·accept·connect만 호출합니다.
TCP 연결 설정 시퀀스입니다. 서버는 socket·bind·listen 후 accept4로 대기하고, 클라이언트 connect가 SYN을 보내면 SYN+ACK·ACK 교환으로 연결이 성립합니다. 이후 양방향 read/write로 데이터를 주고받습니다 (개념 개요).
관련 문서: 네트워크 스택(Network Stack) — sk_buff, TCP 내부, 소켓 계층 | TCP 프로토콜 | UDP 프로토콜 | Netfilter 프레임워크
번호이름시그니처설명
41socketint socket(int domain, int type, int protocol)소켓 파일 디스크립터를 생성합니다. SOCK_NONBLOCK|SOCK_CLOEXEC을 type에 OR할 수 있습니다 (Linux 2.6.27+).
42connectint connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)원격 주소에 연결을 시작합니다. TCP의 경우 3-way handshake를 완료 후 반환. 비블로킹 소켓에서는 EINPROGRESS 반환 후 epoll/select로 완료를 기다립니다.
43acceptint accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)완료된 연결 큐에서 하나를 꺼내 새 소켓 fd를 반환합니다. 연결 없으면 블로킹. accept4 권장.
44sendtossize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest, socklen_t addrlen)UDP에서 목적지를 지정하여 데이터그램을 전송합니다. TCP에서는 dest_addr/addrlen을 NULL/0으로 사용합니다.
45recvfromssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src, socklen_t *addrlen)데이터를 수신하고 송신자 주소를 함께 받습니다. MSG_PEEK로 소비 없이 미리보기 가능합니다.
46sendmsgssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags)scatter/gather 버퍼와 제어 메시지(cmsg — IP_PKTINFO, SCM_RIGHTS 등)를 함께 전송합니다.
47recvmsgssize_t recvmsg(int sockfd, struct msghdr *msg, int flags)scatter/gather 수신 + 보조 데이터(cmsg). MSG_CMSG_CLOEXEC로 fd 수신 시 자동 CLOEXEC 설정.
48shutdownint shutdown(int sockfd, int how)소켓의 일부 또는 전체 방향을 종료합니다. SHUT_RD/WR/RDWR. close()와 달리 fd를 닫지 않습니다.
49bindint bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)소켓에 로컬 주소/포트를 할당합니다. IP=INADDR_ANY(0.0.0.0)이면 모든 인터페이스에서 수신합니다.
50listenint listen(int sockfd, int backlog)소켓을 수신 대기 상태로 만듭니다. backlog는 완료된 연결 큐의 최대 길이입니다 (실제는 /proc/sys/net/core/somaxconn으로 제한).
51getsocknameint getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen)소켓에 할당된 로컬 주소/포트를 가져옵니다. bind(포트 0) 후 실제 할당된 포트 확인에 사용합니다.
52getpeernameint getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen)연결된 원격 소켓의 주소/포트를 가져옵니다.
53socketpairint socketpair(int domain, int type, int protocol, int sv[2])연결된 소켓 쌍을 생성합니다 (AF_UNIX만 지원). pipe보다 양방향 통신에 적합합니다.
54setsockoptint setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen)소켓 옵션을 설정합니다. 중요 옵션은 아래 표를 참고하세요.
55getsockoptint getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen)소켓 옵션의 현재 값을 조회합니다.
181getpmsg—*STREAMS 메시지를 읽기 위한 예약 번호입니다. 표준 커널에는 구현이 없습니다.
182putpmsg—*STREAMS 메시지 전송을 위한 예약 번호입니다. 표준 커널에는 구현이 없습니다.
288accept4int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags)accept에 SOCK_NONBLOCK/SOCK_CLOEXEC을 원자적으로 설정합니다 (현대 서버에서 권장).
299recvmmsgssize_t recvmmsg(int fd, struct mmsghdr *msg, unsigned int vlen, unsigned flags, struct __kernel_timespec *timeout)한 번의 호출로 여러 datagram을 수신합니다. 타임아웃과 플래그를 함께 받습니다.
307sendmmsgssize_t sendmmsg(int fd, struct mmsghdr *msg, unsigned int vlen, unsigned flags)한 번의 호출로 여러 datagram을 전송하고 실제로 보낸 메시지 수를 반환합니다.

* 커널에 구현이 없어 호출하면 -ENOSYS를 반환하는 항목입니다. 제거된 인터페이스는 설명에 제거된 커널 버전을 함께 적었습니다.

socket() domain / type 조합

domaintypeprotocol용도
AF_INETSOCK_STREAM0 (TCP)TCP/IPv4 — 연결 지향, 신뢰성
AF_INETSOCK_DGRAM0 (UDP)UDP/IPv4 — 비연결, 고속
AF_INETSOCK_RAWIPPROTO_ICMP 등Raw 소켓 — 패킷(Packet) 직접 제어 (CAP_NET_RAW 필요)
AF_INET6SOCK_STREAM0TCP/IPv6 (v4-mapped 지원)
AF_UNIXSOCK_STREAM0Unix Domain Socket — 로컬 IPC, 고속
AF_UNIXSOCK_DGRAM0Unix 데이터그램 소켓
AF_UNIXSOCK_SEQPACKET0메시지 경계 보존 신뢰 IPC
AF_NETLINKSOCK_RAWNETLINK_ROUTE 등커널↔유저 제어 채널 (iproute2, nftables 등)
AF_PACKETSOCK_RAWhtons(ETH_P_ALL)L2 원시 패킷 캡처 (tcpdump, Wireshark)
AF_XDPSOCK_RAW0XDP 소켓 — NIC에서 직접 패킷 처리

setsockopt() 주요 옵션

leveloptname설명
SOL_SOCKETSO_REUSEADDRTIME_WAIT 상태의 포트 즉시 재사용 허용 (서버 재시작(Restart) 시 필수)
SOL_SOCKETSO_REUSEPORT여러 프로세스/스레드가 동일 포트를 bind 가능 (로드밸런싱)
SOL_SOCKETSO_KEEPALIVETCP keepalive 활성화 (유휴 연결 감지)
SOL_SOCKETSO_RCVBUF / SO_SNDBUF수신/송신 버퍼 크기 설정
SOL_SOCKETSO_LINGERclose() 시 미전송 데이터 처리 정책 설정
IPPROTO_TCPTCP_NODELAYNagle 알고리즘 비활성화 — 지연 없는 소량 데이터 전송
IPPROTO_TCPTCP_CORK데이터를 모았다가 한 번에 전송 (sendfile과 조합)
IPPROTO_TCPTCP_FASTOPENTFO — SYN 패킷에 데이터를 포함하여 왕복 시간 절감
IPPROTO_TCPTCP_KEEPIDLE/INTVL/CNTkeepalive 파라미터 세부 조정
IPPROTO_IPIP_TOSDSCP/QoS 마킹 설정
IPPROTO_IPIP_MULTICAST_JOIN_GROUP멀티캐스트 그룹 가입

TCP 서버 기본 패턴

/* 최소 TCP 에코 서버 */
int sfd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
int on = 1;
setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));

struct sockaddr_in addr = {
    .sin_family = AF_INET,
    .sin_port   = htons(8080),
    .sin_addr   = { .s_addr = INADDR_ANY },
};
bind(sfd, (struct sockaddr *)&addr, sizeof(addr));
listen(sfd, 128);  /* somaxconn이 실제 상한 */

for (;;) {
    int cfd = accept4(sfd, NULL, NULL,
                      SOCK_CLOEXEC | SOCK_NONBLOCK);
    if (cfd < 0) continue;
    /* 실제 서버: epoll에 cfd 등록 후 비동기 처리 */
    char buf[4096];
    ssize_t n = recv(cfd, buf, sizeof(buf), 0);
    if (n > 0) send(cfd, buf, n, MSG_NOSIGNAL);
    close(cfd);
}
흔한 실수:
  • SO_REUSEADDR 미설정 — 서버 재시작 시 이전 소켓의 TIME_WAIT 상태로 bind()가 EADDRINUSE로 실패합니다. 서버에서는 항상 설정하세요.
  • SIGPIPE 미처리 — 닫힌 소켓에 write()하면 SIGPIPE로 프로세스가 종료됩니다. signal(SIGPIPE, SIG_IGN) 또는 MSG_NOSIGNAL 플래그를 사용하세요.
  • connect() EINPROGRESS 미처리 — 비블로킹 connect()는 즉시 EINPROGRESS를 반환합니다. epoll/poll로 쓰기 가능 상태를 확인한 후 getsockopt(SO_ERROR)로 결과를 확인하세요.
  • accept()에서 EMFILE — fd 한도 초과 시 accept가 영원히 EMFILE을 반환하며 CPU를 100% 사용합니다. 여분의 fd를 하나 확보해두고 EMFILE 시 닫았습니다 열어 소켓을 수거하세요.

시그널

시그널(Signal)은 커널 또는 다른 프로세스가 목표 프로세스에게 특정 이벤트가 발생했음을 알리는 비동기 알림 메커니즘입니다. 예를 들어 Ctrl+C를 누르면 터미널 드라이버가 전경(Foreground) 프로세스 그룹에 SIGINT(2)를 보내고, 자식 프로세스가 종료되면 커널이 부모에게 SIGCHLD(17)를 보냅니다. 각 프로세스는 시그널마다 기본 동작(Default: 종료·무시·중지), 무시(Ignore), 또는 사용자 정의 핸들러(Handler) 세 가지 중 하나를 선택할 수 있습니다. 시그널 전달은 커널이 해당 프로세스를 스케줄링하는 시점(syscall 복귀 직전 또는 인터럽트 복귀 시)에 처리됩니다 — 코드 실행 중 즉각 인터럽트하지 않습니다. SIGKILL(9)과 SIGSTOP(19)은 프로세스가 블록하거나 무시할 수 없으며, 커널이 강제로 처리합니다.

시그널 전달 흐름 — 발생부터 핸들러 실행까지 kill()·tgkill() 사용자 또는 커널 이벤트 do_send_sig_info 대상·권한 검사 pending 큐 등록 task_struct·signal_struct 블록 중이면 대기 sigprocmask 마스크 exit_to_user_mode_loop TIF_SIGPENDING 검사 arch_do_signal_or_restart x86 시그널 처리 진입점 get_signal SIG_DFL·SIG_IGN·핸들러 판별 handle_signal setup_rt_frame: 사용자 스택에 프레임 SIG_DFL 기본 동작 종료·정지·코어 덤프 SIG_IGN 무시 폐기하고 그대로 복귀 핸들러가 반환하면 rt_sigreturn이 프레임을 복원하고, 중단됐던 명령으로 되돌아갑니다.
시그널이 pending 큐에 등록된 뒤 사용자 공간으로 복귀하는 시점에 전달되는 흐름입니다. exit_to_user_mode_loop → arch_do_signal_or_restart → get_signal이 핸들러 실행·기본 동작·무시를 판별합니다 (개념 개요).
관련 문서: IPC — 시그널 내부 동작, signalfd, eventfd | 시스템 콜 — seccomp/ptrace 훅
번호이름시그니처설명
13rt_sigactionint rt_sigaction(int sig, const struct sigaction *act, struct sigaction *oldact, size_t sigsetsize)시그널 핸들러를 등록/조회합니다. sa_flags에 SA_RESTART(중단된 syscall 자동 재시작), SA_SIGINFO(siginfo_t 핸들러), SA_NODEFER(핸들러 내 동일 시그널 허용) 등을 설정합니다.
14rt_sigprocmaskint rt_sigprocmask(int how, const sigset_t *set, sigset_t *oldset, size_t sigsetsize)블록할 시그널 집합을 변경합니다. how=SIG_BLOCK(추가)/SIG_UNBLOCK(제거)/SIG_SETMASK(교체). 블록된 시그널은 마스크 해제 시 전달됩니다.
15rt_sigreturnlong rt_sigreturn(void)시그널 핸들러 종료 후 인터럽트(Interrupt)된 컨텍스트를 복원합니다. 직접 호출하지 않고 커널이 시그널 스택 프레임(Stack Frame)에 자동 삽입합니다.
37alarmunsigned int alarm(unsigned int seconds)seconds 초 후 SIGALRM을 발생시킵니다. 0이면 예약을 취소합니다. 이전 예약의 남은 시간을 반환합니다.
62killint kill(pid_t pid, int sig)프로세스(pid>0), 프로세스 그룹(pid<-1), 자신(-1 또는 0)에게 시그널을 전송합니다. sig=0으로 프로세스 존재 확인 가능.
127rt_sigpendingint rt_sigpending(sigset_t *set, size_t sigsetsize)현재 블록된 상태로 대기 중인 시그널 집합을 가져옵니다.
128rt_sigtimedwaitint rt_sigtimedwait(const sigset_t *set, siginfo_t *info, const struct timespec *timeout, size_t sigsetsize)set에 포함된 시그널 중 하나가 도달할 때까지 대기합니다. timeout으로 최대 대기 시간(Latency) 지정.
129rt_sigqueueinfoint rt_sigqueueinfo(pid_t pid, int sig, siginfo_t *uinfo)시그널과 함께 siginfo_t의 si_value를 다른 프로세스에 전달합니다. si_code를 부여하는 권한이 제한되어 있어 임의 값으로 위조할 수 없습니다.
130rt_sigsuspendint rt_sigsuspend(const sigset_t *mask, size_t sigsetsize)시그널 마스크를 mask로 원자적으로 교체하고 시그널을 기다립니다. EINTR로 반환 후 마스크가 복원됩니다. 경쟁 조건 없는 대기에 사용합니다.
131sigaltstackint sigaltstack(const stack_t *ss, stack_t *oss)시그널 처리용 대체 스택을 설정합니다. 스택 오버플로(Stack Overflow)우(SIGSEGV) 처리에 필수입니다.
200tkillint tkill(pid_t pid, int sig)스레드 ID로 시그널을 보냅니다. tgkill(234)이 tgid까지 지정해 오발송을 막으므로 최신 코드는 tgkill을 사용합니다.
234tgkillint tgkill(pid_t tgid, pid_t tid, int sig)멀티스레드 프로세스에서 특정 스레드에 시그널을 전송합니다. kill(tid)와 달리 tid 재사용에 의한 경쟁 없이 안전합니다.
282signalfdint signalfd(int ufd, const sigset_t *mask, size_t sizemask)mask에 지정한 시그널을 파일 디스크립터로 수신합니다(ufd가 -1이면 새로 생성). flags를 받는 signalfd4(289)가 이후 추가되어 현재는 signalfd4가 사용됩니다.
289signalfd4int signalfd4(int fd, const sigset_t *mask, size_t sizemask, int flags)mask의 시그널을 fd에서 read()로 동기 수신합니다. epoll과 통합하여 이벤트 루프(Event Loop)로 처리 가능합니다 (SFD_NONBLOCK, SFD_CLOEXEC).
297rt_tgsigqueueinfoint rt_tgsigqueueinfo(pid_t tgid, pid_t pid, int sig, siginfo_t *uinfo)특정 스레드(tid)에 siginfo를 포함한 실시간 시그널을 보냅니다.

표준 시그널 참조 (x86_64)

번호이름기본 동작설명 / 주요 발생 원인
1SIGHUP종료제어 터미널 연결 해제, 데몬의 설정 재로드 관례로 사용
2SIGINT종료Ctrl+C — 포그라운드 프로세스 그룹에 전달
3SIGQUIT코어덤프+종료Ctrl+\ — SIGINT와 유사하나 코어 생성
4SIGILL코어덤프+종료잘못된 CPU 명령어 실행
5SIGTRAP코어덤프+종료디버거 breakpoint, ptrace 트랩
6SIGABRT코어덤프+종료abort() 호출, assert() 실패
7SIGBUS코어덤프+종료버스(Bus) 오류 — 정렬되지 않은 메모리 접근, mmap 영역 접근 오류
8SIGFPE코어덤프+종료부동 소수점/정수 나누기 0, 오버플로우
9SIGKILL종료 (강제)즉시 종료 — 블록/무시 불가. OOM killer가 사용
10SIGUSR1종료사용자 정의 — Nginx worker 재로드, 로그 로테이션 등
11SIGSEGV코어덤프+종료잘못된 메모리 접근 (NULL 역참조, 스택 오버플로우 등)
12SIGUSR2종료사용자 정의 — 애플리케이션별 커스텀 용도
13SIGPIPE종료읽는 쪽이 닫힌 파이프/소켓에 쓰기 — SIG_IGN 처리 관례
14SIGALRM종료alarm() 타이머 만료
15SIGTERM종료정상 종료 요청 — systemd stop, kill 기본값
17SIGCHLD무시자식 프로세스 종료/중지 알림 — waitpid() 연계
18SIGCONT계속SIGSTOP/SIGTSTP로 중지된 프로세스 재개
19SIGSTOP중지 (강제)프로세스 일시 정지 — 블록/무시 불가
20SIGTSTP중지Ctrl+Z — 블록/무시 가능
29SIGIO종료비동기 I/O 완료 알림 (F_SETOWN + O_ASYNC)
30SIGPWR종료전원 이상 알림 (UPS 등)
31SIGSYS코어덤프+종료잘못된 syscall 호출 — seccomp 필터가 활용
34~64SIGRTMIN~SIGRTMAX종료실시간 시그널 — 큐잉 보장, 순서 보장(Ordering), 추가 데이터 전달 가능

시그널 핸들러 등록 패턴

/* 안전한 시그널 핸들러 패턴 */
static volatile sig_atomic_t got_signal = 0;

static void handler(int sig) {
    got_signal = 1;  /* sig_atomic_t만 안전하게 쓸 수 있음 */
}

struct sigaction sa = {
    .sa_handler = handler,
    .sa_flags   = SA_RESTART,  /* 중단된 syscall 자동 재시작 */
};
sigemptyset(&sa.sa_mask);
sigaction(SIGTERM, &sa, NULL);
sigaction(SIGINT,  &sa, NULL);

/* 이벤트 루프에서 시그널 처리 (signalfd 방식) */
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGTERM);
sigprocmask(SIG_BLOCK, &mask, NULL);
int sigfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
/* sigfd를 epoll에 등록하면 이벤트 루프에서 시그널 처리 가능 */
시그널 핸들러 안전 규칙:
  • async-signal-safe 함수만 호출 — 핸들러 내에서 printf(), malloc(), exit() 등은 데드락(Deadlock)을 유발할 수 있습니다. 안전한 함수: write(), _exit(), signal(), sigaction(), read() 등 (man 7 signal-safety 참조).
  • volatile sig_atomic_t만 공유 — 핸들러에서 전역 변수를 수정하려면 volatile sig_atomic_t 타입만 안전합니다.
  • SA_RESTART 설정 — 이 플래그가 없으면 시그널이 read(), write(), accept() 등을 EINTR로 중단시킵니다.
  • signalfd 권장 — 시그널을 fd로 변환하면 이벤트 루프에서 안전하게 처리할 수 있으며, 비동기 핸들러의 복잡성을 제거합니다.

IPC (프로세스 간 통신)

IPC(Inter-Process Communication)는 서로 다른 프로세스 간에 데이터를 교환하거나 실행을 동기화하는 메커니즘입니다. 프로세스는 기본적으로 독립된 가상 주소 공간을 사용하므로 포인터를 직접 공유할 수 없고, 커널이 중개하는 공유 채널이 필요합니다. Linux의 IPC 메커니즘은 특성에 따라 선택합니다: 파이프(pipe)는 부모-자식 간 단방향 스트림, Unix 도메인 소켓은 양방향·권한 전달·fd 공유가 가능한 범용 IPC, 공유 메모리(shared memory)는 대용량 데이터를 복사 없이 교환하는 최고 성능 방법, futex는 잠금 경합(Lock Contention)이 없는 경우 syscall을 생략하는 빠른 동기화 기본 요소입니다. 현대적 설계에서는 futex(잠금), Unix socket(메시지), memfd+mmap(대용량 공유 메모리)을 조합하여 사용합니다.

관련 문서: IPC — pipe/Unix socket, futex, System V IPC | 동기화 기법
IPC 메커니즘 비교 — 커널 버퍼 경유와 메모리 공유 커널 버퍼 경유 — 데이터 복사 발생 공유 메모리 직접 접근 — 복사 없음 pipe·FIFO 단방향 스트림 socketpair 양방향 소켓 메시지 큐 메시지 단위 시그널 알림 전용 POSIX shm shm_open + mmap memfd_create 익명 파일 공유 mmap MAP_SHARED 파일·익명 공유 futex 공유 워드 대기 동기화 불필요 커널이 복사와 순서를 보장 동기화 필요 futex·세마포어로 순서 보장 메시지 큐·시그널도 커널 객체를 거치므로 데이터 복사가 일어납니다.
IPC 메커니즘을 데이터 경로 기준으로 나눈 비교입니다. pipe·socketpair·메시지 큐·시그널은 커널 버퍼를 경유해 복사가 일어나고, 공유 메모리·memfd·futex는 사용자 메모리를 직접 공유하므로 futex·세마포어로 동기화해야 합니다 (개념 개요).
futex 동작 원리 — FUTEX_WAIT과 FUTEX_WAKE *uaddr == val 확인 다르면 즉시 EAGAIN 큐 등록 준비 futex_q 초기화 FUTEX_WAIT: 잠들기 해시 버킷 큐에서 대기 *uaddr = new 사용자 코드가 값 변경 FUTEX_WAKE 호출 wake N waiters N개 태스크 재개 wake_up_q futex word (uaddr) 32비트 공유 값 futex 해시 버킷 struct futex_hash_bucket 대기자 연결 리스트 FUTEX_WAIT은 값이 다르면 즉시 EAGAIN을 반환하고, FUTEX_WAKE는 N개의 대기자만 깨웁니다.
futex는 커널이 공유 워드(uaddr)를 해시(Hash) 버킷으로 관리하는 구조입니다. FUTEX_WAIT은 값이 같을 때만 큐에 등록하고, FUTEX_WAKE는 버킷에서 대기자를 찾아 요청한 수만큼 깨웁니다 (개념 개요).
번호이름시그니처설명
22pipeint pipe(int pipefd[2])단방향 통신용 파이프를 생성합니다. fd[0]은 읽기 전용, fd[1]은 쓰기 전용이며 기본 커널 버퍼는 16페이지(보통 64KiB)입니다. fcntl(F_SETPIPE_SZ)로 키울 수 있고, 상한은 /proc/sys/fs/pipe-max-size(기본 1MiB, Linux 2.6.35+)입니다.
29shmgetint shmget(key_t key, size_t size, int shmflg)System V 공유 메모리 세그먼트를 생성하거나 기존 것을 가져옵니다. IPC_CREAT|0666 플래그로 생성하며, 반환된 shmid로 shmat에서 연결합니다.
30shmatvoid *shmat(int shmid, const void *shmaddr, int shmflg)공유 메모리 세그먼트를 프로세스 주소 공간에 매핑합니다. shmaddr=NULL이면 커널이 적절한 주소를 선택합니다. SHM_RDONLY로 읽기 전용 연결 가능.
31shmctlint shmctl(int shmid, int cmd, struct shmid_ds *buf)공유 메모리 세그먼트를 제어합니다. IPC_RMID로 삭제, IPC_STAT으로 상태 조회, IPC_SET으로 권한 변경.
64semgetint semget(key_t key, int nsems, int semflg)System V 세마포어(Semaphore) 집합을 생성하거나 가져옵니다. nsems개의 세마포어가 하나의 집합을 이룹니다.
65semopint semop(int semid, struct sembuf *sops, size_t nsops)세마포어 집합에 P(sem_op 음수)/V(sem_op 양수) 연산을 수행합니다. SEM_UNDO 플래그로 프로세스 종료 시 자동 롤백(Rollback)됩니다.
66semctlint semctl(int semid, int semnum, int cmd, unsigned long arg)세마포어 집합의 값·권한·통계를 조회하거나 설정합니다.
67shmdtint shmdt(const void *shmaddr)프로세스 주소 공간에서 공유 메모리 세그먼트의 연결을 해제합니다. 세그먼트 자체는 삭제되지 않습니다.
68msggetint msgget(key_t key, int msgflg)System V 메시지 큐를 생성하거나 가져옵니다. 타입 필드로 우선순위(Priority) 기반 수신이 가능합니다.
69msgsndint msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg)메시지 큐에 메시지를 전송합니다. msgp는 long mtype으로 시작하는 구조체이며, IPC_NOWAIT로 비블로킹 송신이 가능합니다.
70msgrcvssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg)메시지 큐에서 메시지를 수신합니다. msgtyp=0이면 첫 메시지, 양수면 특정 타입, 음수면 절댓값 이하 중 가장 낮은 타입을 수신합니다.
71msgctlint msgctl(int msqid, int cmd, struct msqid_ds *buf)메시지 큐의 권한·통계를 조회하거나 큐를 제거합니다.
202futexlong futex(uint32_t *uaddr, int futex_op, uint32_t val, ...)사용자 공간(User Space) 원자 연산과 커널 대기 큐(Wait Queue)를 결합한 빠른 잠금 원시 연산입니다. pthread_mutex, pthread_cond, Go runtime의 기반. FUTEX_WAIT/FUTEX_WAKE가 핵심 오퍼레이션입니다.
220semtimedopint semtimedop(int semid, struct sembuf *sops, size_t nsops, const struct timespec *timeout)타임아웃을 지정할 수 있는 semop의 확장입니다. NULL 타임아웃이면 semop와 동일하게 동작합니다.
240mq_openmqd_t mq_open(const char *name, int oflag, mode_t mode, struct mq_attr *attr)POSIX 메시지 큐를 생성하거나 엽니다. /name 형식의 이름으로 식별되며 fd처럼 사용합니다.
241mq_unlinkint mq_unlink(const char *name)POSIX 메시지 큐 이름을 제거합니다.
242mq_timedsendint mq_timedsend(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned msg_prio, const struct timespec *abs_timeout)POSIX 메시지 큐에 우선순위와 타임아웃을 지정하여 메시지를 전송합니다.
243mq_timedreceivessize_t mq_timedreceive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned *msg_prio, const struct timespec *abs_timeout)POSIX 메시지 큐에서 가장 높은 우선순위 메시지를 타임아웃을 지정하여 수신합니다.
244mq_notifyint mq_notify(mqd_t mqdes, const struct sigevent *notification)큐에 메시지가 도착할 때 시그널이나 스레드로 통지받도록 등록합니다.
245mq_getsetattrint mq_getsetattr(mqd_t mqdes, const struct mq_attr *mqstat, struct mq_attr *omqstat)POSIX 메시지 큐의 속성을 조회·설정합니다. 보통 mq_open() 내부에서 사용됩니다.
290eventfd2int eventfd2(unsigned int initval, int flags)64비트 카운터를 fd로 추상화한 이벤트 알림 메커니즘입니다. write(fd, &1, 8)로 신호, read(fd, &v, 8)로 수신합니다. epoll과 조합하여 사용합니다.
293pipe2int pipe2(int pipefd[2], int flags)O_CLOEXEC(exec 시 자동 닫기), O_NONBLOCK(비블로킹) 플래그를 원자적으로 지정하여 파이프를 생성합니다. 모던 코드에서 pipe 대신 권장됩니다.
449futex_waitvint futex_waitv(struct futex_waitv *waiters, unsigned int nr_futexes, unsigned int flags, struct timespec *timeout, clockid_t clockid)FUTEX2 계열: 여러 futex를 벡터로 한 번에 대기합니다 (Linux 5.16+). Wine/Proton의 멀티 오브젝트 대기 구현에 사용됩니다.
454futex_wakeint futex_wake(void *uaddr, unsigned long mask, int nr, unsigned int flags)FUTEX2 계열: 지정한 futex에서 최대 nr개의 대기자를 깨움니다 (Linux 6.7+). mask로 깨울 waiter를 선택하며, 기존 FUTEX_WAKE_BITSET 오퍼레이션을 독립 syscall로 분리한 형태입니다.
455futex_waitint futex_wait(void *uaddr, unsigned long val, unsigned long mask, unsigned int flags, struct timespec *timeout, clockid_t clockid)FUTEX2 계열: 단일 futex 대기 (Linux 6.7+). 기존 FUTEX_WAIT_BITSET 오퍼레이션을 독립 syscall로 분리하여 타입 검사와 확장성을 개선합니다. FUTEX_PRIVATE_FLAG는 flags 인자로 전달합니다.
456futex_requeueint futex_requeue(struct futex_waitv *waiters, unsigned int flags, int nr_wake, int nr_requeue)FUTEX2 계열: 대기 중인 waiter를 다른 futex로 재큐잉합니다 (Linux 6.7+). 기존 FUTEX_CMP_REQUEUE를 개선한 버전으로, struct futex_waitv로 소스·목적지 futex를 지정합니다.

Linux 6.7부터: futex2 시스템 콜 패밀리(futex_wake 454, futex_wait 455, futex_requeue 456)가 완성되었습니다. 기존 다중화(Multiplexing)된 futex() 인터페이스의 각 오퍼레이션을 독립 syscall로 분리하여 타입 안전성과 유지보수성을 높입니다. glibc가 래퍼를 제공하기 전까지는 syscall(SYS_futex_wait, ...) 형태로 직접 호출해야 합니다.

IPC 활용 패턴

/* pipe2: 부모-자식 간 스트림 통신 */
int pfd[2];
pipe2(pfd, O_CLOEXEC);
if (fork() == 0) {
    close(pfd[0]);  /* 자식: 읽기 끝 닫기 */
    write(pfd[1], "hello", 5);
    _exit(0);
}
close(pfd[1]);  /* 부모: 쓰기 끝 닫기 */
char buf[64];
read(pfd[0], buf, sizeof(buf));

/* eventfd: 스레드/프로세스 간 이벤트 알림 */
int efd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
/* 생산자: 카운터 증가 */
uint64_t val = 1;
write(efd, &val, sizeof(val));
/* 소비자: 카운터 읽기 (읽으면 0으로 초기화) */
read(efd, &val, sizeof(val));
/* epoll에 efd 등록하면 생산자 알림을 이벤트 루프에서 처리 */

시간 & 타이머

정확한 시간 측정과 타이머 기반 이벤트 처리는 네트워크 프로토콜(타임아웃·재전송(Retransmission)), 실시간 제어(주기 작업), 성능 분석(latency 측정) 등 광범위한 영역에서 필요합니다. Linux는 여러 종류의 시계(Clock)를 제공합니다: CLOCK_REALTIME은 벽시계(Wall Clock) 시간으로 NTP 조정의 영향을 받으며, CLOCK_MONOTONIC은 항상 단조 증가하여 경과 시간 측정에 안전하고, CLOCK_BOOTTIME은 슬립(Sleep) 중에도 계속 흐르며, CLOCK_TAI는 윤초(Leap Second)를 포함한 국제 원자시입니다. clock_gettime과 gettimeofday는 vDSO(virtual Dynamic Shared Object)를 통해 커널 진입 없이 사용자 공간에서 직접 실행되므로 일반 syscall의 진입/복귀 오버헤드를 없앨 수 있습니다. 고해상도 타이머(hrtimer)가 필요할 때는 CLOCK_MONOTONIC을 우선 사용하세요.

관련 문서: 타이머 — hrtimer, timer wheel | ktime/Clock — clocksource, vDSO, NTP/PTP
vDSO와 timerfd — 커널 진입 여부 비교 vDSO 경로 — 커널 진입 없음 timerfd 경로 — 커널 진입 발생 clock_gettime(CLOCK_MONOTONIC) glibc가 vDSO 함수 선택 __vdso_clock_gettime 커널이 매핑한 읽기 전용 코드 timespec 반환 syscall 명령 실행 없음 timerfd_create·timerfd_settime hrtimer 등록 만료 시 fd 준비 read()·epoll_wait()로 확인 이벤트 대기·깨우기 커널 진입과 스케줄링 발생 vDSO는 시간 조회만 담당하며, 타이머 대기는 timerfd·epoll·ppoll로 커널을 거칩니다.
시간 처리 경로를 비교합니다. clock_gettime()은 vDSO 코드로 커널 진입 없이 값을 읽고, timerfd는 hrtimer 만료를 fd 준비 이벤트로 바꿔 read()·epoll_wait()가 통지받습니다 (개념 개요).

Clock ID 참조

Clock ID값특성사용 시나리오
CLOCK_REALTIME0실제 시각 (UTC 기준), settable, NTP 조정 영향타임스탬프, 로그 시각 기록
CLOCK_MONOTONIC1단조 증가, 재부팅 후 0 초기화, 불연속 시간 점프 없음 (NTP·adjtime 주파수 보정은 반영)경과 시간 측정, 타임아웃 계산 (권장)
CLOCK_PROCESS_CPUTIME_ID2프로세스의 CPU 사용 시간 합산CPU 프로파일링(Profiling), 벤치마크
CLOCK_THREAD_CPUTIME_ID3현재 스레드의 CPU 사용 시간스레드별 CPU 사용량 측정
CLOCK_MONOTONIC_RAW4NTP/adjtime 조정 없는 순수 하드웨어 클럭정밀 지연 측정 (NTP 간섭 배제)
CLOCK_REALTIME_COARSE5낮은 정밀도지만 매우 빠름 (vDSO 최적화)정밀도가 중요하지 않은 빈번한 시각 조회
CLOCK_MONOTONIC_COARSE6낮은 정밀도의 단조 클럭정밀도 불필요한 경과 시간 측정
CLOCK_BOOTTIME7시스템 부팅 후 경과 시간 (suspend 포함)절전 포함 경과 시간, 타이머 정확도 필요 시
CLOCK_REALTIME_ALARM8CLOCK_REALTIME 기반이지만 RTC 깨우기를 쓸 수 있는 알람 전용 시계timerfd_create로 suspend 상태를 깨우는 알람
CLOCK_BOOTTIME_ALARM9CLOCK_BOOTTIME 기반의 알람 전용 시계 (suspend 시간 포함)절전 상태에서도 동작하는 타임아웃
CLOCK_TAI11국제 원자시(TAI) 기반. 윤초 삽입에 따른 불연속·주파수 보정이 없어 UTC와는 누적 오프셋이 생김통신 프로토콜, 금융 타임스탬프
번호이름시그니처설명
35nanosleepint nanosleep(const struct timespec *req, struct timespec *rem)CLOCK_MONOTONIC 기반 상대 시간 슬립. 실제 수면 시간은 타이머 해상도에 따라 달라질 수 있습니다.
36getitimerint getitimer(int which, struct itimerval *curr_value)ITIMER_REAL·ITIMER_VIRTUAL·ITIMER_PROF 인터벌 타이머의 남은 시간을 조회합니다. ITIMER_REAL은 SIGALRM, VIRTUAL은 SIGVTALRM, PROF는 SIGPROF로 통지합니다.
38setitimerint setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value)인터벌 타이머를 설정합니다. POSIX 타이머(timer_create)보다 해상도와 기능이 제한적입니다.
96gettimeofdayint gettimeofday(struct timeval *tv, struct timezone *tz)마이크로초 정밀도로 현재 시각과 시간대를 가져옵니다. vDSO로 가속. tz는 deprecated, NULL 권장.
100timesclock_t times(struct tms *buf)프로세스와 자식 프로세스의 사용자·시스템 CPU 시간과 경과 시간을 반환합니다. 반환값의 단위는 sysconf(_SC_CLK_TCK)로 확인합니다.
132utimeint utime(const char *filename, const struct utimbuf *times)접근 시각과 수정 시각을 초 단위로 설정합니다. 나노초 해상도나 심볼릭 링크 제어가 필요하면 utimensat(280)을 사용합니다.
159adjtimexint adjtimex(struct timex *buf)NTP 데몬이 사용하는 커널 시계 조정 인터페이스입니다. 주파수 오차, 시간 오프셋, PPS 신호 등을 설정합니다. (CAP_SYS_TIME 필요)
164settimeofdayint settimeofday(struct __kernel_old_timeval *tv, struct timezone *tz)시스템 벽시계 시각과 타임존을 설정합니다(CAP_SYS_TIME 필요). clock_settime(227)과 달리 타임존 인자를 받습니다.
201timetime_t time(time_t *tloc)1970-01-01 UTC 이후 경과한 초를 반환합니다. vDSO로 처리되어 커널 진입 없이 동작하는 경우가 많으며, 해상도가 낮아 경과 시간 측정에는 clock_gettime(228)을 사용합니다.
222timer_createint timer_create(clockid_t clkid, struct sigevent *sevp, timer_t *timerid)POSIX 인터벌 타이머를 생성합니다. 만료 시 시그널 전달(SIGEV_SIGNAL) 또는 스레드 함수 호출(SIGEV_THREAD) 방식 선택 가능.
223timer_settimeint timer_settime(timer_t timerid, int flags, const struct itimerspec *new_value, struct itimerspec *old_value)POSIX 타이머의 만료 시각과 인터벌을 설정합니다. it_interval을 0이 아니면 반복 타이머로 동작합니다.
224timer_gettimeint timer_gettime(timer_t timerid, struct itimerspec *curr_value)POSIX 타이머의 현재 만료까지 남은 시간과 인터벌을 조회합니다.
225timer_getoverrunint timer_getoverrun(timer_t timer_id)POSIX 타이머 만료가 몇 번 겹쳤는지(오버런) 반환합니다.
226timer_deleteint timer_delete(timer_t timer_id)POSIX 타이머를 삭제합니다.
227clock_settimeint clock_settime(clockid_t clkid, const struct timespec *tp)시스템 실시간 시계를 설정합니다. CAP_SYS_TIME이 필요하며, CLOCK_REALTIME만 설정 가능합니다.
228clock_gettimeint clock_gettime(clockid_t clkid, struct timespec *tp)지정된 시계의 현재 시간을 나노초 정밀도로 가져옵니다. CLOCK_MONOTONIC/CLOCK_REALTIME은 vDSO로 가속됩니다. 가장 널리 쓰이는 시간 syscall.
229clock_getresint clock_getres(clockid_t clkid, struct timespec *res)시계의 해상도(최소 분해능)를 가져옵니다. 일반적으로 1ns이지만 COARSE 클럭은 ~4ms.
230clock_nanosleepint clock_nanosleep(clockid_t clkid, int flags, const struct timespec *req, struct timespec *rem)지정된 시계 기준으로 절대(TIMER_ABSTIME) 또는 상대 시각까지 고해상도 슬립합니다. 시그널 중단 후 나머지 시간은 rem에 반환됩니다.
235utimesint utimes(char *filename, struct __kernel_old_timeval *utimes)접근 시각과 수정 시각을 마이크로초 해상도로 설정합니다.
261futimesatint futimesat(int dfd, const char *filename, struct __kernel_old_timeval *utimes)dirfd 기준 경로의 시각을 마이크로초 해상도로 설정합니다.
283timerfd_createint timerfd_create(clockid_t clkid, int flags)타이머 만료를 fd로 읽을 수 있는 타이머 fd를 생성합니다. epoll/select와 조합하여 이벤트 루프에 타이머를 통합할 때 이상적입니다. TFD_NONBLOCK|TFD_CLOEXEC 권장.
286timerfd_settimeint timerfd_settime(int fd, int flags, const struct itimerspec *new_value, struct itimerspec *old_value)timerfd의 만료 시각과 인터벌을 설정합니다. TFD_TIMER_ABSTIME으로 절대 시각 설정도 가능합니다.
287timerfd_gettimeint timerfd_gettime(int fd, struct itimerspec *curr_value)timerfd의 현재 설정(남은 시간, 인터벌)을 조회합니다.
305clock_adjtimeint clock_adjtime(clockid_t clkid, struct timex *tx)특정 시계(보통 CLOCK_REALTIME)에 adjtimex(159)와 같은 보정을 적용합니다. PTP 하드웨어 클럭 조정에 사용되며 CAP_SYS_TIME이 필요합니다.

보안 & 권한

Linux 보안 모델은 세 가지 기본 질문으로 구성됩니다: "누구인가"(신원/UID·GID), "무엇을 할 수 있는가"(권한/Capabilities), "무엇에 접근할 수 있는가"(정책/LSM). 전통적인 DAC(Discretionary Access Control)는 파일 소유자·그룹·others 3단계 권한 비트로 접근을 제어합니다. 현대 Linux는 여기에 더해 Capabilities(root 권한을 41개 세분화된 능력으로 분리), LSM(SELinux/AppArmor — 강제적 접근 통제), seccomp(syscall 화이트리스트·BPF 필터로 공격 표면 최소화), Namespaces(PID/user/mount/network 등 자원 격리)를 다층으로 결합합니다. 컨테이너(Docker/Kubernetes)의 격리는 이 네 가지 메커니즘의 조합으로 구현됩니다. 관련 syscall은 프로세스가 자신의 자격증명(Credentials)을 변경하거나 보안 정책을 설정하는 데 사용됩니다.

관련 문서: 네임스페이스 — PID/user/mount 격리 | Linux Containers — seccomp, capabilities | eBPF 기반 보안 정책
seccomp-BPF 동작 흐름 — 필터 판정과 결과 분기 syscall 진입 do_syscall_64 seccomp 필터 실행 BPF 프로그램 (cBPF) 반환값 판정 가장 제한적인 값 채택 SECCOMP_RET_ALLOW 필터 통과 — syscall 실행 SECCOMP_RET_ERRNO -errno 반환 (실행 안 함) TRACE / USER_NOTIF 감시자·사용자 프로세스에 위임 SECCOMP_RET_KILL_PROCESS 프로세스 즉시 종료 여러 필터가 등록되면 가장 제한적인(값이 작은) 반환값이 채택됩니다.
seccomp-BPF는 syscall 진입 시 등록된 cBPF 필터를 실행하고 반환값으로 동작을 정합니다. ALLOW·ERRNO·TRACE/USER_NOTIF·KILL_PROCESS로 분기하며, 필터가 겹치면 가장 제한적인 값이 채택됩니다 (개념 개요).

주요 Linux Capabilities

Capability번호허용 행위
CAP_CHOWN0임의로 파일 소유자/그룹 변경 (chown)
CAP_DAC_OVERRIDE1파일 권한 검사 우회 (읽기/쓰기/실행)
CAP_DAC_READ_SEARCH2읽기 권한 및 디렉터리 탐색 권한 우회
CAP_FOWNER3소유자 아닌 파일의 권한 변경 허용
CAP_KILL5임의 프로세스에 시그널 전송
CAP_NET_BIND_SERVICE101024 미만 포트에 바인드 (HTTP, HTTPS 등)
CAP_NET_RAW13RAW/PACKET 소켓 사용, ARP 스푸핑, tcpdump
CAP_SYS_ADMIN21mount, chroot, sethostname 등 광범위한 관리 권한
CAP_SYS_PTRACE19다른 프로세스를 ptrace로 추적/검사
CAP_SYS_TIME25시스템 시계 설정 (clock_settime, adjtimex)
CAP_SYS_MODULE16커널 모듈(Kernel Module) 로드/언로드 (init_module, finit_module)
CAP_MKNOD27특수 파일(디바이스) 생성
CAP_SETUID7임의 UID로 변경 (su, sudo)
CAP_SETGID6임의 GID로 변경
CAP_SETPCAP8허용 집합의 capabilities를 타 프로세스에 부여/회수
CAP_SYS_RAWIO17ioperm/iopl, /dev/mem, /dev/kmem 직접 접근
CAP_SYSLOG34커널 로그 우선순위 변경, kmsg 읽기 (Linux 2.6.37+)
CAP_WAKE_ALARM35시스템 대기 모드 깨우기(Wakeup) 알람 설정 (Linux 3.0+)
CAP_BLOCK_SUSPEND36시스템 suspend 차단 (epoll EPOLLWAKEUP, /proc/sys/wake_lock)
CAP_AUDIT_READ37멀티캐스트 netlink 소켓으로 audit 로그 읽기 (Linux 3.16+)
CAP_PERFMON38perf_event_open, 성능 모니터링 BPF 연산 (Linux 5.8+, CAP_SYS_ADMIN에서 분리)
CAP_BPF39privileged eBPF 연산: 프로그램 로드, 맵 생성, BTF 접근 (Linux 5.8+, CAP_SYS_ADMIN에서 분리)
CAP_CHECKPOINT_RESTORE40체크포인트(Checkpoint)/복원: ns_last_pid 업데이트, clone3 set_tid, /proc/pid/map_files 읽기 (Linux 5.9+, CAP_SYS_ADMIN에서 분리)
CAP_SYS_PACCT20프로세스 계정(acct) 관리
CAP_SYS_TTY_CONFIG26vhangup, 터미널 특권 ioctl
CAP_LEASE28파일 임대(lease) 설정 (fcntl F_SETLEASE)
CAP_LINUX_IMMUTABLE9FS_IMMUTABLE_FL, FS_APPEND_FL inode 플래그 설정
CAP_IPC_LOCK14메모리 잠금(mlock, mmap MAP_LOCKED), HugePage 할당
CAP_IPC_OWNER15System V IPC 객체 권한 검사 우회
CAP_MAC_ADMIN33MAC 구성/상태 변경 (Smack LSM)
CAP_MAC_OVERRIDE32MAC 정책 우회 (Smack LSM)
CAP_AUDIT_CONTROL30커널 감사 시스템 제어 (필터 규칙, 상태)
CAP_AUDIT_WRITE29커널 감사 로그 기록
CAP_SETFCAP31파일에 임의 capabilities 설정 (Linux 2.6.24+, 5.12+ user ns UID 0 매핑)

Linux Namespaces 종류

네임스페이스clone 플래그격리 대상사용 예
Mount (mnt)CLONE_NEWNS파일시스템 마운트 트리컨테이너별 루트 파일시스템
UTSCLONE_NEWUTS호스트명, 도메인명컨테이너별 hostname
IPCCLONE_NEWIPCSystem V IPC, POSIX MQIPC 자원 격리
PIDCLONE_NEWPID프로세스 ID 공간컨테이너 내 PID 1
NetworkCLONE_NEWNET네트워크 인터페이스, 라우팅(Routing), 포트가상 네트워크 스택, veth
UserCLONE_NEWUSERUID/GID 매핑루트리스 컨테이너
CgroupCLONE_NEWCGROUPcgroup 루트 뷰컨테이너별 cgroup 계층
TimeCLONE_NEWTIME시스템 시계 오프셋 (Linux 5.6+)컨테이너별 시간 격리
번호이름시그니처설명
101ptracelong ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data)프로세스를 추적/검사합니다. 디버거(GDB), strace, 샌드박스(Sandbox)의 기반. PTRACE_ATTACH/PTRACE_SYSCALL/PTRACE_PEEKDATA 등의 요청을 사용합니다. Linux 6.16+는 PTRACE_SET_SYSCALL_INFO로 tracee의 syscall 번호·인자·반환값을 아키텍처 독립적으로 원자적 재작성합니다 (기존 PTRACE_GET_SYSCALL_INFO의 역방향).
102getuiduid_t getuid(void)현재 프로세스의 실제 UID를 반환합니다. 프로세스가 root인지 확인할 때 사용합니다.
104getgidgid_t getgid(void)현재 프로세스의 실제 GID를 반환합니다.
105setuidint setuid(uid_t uid)프로세스의 실제/유효 UID를 변경합니다. root에서 일반 사용자로 권한 강하 시 사용 (복귀 불가).
106setgidint setgid(gid_t gid)프로세스의 실제/유효/저장 GID를 변경합니다.
107geteuiduid_t geteuid(void)현재 프로세스의 유효 UID를 반환합니다. setuid 비트가 설정된 실행 파일에서 달라집니다.
108getegidgid_t getegid(void)현재 프로세스의 유효 GID를 반환합니다.
117setresuidint setresuid(uid_t ruid, uid_t euid, uid_t suid)실제/유효/저장 UID를 한 번에 설정합니다. -1은 변경 없음. 권한 강하 후 복귀가 필요한 서버에 사용.
118getresuidint getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)실제/유효/저장 UID를 모두 조회합니다.
119setresgidint setresgid(gid_t rgid, gid_t egid, gid_t sgid)실제/유효/저장 GID를 한 번에 설정합니다.
120getresgidint getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)실제·실효·저장 그룹 ID를 한 번에 조회합니다.
125capgetint capget(cap_user_header_t hdrp, cap_user_data_t datap)스레드의 capabilities 집합(Effective, Permitted, Inheritable)을 조회합니다.
126capsetint capset(cap_user_header_t hdrp, const cap_user_data_t datap)스레드의 capabilities를 설정합니다. Permitted 집합 내에서만 Effective/Inheritable을 변경할 수 있습니다.
157prctlint prctl(int option, unsigned long arg2, ...)프로세스 속성을 제어합니다. PR_SET_NAME(이름 설정), PR_SET_DUMPABLE(coredump 허용), PR_SET_NO_NEW_PRIVS(권한 상승 금지), PR_CAP_AMBIENT(Ambient capabilities) 등.
248add_keykey_serial_t add_key(const char *type, const char *description, const void *payload, size_t plen, key_serial_t keyring)키링에 새 키를 추가하고 시리얼 번호를 반환합니다. type은 user·logon·keyring 등이며, 같은 설명의 키가 이미 있으면 갱신합니다.
249request_keykey_serial_t request_key(const char *type, const char *description, const char *callout_info, key_serial_t dest_keyring)키링에서 키를 찾고, 없으면 커널이 /sbin/request-key를 호출해 키를 생성하게 합니다. 커널 키 관리 서브시스템의 조회 경로입니다.
250keyctllong keyctl(int operation, unsigned long arg2, ...)커널 키링(Keyring)을 관리합니다. KEYCTL_ADD_KEY로 암호화 키 저장, KEYCTL_SEARCH로 조회. LUKS, Kerberos 인증 등에 사용.
272unshareint unshare(int flags)새 네임스페이스를 생성하여 현재 프로세스를 격리합니다. CLONE_NEWNS|CLONE_NEWNET|CLONE_NEWPID 등의 플래그 조합. unshare(1) 명령어의 기반.
308setnsint setns(int fd, int nstype)/proc/<pid>/ns/<type>를 열어 기존 네임스페이스에 가입합니다. 컨테이너 exec 기능의 기반.
317seccompint seccomp(unsigned int operation, unsigned int flags, void *args)syscall 필터링을 설정합니다. SECCOMP_SET_MODE_STRICT(read/write/exit/_exit만 허용), SECCOMP_SET_MODE_FILTER(BPF 필터 지정). PR_SET_NO_NEW_PRIVS 후에만 사용 가능.
318getrandomssize_t getrandom(char *buf, size_t count, unsigned int flags)커널 CSPRNG에서 난수를 채웁니다. GRND_RANDOM·GRND_NONBLOCK 플래그를 지원합니다.
444landlock_create_rulesetint landlock_create_ruleset(const struct landlock_ruleset_attr *attr, size_t size, __u32 flags)Landlock LSM(Linux 5.13+)으로 파일시스템 접근 규칙 집합을 생성합니다. unprivileged 샌드박싱 가능.
445landlock_add_ruleint landlock_add_rule(int ruleset_fd, enum landlock_rule_type rule_type, const void *rule_attr, __u32 flags)Landlock 규칙 집합에 허용 규칙을 추가합니다. LANDLOCK_RULE_PATH_BENEATH로 특정 디렉터리 이하만 허용.
446landlock_restrict_selfint landlock_restrict_self(int ruleset_fd, __u32 flags)현재 스레드에 Landlock 규칙 집합을 적용하여 파일시스템 접근을 제한합니다. 적용 후 철회 불가.
459lsm_get_self_attrint lsm_get_self_attr(unsigned int attr, struct lsm_ctx *ctx, __u32 *size, __u32 flags)현재 프로세스의 LSM(Linux Security Module) 보안 속성을 조회합니다 (Linux 6.8+). 기존 /proc/self/attr/ 인터페이스를 대체하며, 다중 LSM(SELinux + AppArmor 동시 활성) 환경에서 정확한 속성 분리를 지원합니다.
460lsm_set_self_attrint lsm_set_self_attr(unsigned int attr, struct lsm_ctx *ctx, __u32 size, __u32 flags)현재 프로세스의 LSM 보안 속성을 설정합니다 (Linux 6.8+). SELinux의 도메인 전환이나 AppArmor 프로필 전환에 활용됩니다. LSM_FLAG_SINGLE 플래그로 특정 LSM에만 적용할 수 있습니다.
461lsm_list_modulesint lsm_list_modules(__u64 *ids, __u32 *size, __u32 flags)시스템에서 활성화된 LSM 모듈 목록을 LSM ID 배열로 반환합니다 (Linux 6.8+). 다중 LSM 스태킹 환경에서 어떤 모듈이 활성화됐는지 확인하는 데 사용합니다.

Linux 6.8부터: lsm_get_self_attr(), lsm_set_self_attr(), lsm_list_modules() 세 가지 LSM syscall이 추가되었습니다. 기존 /proc/self/attr/ 인터페이스는 단일 LSM 시대에 설계되어 다중 LSM 스태킹 환경에서 정보가 누락되는 문제가 있었습니다. 새 syscall은 LSM ID 기반으로 각 모듈의 속성을 명확히 분리합니다.

Landlock 샌드박싱 패턴 (Linux 5.13+)

/* 파일시스템 접근을 /tmp 아래로만 제한 */
struct landlock_ruleset_attr attr = {
    .handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE |
                         LANDLOCK_ACCESS_FS_WRITE_FILE,
};
int rfd = landlock_create_ruleset(&attr, sizeof(attr), 0);

/* /tmp 아래만 읽기/쓰기 허용 */
int dir = open("/tmp", O_PATH | O_CLOEXEC);
struct landlock_path_beneath_attr rule = {
    .allowed_access = LANDLOCK_ACCESS_FS_READ_FILE |
                      LANDLOCK_ACCESS_FS_WRITE_FILE,
    .parent_fd = dir,
};
landlock_add_rule(rfd, LANDLOCK_RULE_PATH_BENEATH,
                  &rule, 0);
close(dir);

/* 규칙 적용 (되돌릴 수 없음!) */
prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
landlock_restrict_self(rfd, 0);
close(rfd);
/* 이후 /tmp 이외의 파일 접근 시 EACCES */

비동기 I/O & 이벤트

수천~수만 개의 동시 연결을 처리해야 하는 서버(웹 서버, 데이터베이스, 게임 서버)는 각 연결마다 스레드를 만드는 방식으로는 메모리와 문맥 전환(Context Switch) 오버헤드 때문에 확장하기 어렵습니다. 대신 이벤트 기반(Event-Driven) 방식으로 하나의 스레드가 다수의 fd를 감시하며 준비된 fd만 처리합니다. Linux에서 이 역할을 하는 syscall이 epoll입니다 — O(1) 시간에 준비된 fd를 반환하여 select/poll보다 대규모 연결에 효율적입니다. 한 단계 더 나아가 io_uring(Linux 5.1+)은 제출 큐(SQ Ring)와 완료 큐(CQ Ring)를 공유 메모리로 구현하여 I/O 요청과 응답을 syscall 없이 배치로 처리합니다. nginx·libuv·tokio·Redis는 epoll, io_uring이 지원되는 최신 환경에서는 Tokio·Monoio가 io_uring을 활용합니다.

관련 문서: IPC — eventfd, epoll 통합 패턴 | 성능 최적화 — io_uring 배치 처리, 오버헤드(Overhead) 분석
io_uring 링 구조 — 제출(SQ)과 완료(CQ) io_uring_get_sqe() SQE 배열 빈 슬롯 SQ ring 갱신 khead·ktail·kring_mask io_uring_enter() 제출 (SQPOLL이면 생략) 커널 처리 io-wq·파일 연산 io_uring_peek_cqe() 결과 확인 후 재사용 CQE 배열 슬롯 io_uring_cqe CQ ring tail 증가 koverflow 검사 완료(CQE) 작성 khead·ktail·kring_mask SQ·CQ 링은 mmap으로 공유되어 커널과 사용자가 head·tail만 갱신합니다. 완료 순서는 CQ ring의 tail 증가로만 사용자에게 노출됩니다.
io_uring의 두 링 구조입니다. SQE 배열과 SQ ring으로 요청을 제출하면 커널이 처리한 뒤 CQ ring과 CQE 배열에 완료를 기록하고, 사용자는 peek_cqe로 회수합니다 (개념 개요).

epoll / poll / select / io_uring 비교

방식최대 fd시간 복잡도커널→사용자 복사특징
select1024 (FD_SETSIZE)O(n) 매 호출fd_set 비트맵(Bitmap) 전체레거시, POSIX 표준
poll무제한O(n) 매 호출pollfd 배열 전체레거시, select보다 개선
epoll백만+O(1) 이벤트 수발생된 이벤트만레벨/엣지 트리거, 현대 표준
io_uring무제한O(1) 배치공유 링 버퍼(Ring Buffer)(복사 없음)제출+완료 분리, zero-syscall 가능

io_uring 주요 오퍼레이션 타입 (IORING_OP_*)

오퍼레이션설명
IORING_OP_READ / IORING_OP_WRITE파일 읽기/쓰기 (scatter/gather 지원)
IORING_OP_READV / IORING_OP_WRITEV분산/집합 I/O (iovec 배열)
IORING_OP_RECV / IORING_OP_SEND소켓 수신/송신
IORING_OP_ACCEPT연결 수락 (서버 소켓)
IORING_OP_CONNECT서버에 연결 (클라이언트)
IORING_OP_OPENAT / IORING_OP_CLOSE파일 열기/닫기
IORING_OP_STATX파일 메타데이터 조회
IORING_OP_FSYNCfsync 비동기 실행 (IOSQE_FIXED_FILE·IORING_FSYNC_DATASYNC 플래그로 fdatasync 지정)
IORING_OP_TIMEOUT타임아웃 이벤트 등록
IORING_OP_POLL_ADDepoll 스타일 fd 이벤트 등록
IORING_OP_NOP아무 동작 없음 (링 테스트 용도)
IORING_OP_SPLICE데이터 복사 없이 파이프 간 이동
IORING_OP_FIXED_FD_INSTALL고정 파일 fd 설치 (6.8+)
IORING_OP_RENAMEAT / IORING_OP_UNLINKAT파일 이름 변경/제거 (5.11+)
IORING_OP_MKDIRAT / IORING_OP_SYMLINKAT / IORING_OP_LINKAT디렉터리/심볼릭 링크/하드 링크 생성 (5.15+)
IORING_OP_SENDMSG / IORING_OP_RECVMSG소켓 메시지 송수신 (scatter/gather + ancillary data)
IORING_OP_SEND_ZC / IORING_OP_RECV_ZCZero-copy 송수신 (SEND_ZC 6.0+, RECV_ZC 6.15+)
IORING_OP_READ_FIXED / IORING_OP_WRITE_FIXED고정 버퍼 읽기/쓰기
IORING_OP_READ_MULTISHOT단일 SQE로 반복 읽기 (6.7+)
IORING_OP_FUTEX_WAIT / IORING_OP_FUTEX_WAKE / IORING_OP_FUTEX_WAITVfutex 대기/깨우기(Wakeup)/벡터 대기 (6.7+)
IORING_OP_URING_CMD (5.19+) / IORING_OP_URING_CMD128 (6.19+)드라이버별 명령 전달 (128은 128바이트 SQE용)
IORING_OP_PIPE파이프 생성 (6.16+)
IORING_OP_BIND / IORING_OP_LISTEN소켓 바인드/리슨 (6.11+)
IORING_OP_EPOLL_CTL (5.6+) / IORING_OP_EPOLL_WAIT (6.15+)epoll 제어/대기
IORING_OP_FALLOCATE (5.6+) / IORING_OP_FTRUNCATE (6.9+)파일 공간 할당/크기 조정
IORING_OP_SOCKET소켓 생성 (5.19+)
IORING_OP_SETXATTR / IORING_OP_GETXATTR / IORING_OP_FSETXATTR / IORING_OP_FGETXATTR확장 속성 설정/조회 (5.19+)
IORING_OP_WAITID자식 프로세스 대기 (6.7+)
IORING_OP_PROVIDE_BUFFERS / IORING_OP_REMOVE_BUFFERS제공 버퍼 풀 관리 (5.7+)
IORING_OP_TEE / IORING_OP_SHUTDOWN파이프 복제/소켓 셧다운
IORING_OP_SYNC_FILE_RANGE파일 범위 동기화
IORING_OP_TIMEOUT_REMOVE / IORING_OP_LINK_TIMEOUT타임아웃 제거/링크된 타임아웃
IORING_OP_ASYNC_CANCEL비동기 요청 취소
IORING_OP_MADVISE / IORING_OP_FADVISE메모리/파일 힌트 (5.6+)
IORING_OP_MSG_RING링 간 메시지 전달 (5.19+)
IORING_OP_FILES_UPDATE등록된 파일 테이블 업데이트 (5.6+)
IORING_OP_READV_FIXED / IORING_OP_WRITEV_FIXED고정 버퍼 벡터 I/O (6.15+)
IORING_OP_NOP128128바이트 SQE용 NOP (6.19+)
번호이름시그니처설명
7pollint poll(struct pollfd *fds, nfds_t nfds, int timeout)select의 개선판으로 fd 수 제한이 없습니다. 매 호출 시 전체 pollfd 배열을 커널로 복사하는 단점이 있습니다.
23selectint select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)여러 fd를 동시에 감시합니다. fd 수가 1024로 제한되며 매 호출 시 전체 집합을 복사합니다. 레거시, epoll 사용을 권장합니다.
206io_setupint io_setup(unsigned nr_events, aio_context_t *ctx_idp)Linux AIO 비동기 I/O 컨텍스트를 생성합니다. O_DIRECT 파일에서만 진정한 비동기가 보장됩니다 (일반 파일은 실제로 블로킹).
207io_destroyint io_destroy(aio_context_t ctx)AIO 컨텍스트를 파괴하고 진행 중인 요청을 정리합니다.
208io_geteventslong io_getevents(aio_context_t ctx_id, long min_nr, long nr, struct io_event *events, struct timespec *timeout)완료된 AIO 이벤트를 수집합니다. min_nr개 이상 완료될 때까지 대기합니다.
209io_submitlong io_submit(aio_context_t ctx_id, long nr, struct iocb **iocbpp)Linux AIO 요청을 제출합니다. 실제 커널 비동기 I/O 제출.
210io_cancelint io_cancel(aio_context_t ctx_id, struct iocb *iocb, struct io_event *result)진행 중인 AIO 요청 하나를 취소합니다.
213epoll_createint epoll_create(int size)epoll 인스턴스를 만들고 파일 디스크립터를 반환합니다. size는 Linux 2.6.8 이후 무시되지만 0보다 커야 하며, 현재는 epoll_create1(291) 사용이 권장됩니다.
214epoll_ctl_old—*초기 epoll 구현용으로 남은 번호입니다. 현재 커널에는 구현이 없습니다.
215epoll_wait_old—*초기 epoll 구현용으로 남은 번호입니다. 현재 커널에는 구현이 없습니다.
232epoll_waitint epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout)준비된 이벤트가 있을 때까지 대기합니다. 반환값은 준비된 fd 수이며, events[]에만 결과가 채워집니다.
233epoll_ctlint epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)epoll 관심 목록에 fd를 추가(EPOLL_CTL_ADD), 수정(EPOLL_CTL_MOD), 삭제(EPOLL_CTL_DEL)합니다. EPOLLET으로 엣지 트리거 모드 설정.
270pselect6int pselect6(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, const sigset_t *sigmask)시그널 마스크와 nanosecond 타임아웃을 지원하는 select 확장입니다. 시그널과 I/O를 원자적으로 처리할 때 사용합니다.
271ppollint ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *tmo_p, const sigset_t *sigmask)시그널 마스크와 nanosecond 타임아웃을 지원하는 poll 확장입니다.
281epoll_pwaitint epoll_pwait(int epfd, struct epoll_event *events, int maxevents, int timeout, const sigset_t *sigmask, size_t sigsetsize)epoll_wait에 시그널 마스크를 더해 대기 진입과 마스크 적용을 원자적으로 수행합니다.
284eventfdint eventfd(unsigned int count)64비트 카운터를 가진 이벤트 파일 디스크립터(Eventfd)를 만듭니다. write로 카운터를 더하고 read로 0으로 되돌리며, flags를 받는 eventfd2(290)가 이후 추가되었습니다.
291epoll_create1int epoll_create1(int flags)새 epoll 인스턴스를 생성합니다. EPOLL_CLOEXEC 플래그를 항상 지정하는 것을 권장합니다. O(1) 이벤트 통지, 백만 이상의 fd를 효율적으로 처리합니다.
333io_pgeteventsint io_pgetevents(aio_context_t ctx_id, long min_nr, long nr, struct io_event *events, struct __kernel_timespec *timeout, const struct __aio_sigset *sig)io_getevents에 시그널 마스크를 더한 형태입니다.
425io_uring_setupint io_uring_setup(u32 entries, struct io_uring_params *params)고성능 비동기 I/O를 위한 io_uring 인스턴스를 설정합니다 (Linux 5.1+). SQ/CQ 링을 mmap으로 매핑하여 syscall 없이 요청/완료 처리가 가능합니다.
426io_uring_enterint io_uring_enter(unsigned int fd, u32 to_submit, u32 min_complete, u32 flags, const sigset_t *sig, size_t sigsz)SQ에 추가된 요청을 커널에 제출하고 완료를 대기합니다. SQPOLL 모드에서는 이 syscall도 불필요합니다.
427io_uring_registerint io_uring_register(unsigned int fd, unsigned int opcode, void *arg, unsigned int nr_args)io_uring 인스턴스에 파일/버퍼를 미리 등록하여 매 요청 시 참조 카운팅 오버헤드를 제거합니다 (IORING_REGISTER_BUFFERS, IORING_REGISTER_FILES 등).
441epoll_pwait2int epoll_pwait2(int epfd, struct epoll_event *events, int maxevents, const struct __kernel_timespec *timeout, const sigset_t *sigmask, size_t sigsetsize)epoll_pwait의 타임아웃을 나노초 해상도(timespec)로 받는 형태입니다.

* 커널에 구현이 없어 호출하면 -ENOSYS를 반환하는 항목입니다. 제거된 인터페이스는 설명에 제거된 커널 버전을 함께 적었습니다.

epoll 레벨 트리거(LT) vs 엣지 트리거(ET) 비교

epoll LT와 ET — 반환 시점 비교 LT (Level Trigger) ET (Edge Trigger) 데이터 도착 전 epoll_wait 블록 t1: 데이터 도착 준비됨 → 즉시 반환 t2: 남은 데이터 다시 반환 (레벨 유지) 데이터 도착 전 epoll_wait 블록 t1: 엣지 감지 1회만 반환 t2: 변화 없음 반환하지 않음 LT는 남은 데이터가 있는 한 매 epoll_wait마다 준비 상태를 반환합니다. ET는 새 데이터가 도착할 때만 반환하므로 read()로 버퍼를 모두 소진해야 합니다.
epoll의 두 트리거 모드를 비교합니다. LT는 데이터가 남아 있는 동안 epoll_wait가 매번 해당 fd를 반환하고, ET는 상태가 바뀌는 시점에만 반환하므로 버퍼를 모두 읽어야 합니다 (개념 개요).

epoll 이벤트 루프 패턴

int epfd = epoll_create1(EPOLL_CLOEXEC);

/* 서버 소켓을 epoll에 등록 */
struct epoll_event ev = {
    .events = EPOLLIN,
    .data.fd = server_fd,
};
epoll_ctl(epfd, EPOLL_CTL_ADD, server_fd, &ev);

struct epoll_event events[1024];
for (;;) {
    int nfds = epoll_wait(epfd, events, 1024, -1);
    for (int i = 0; i < nfds; i++) {
        if (events[i].data.fd == server_fd) {
            /* 새 연결 수락 후 epoll에 등록 */
            int cfd = accept4(server_fd, NULL, NULL,
                              SOCK_NONBLOCK | SOCK_CLOEXEC);
            ev.events = EPOLLIN | EPOLLET;  /* 엣지 트리거 */
            ev.data.fd = cfd;
            epoll_ctl(epfd, EPOLL_CTL_ADD, cfd, &ev);
        } else {
            /* ET 모드: EAGAIN까지 모든 데이터 읽기 필수 */
            for (;;) {
                ssize_t n = read(events[i].data.fd, buf, sizeof(buf));
                if (n <= 0) break;  /* EAGAIN 또는 EOF */
                process_data(buf, n);
            }
        }
    }
}
흔한 실수:
  • EPOLLET에서 부분 읽기 — 엣지 트리거(Edge Trigger) 모드에서 데이터를 EAGAIN까지 모두 읽지 않으면 남은 데이터에 대한 알림이 오지 않습니다. 반드시 루프로 전부 읽으세요.
  • EPOLLONESHOT 미사용 (멀티스레드) — 여러 스레드가 같은 fd 이벤트를 동시에 처리할 수 있습니다. EPOLLONESHOT으로 한 번 알림 후 비활성화하고, 처리 완료 후 EPOLL_CTL_MOD로 재활성화하세요.
  • dup된 fd와 epoll — close(fd)해도 같은 struct file을 참조하는 다른 fd가 남아있으면 epoll에서 제거되지 않습니다. EPOLL_CTL_DEL을 명시적으로 호출하세요.

기타 시스템 콜

앞서 분류된 카테고리에 속하지 않는 중요한 syscall 목록입니다. 시스템 정보 조회(uname, sysinfo), 리소스 제한(prlimit64: 프로세스별 파일 수·메모리·CPU 시간 한도), 커널 모듈 로딩(finit_module), eBPF(bpf(): 커널에 안전하게 검증된 프로그램을 주입하는 혁신적 인터페이스), 성능 분석(perf_event_open(): PMU 하드웨어 카운터·tracepoint 접근)이 여기에 해당합니다. 특히 bpf()는 클래식 BPF(패킷 필터)에서 출발해 현재는 네트워킹(XDP), 보안(seccomp-BPF, BPF-LSM), 관측성(bpftrace, BCC), 스케줄러(sched_ext) 등 커널 전반을 사용자 프로그램이 안전하게 확장하는 플랫폼으로 발전했습니다. prlimit64는 데몬/서버 프로세스의 열린 파일 수(RLIMIT_NOFILE)·잠금 가능 메모리(RLIMIT_MEMLOCK)·코어 덤프 크기(RLIMIT_CORE) 등을 운영 환경에 맞게 튜닝하는 데 필수입니다.

RLIMIT 리소스 종류

리소스값단위설명
RLIMIT_CPU0초CPU 시간 제한. 초과 시 SIGXCPU 전달
RLIMIT_FSIZE1바이트파일 크기 최대값. 초과 시 SIGXFSZ
RLIMIT_DATA2바이트데이터 세그먼트(힙+BSS) 크기 한도
RLIMIT_STACK3바이트스택 크기 한도 (기본 8MiB)
RLIMIT_CORE4바이트코어 덤프 파일 크기 한도 (0이면 생성 안함)
RLIMIT_NOFILE7개수열 수 있는 최대 파일 디스크립터 수 (기본 1024)
RLIMIT_AS9바이트가상 주소 공간 최대 크기
RLIMIT_NPROC6개수사용자가 생성할 수 있는 최대 프로세스/스레드 수
RLIMIT_MEMLOCK8바이트메모리에 잠글 수 있는 최대 바이트 수 (mlock)
RLIMIT_LOCKS10개수파일 잠금/lease 최대 수
RLIMIT_SIGPENDING11개수대기 시그널 최대 수
RLIMIT_MSGQUEUE12바이트POSIX 메시지 큐 총 바이트 한도
RLIMIT_NICE13우선순위nice 값의 최대 상향 한도
RLIMIT_RTPRIO14우선순위실시간 스케줄링 최대 우선순위
RLIMIT_RTTIME15마이크로초실시간 프로세스 연속 CPU 시간 한도

eBPF 프로그램 타입 (bpf() 주요 용도)

프로그램 타입연결점주요 사용 시나리오
BPF_PROG_TYPE_SOCKET_FILTER소켓패킷 필터링, tcpdump 대체
BPF_PROG_TYPE_KPROBE커널 함수 진입/반환함수 추적, 인자/반환값 감시
BPF_PROG_TYPE_TRACEPOINT커널 트레이스포인트syscall 진입/반환, 스케줄러(Scheduler) 이벤트
BPF_PROG_TYPE_XDPNIC 드라이버 레벨초고속 패킷 처리, DDoS 완화
BPF_PROG_TYPE_TCTC (traffic control)네트워크 QoS, 패킷 리다이렉트
BPF_PROG_TYPE_PERF_EVENTperf 이벤트PMU 카운터, CPU 프로파일링
BPF_PROG_TYPE_CGROUP_SKBcgroup 소켓컨테이너별 네트워크 정책
BPF_PROG_TYPE_LSMLSM 훅커널 보안 정책 (BPF-LSM, Linux 5.7+)
BPF_PROG_TYPE_SK_LOOKUP소켓 룩업소켓 선택 정책 커스터마이즈
BPF_PROG_TYPE_SYSCALLsyscall 추적syscall 인자 검사, seccomp 보완
번호이름시그니처설명
63unameint uname(struct utsname *buf)커널 이름(sysname), 호스트명(nodename), 릴리즈(release), 버전(version), 아키텍처(machine) 정보를 가져옵니다.
97getrlimitint getrlimit(int resource, struct rlimit *rlim)프로세스의 리소스 소프트/하드 제한값을 조회합니다. prlimit64 사용을 권장합니다.
98getrusageint getrusage(int who, struct rusage *usage)사용자/시스템 CPU 시간, 메이저/마이너 페이지 폴트 수, 최대 RSS, I/O 횟수 등 리소스 사용 통계를 가져옵니다. RUSAGE_SELF/RUSAGE_CHILDREN/RUSAGE_THREAD로 범위 선택.
99sysinfoint sysinfo(struct sysinfo *info)메모리 총량/여유, 스왑(Swap) 총량/여유, 1/5/15분 부하 평균, 업타임, 프로세스 수를 한 번에 가져옵니다.
103syslogint syslog(int type, char *bufp, int len)커널 로그 링 버퍼를 제어합니다. SYSLOG_ACTION_READ로 읽기, SYSLOG_ACTION_CLEAR로 버퍼 지우기, SYSLOG_ACTION_SIZE_BUFFER로 크기 조회. dmesg 명령어의 기반.
134uselib—*공유 라이브러리를 미리 매핑하던 레거시 콜입니다. x86_64 syscall 테이블에는 이름만 유지되어 있어 호출하면 -ENOSYS를 반환합니다.
139sysfsint sysfs(int option, unsigned long arg1, unsigned long arg2)초기 sysfs(2) 파일시스템 정보 인터페이스입니다. 현재는 사용되지 않습니다.
153vhangupint vhangup(void)현재 tty를 걸어 두고 제어 터미널을 정리합니다. getty·login이 세션을 초기화할 때 사용했습니다(CAP_SYS_TTY_CONFIG 필요).
156_sysctl—*/proc/sys 값을 직접 읽고 쓰던 인터페이스입니다. Linux 5.5에서 제거되어 호출하면 -ENOSYS를 반환합니다.
160setrlimitint setrlimit(int resource, const struct rlimit *rlim)프로세스의 리소스 제한값을 설정합니다. 소프트 한도는 하드 한도 이하, 하드 한도는 CAP_SYS_RESOURCE가 있어야만 상향 가능합니다.
163acctint acct(const char *name)프로세스 계정(Accounting) 기록을 켜고 끄거나 기록 파일을 지정합니다.
167swaponint swapon(const char *specialfile, int swap_flags)스왑 영역(Swap Area)이나 스왑 파일을 활성화합니다(CAP_SYS_ADMIN 필요).
168swapoffint swapoff(const char *specialfile)스왑 영역을 비활성화하고 스왑된 페이지를 메모리로 되돌립니다.
169rebootint reboot(int magic1, int magic2, int cmd, void *arg)시스템 재시작, 전원 끄기, halt, kexec 로드/실행 등을 수행합니다. 실수 방지를 위해 magic1=0xfee1dead, magic2=0x28121969 등 매직 넘버가 필요합니다.
170sethostnameint sethostname(char *name, int len)호스트 이름을 설정합니다(UTS 네임스페이스 단위).
171setdomainnameint setdomainname(char *name, int len)NIS 도메인 이름을 설정합니다.
172ioplint iopl(unsigned int level)x86 전용으로 I/O 권한 수준(IOPL)을 조정합니다.
173iopermint ioperm(unsigned long from, unsigned long num, int on)x86 전용으로 지정한 포트 범위의 입출력(I/O) 권한을 부여합니다.
174create_module—*적재 가능 모듈을 만들던 인터페이스입니다. Linux 2.6에서 제거되었습니다.
175init_moduleint init_module(void *module_image, unsigned long len, const char *param_values)메모리의 ELF 이미지를 커널 모듈로 로드합니다. CAP_SYS_MODULE 필요. 서명 확인(CONFIG_MODULE_SIG) 가능.
176delete_moduleint delete_module(const char *name, unsigned int flags)커널 모듈을 언로드합니다. 사용 중인 모듈은 EBUSY를 반환합니다.
177get_kernel_syms—*커널 심볼 테이블(Symbol Table)을 내보내던 인터페이스입니다. Linux 2.6에서 제거되었습니다.
178query_module—*모듈 정보를 조회하던 인터페이스입니다. Linux 2.6에서 제거되었습니다.
180nfsservctl—*커널 NFS 데몬을 제어하던 인터페이스입니다. Linux 3.1에서 제거되었습니다.
183afs_syscall—*AFS 파일시스템용으로 예약된 번호입니다. 표준 커널에는 구현이 없습니다.
184tuxcall—*TUX 웹 서버용으로 예약된 번호입니다. 표준 커널에는 구현이 없습니다.
185security—*보안 모듈 호출용으로 예약된 번호입니다. 표준 커널에는 구현이 없으며 LSM은 별도 훅을 사용합니다.
212lookup_dcookieint lookup_dcookie(u64 cookie, char *buffer, size_t len)oprofile이 dcookie로 디렉터리 경로를 조회할 때 사용합니다.
236vserver—*Linux-VServer용으로 예약된 번호입니다. 표준 커널에는 구현이 없습니다.
246kexec_loadlong kexec_load(unsigned long entry, unsigned long nr_segments, struct kexec_segment *segments, unsigned long flags)사용자 공간이 준비한 세그먼트를 새 커널로 적재합니다(CAP_SYS_BOOT 필요). 적재한 뒤 reboot(2)에 LINUX_REBOOT_CMD_KEXEC를 지정하면 펌웨어(Firmware) 초기화를 거치지 않고 새 커널로 전환합니다.
298perf_event_openint perf_event_open(struct perf_event_attr *attr, pid_t pid, int cpu, int group_fd, unsigned long flags)하드웨어 PMU 카운터, 소프트웨어 이벤트(page fault, context switch 등), 트레이스포인트를 fd로 접근합니다. perf, BCC, BPFTrace의 기반.
302prlimit64int prlimit64(pid_t pid, int resource, const struct rlimit64 *new, struct rlimit64 *old)64비트 리소스 제한을 조회/설정합니다. pid=0이면 자신에게, 타 PID에는 CAP_SYS_RESOURCE가 필요합니다. 서비스 소켓 수 등 튜닝에 사용합니다.
313finit_moduleint finit_module(int fd, const char *param_values, int flags)파일 디스크립터에서 직접 커널 모듈을 로드합니다. init_module보다 보안적으로 우월합니다 (fd 기반이므로 경로 기반 TOCTOU 없음).
320kexec_file_loadlong kexec_file_load(int kernel_fd, int initrd_fd, unsigned long cmdline_len, const char *cmdline_ptr, unsigned long flags)커널과 initrd 파일을 fd로 넘겨 새 커널을 적재합니다. 커널이 서명을 직접 검증하므로 kexec_load보다 안전한 경로로 사용됩니다(CAP_SYS_BOOT 필요).
321bpfint bpf(int cmd, union bpf_attr *attr, unsigned int size)eBPF 서브시스템을 제어합니다. BPF_PROG_LOAD로 프로그램 로드, BPF_MAP_CREATE로 맵 생성, BPF_PROG_ATTACH로 훅 연결. BCC/libbpf/bpftrace의 기반.
334rseqint rseq(struct rseq *rseq, uint32_t rseq_len, int flags, uint32_t sig)Restartable Sequence를 등록합니다. 시그널/선점(Preemption)으로 중단된 임계 구간을 재시작하는 lock-free 패턴 구현에 사용합니다 (Linux 4.18+).
335uretprobeint uretprobe(void)함수 반환점에 설치된 uretprobe 트램폴린이 호출하여 return probe를 실행하는 syscall입니다 (Linux 6.11+, x86_64/x32 전용, 인자 없음). 브레이크포인트 트랩 대신 syscall을 사용해 return probe 오버헤드를 줄일 수 있습니다. 커널이 주입한 특수 트램폴린 밖에서 호출하면 SIGILL이 전달됩니다.
336uprobeint uprobe(void)최적화된 uprobe 트램폴린이 원본 breakpoint 주소를 회수 주소로 삼아 호출하며, 해당 주소의 uprobe 컨슈머(eBPF 프로그램 등)를 실행합니다 (Linux 6.18+, x86_64 전용, 인자 없음). USDT(Statically Defined Tracing) 5-byte nop 프로브(Probe)를 syscall 기반으로 전환하여 처리량(Throughput)이 크게 개선됩니다. seccomp 필터에서 예외 처리되어 필터링 없이 통과하며, 트램폴린 외부 호출 시 SIGILL을 받습니다.
435clone3long clone3(struct clone_args *args, size_t size)확장된 clone syscall입니다. pidfd 직접 생성, cgroup 지정, 스택 자동 설정 등의 새 기능을 구조체로 전달합니다 (Linux 5.3+).
462msealint mseal(unsigned long start, size_t len, unsigned long flags)VMA 범위를 봉인하여 mprotect/munmap/mmap/mremap으로 수정할 수 없게 합니다 (Linux 6.10+). VM_SEALED 플래그를 설정하며, 이후 수정 시도는 -EPERM을 반환합니다. Chrome, Firefox 등 브라우저 JIT 영역 보호에 활용됩니다.
471rseq_slice_yieldint rseq_slice_yield(void)타임 슬라이스 연장(grant)을 받은 rseq 임계 구간을 일찍 마친 스레드가 CPU를 자발적으로 양보(Yield)하는 syscall입니다 (Linux 7.0+, 인자 없음). 반환값은 1(연장이 유효한 동안 양보 성공) 또는 0(연장 미부여·이미 박탈됨). sched_yield()와 달리 조건부로만 양보하며, 연장 중 이외의 syscall을 호출하면 grant가 즉시 박탈되어 커널 진입 시점에 CPU를 내놓습니다.

* 커널에 구현이 없어 호출하면 -ENOSYS를 반환하는 항목입니다. 제거된 인터페이스는 설명에 제거된 커널 버전을 함께 적었습니다.

시스템 콜의 동작 원리와 각 서브시스템 내용을 담은 문서 목록입니다.

필수 관련 문서:
  • 시스템 콜 (System Call) — syscall 진입 경로, SYSCALL_DEFINE, vDSO, seccomp/ptrace/audit 훅, compat ABI
  • VFS 계층 — 파일 I/O syscall의 커널 내부 경로: superblock, dentry, inode, 페이지 캐시, writeback
  • 프로세스 관리 — fork/clone/execve 내부, task_struct 생명주기, CFS 스케줄러, PID 네임스페이스
  • 메모리 관리 — mmap/VMA 구조, 페이지 폴트, madvise/mprotect 처리 경로, swap
  • 네트워크 스택 — 소켓 syscall의 커널 내부: sk_buff, TCP 상태 머신, NAPI, 라우팅
  • IPC — pipe, futex, System V IPC, eventfd/signalfd/timerfd+epoll 통합
  • 타이머 — hrtimer, timer wheel, jiffies, tickless — 시간 syscall의 기반
  • Linux Containers — seccomp 필터, capabilities, clone 플래그를 활용한 컨테이너 격리
  • BPF/eBPF/XDP — bpf() syscall 상세: eBPF 프로그램 로드, 맵 API, 검증기
  • 성능 최적화 — perf_event_open 활용, io_uring 배치 처리, syscall 오버헤드 분석

참고자료

커널 공식 문서

man 페이지 (Linux Programmer's Manual)

아키텍처별 시스템 콜 테이블

커널 소스 (Bootlin Elixir)

LWN.net 기사

외부 참고 자료