파일 · 권한 · 사용자 관리 13 / 50 · Part 2. Linux 파일 종류와 속성
실습 환경: Rocky Linux 9.8 · Ubuntu 24.04.5 (Docker 격리 컨테이너, 테스트 계정 analyst)
기초편 연계: 「리눅스 시스템 기초」 14. inode와 파일 시스템

1. 들어가며

01편과 02편에서 inode를 "파일의 메타데이터를 담은 구조체"라고 소개했다. 이번 글에서는 inode를 직접 열어 본다. debugfs로 ext4 inode의 실제 필드를 확인하고, inode가 가진 정보와 가지지 않은 정보를 구분한다.

그리고 운영과 관제 모두에 영향을 주는 inode 고갈 을 재현한다. 디스크 용량은 1%만 썼는데 파일을 더 만들 수 없는 상황이다.

「리눅스 시스템 기초 14편」이 inode·링크·타임스탬프를 한 번에 개괄했다면, 이 시리즈는 inode(13편), 링크(14편), 타임스탬프(15편), stat(16편)으로 나누어 각각 깊게 다룬다.


2. 핵심 개념

2-1. inode에 저장되는 정보

필드설명확인
inode 번호파일 시스템 안에서의 고유 번호ls -i, stat %i
종류 + 권한 (mode)파일 종류, 특수 권한, rwxstat %f, %A
UID / GID소유자·그룹 번호stat %u %g
크기바이트 단위stat %s
링크 수이 inode를 가리키는 이름의 수stat %h
타임스탬프atime, mtime, ctime, crtime(birth)stat
블록 위치데이터가 저장된 블록 (ext4는 extent 방식)debugfs stat
확장 속성 참조ACL, SELinux 컨텍스트 등getfattr

2-2. inode에 없는 정보

  • 파일 이름 — 디렉터리 엔트리에 있다.
  • 전체 경로 — 여러 이름(하드 링크)이 같은 inode를 가리킬 수 있어 "하나의 경로"가 정의되지 않는다.
  • 만든 사람의 계정 이름 — 숫자 UID만 있다.

2-3. inode 번호의 범위

inode 번호는 파일 시스템 단위로만 고유 하다. 서로 다른 파일 시스템에는 같은 번호가 존재할 수 있다. 그래서 파일을 정확히 식별하려면 장치 번호 + inode 번호 쌍이 필요하다 (stat의 Device + Inode).


3. 동작 원리

inode 구조와 inode 고갈

3-1. inode 테이블

ext4는 mkfs 시점에 inode 테이블의 크기(= 최대 파일 수)를 고정 한다. 기본값은 용량 대비 비율(bytes-per-inode)로 정해지며, 나중에 늘릴 수 없다. xfs는 필요할 때 inode를 동적으로 할당하므로 ext4보다 고갈 가능성이 낮지만, 전체 용량 중 inode에 쓸 수 있는 비율 상한(imaxpct)은 있다.

3-2. 특별한 inode 번호 (ext4)

번호용도
2루트 디렉터리 (/)
11첫 번째 일반 inode (보통 lost+found)

이번 실습에서는 /data의 lost+found를 미리 지웠기 때문에 첫 파일 a.txt가 inode 11을 받았다.

3-3. 고갈이 일어나는 이유

빈 파일도 inode를 하나 쓴다. 세션 파일, 캐시 조각, 메일 큐처럼 작은 파일이 대량으로 생기는 서비스 에서는 데이터 블록보다 inode가 먼저 소진된다. 이때 커널은 ENOSPC(No space left on device)를 반환한다. 메시지만 보면 용량 부족과 구분되지 않는다.


4. 명령어 실습

inode 고갈 실습을 위해 root가 inode 32개짜리 8MB ext4 볼륨 을 만들어 /mnt/small에 연결했다 (mkfs.ext4 -N 32). 운영 파일 시스템에서 이 실습을 하지 않는다.

# 1) 파일 하나의 inode 정보
cd /data && echo "inode lab" > a.txt && ls -i a.txt
stat -c 'inode=%i links=%h uid=%u mode=%a size=%s blocks=%b' a.txt
df -i /data

# 2) inode 고갈 재현
df -h /mnt/small && df -i /mnt/small
cd /mnt/small/lab && for i in $(seq 1 40); do touch f$i 2>/dev/null || { echo "touch f$i 실패"; break; }; done
touch one-more.txt
df -h /mnt/small && df -i /mnt/small

# 3) (root) debugfs 로 inode 직접 보기 — 읽기 전용 조회
sync
debugfs -R 'stat /a.txt' /root/lab-ext4.img 2>/dev/null | head -14
debugfs -R 'ls -l /' /root/lab-ext4.img 2>/dev/null

debugfs는 기본적으로 읽기 전용 으로 열린다. -w 옵션을 주면 inode를 직접 수정할 수 있어 파일 시스템을 손상시킬 수 있으므로 실습에서도 사용하지 않는다.


5. 실행 결과

실제 실행 결과 — Rocky Linux 9.8 · analyst@rocky9-lab — inode 고갈 재현

실제 실행 결과 — Rocky Linux 9.8 · root@rocky9-lab — debugfs 로 본 inode

텍스트 원본(실제 출력):

[analyst@rocky9-lab ~]$ cd /data && echo "inode lab" > a.txt && ls -i a.txt
11 a.txt
[analyst@rocky9-lab data]$ stat -c 'inode=%i links=%h uid=%u mode=%a size=%s blocks=%b' a.txt
inode=11 links=1 uid=1000 mode=644 size=10 blocks=8
[analyst@rocky9-lab data]$ df -i /data
Filesystem     Inodes IUsed IFree IUse% Mounted on
/dev/loop0      65536    11 65525    1% /data
[analyst@rocky9-lab data]$ df -h /mnt/small && df -i /mnt/small
Filesystem      Size  Used Avail Use% Mounted on
/dev/loop1      7.0M   15K  6.4M   1% /mnt/small
Filesystem     Inodes IUsed IFree IUse% Mounted on
/dev/loop1         32    12    20   38% /mnt/small
[analyst@rocky9-lab data]$ cd /mnt/small/lab && for i in $(seq 1 40); do touch f$i 2>/dev/null || { echo "touch f$i 실패"; break; }; done
touch f21 실패
[analyst@rocky9-lab lab]$ touch one-more.txt
touch: cannot touch 'one-more.txt': No space left on device
[analyst@rocky9-lab lab]$ df -h /mnt/small && df -i /mnt/small
Filesystem      Size  Used Avail Use% Mounted on
/dev/loop1      7.0M   15K  6.4M   1% /mnt/small
Filesystem     Inodes IUsed IFree IUse% Mounted on
/dev/loop1         32    32     0  100% /mnt/small
[root@rocky9-lab ~]# sync
[root@rocky9-lab ~]# debugfs -R 'stat /a.txt' /root/lab-ext4.img 2>/dev/null | head -14
Inode: 11   Type: regular    Mode:  0644   Flags: 0x80000
Generation: 683426729    Version: 0x00000000:00000001
User:  1000   Group:  1000   Project:     0   Size: 10
File ACL: 0
Links: 1   Blockcount: 8
Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x6ab47e53:15dc9d98 -- Thu Sep 24 10:35:15 2026
 atime: 0x6ab47e53:15dc9d98 -- Thu Sep 24 10:35:15 2026
 mtime: 0x6ab47e53:15dc9d98 -- Thu Sep 24 10:35:15 2026
crtime: 0x6ab47e53:15dc9d98 -- Thu Sep 24 10:35:15 2026
Size of extra inode fields: 32
Inode checksum: 0xb77d1f32
EXTENTS:
(0):4139
[root@rocky9-lab ~]# debugfs -R 'ls -l /' /root/lab-ext4.img 2>/dev/null
      2   40755 (2)   1000   1000    4096 24-Sep-2026 10:35 .
      2   40755 (2)   1000   1000    4096 24-Sep-2026 10:35 ..
     11  100644 (1)   1000   1000      10 24-Sep-2026 10:35 a.txt

6. 결과 해석

출력해석
inode=11 links=1 uid=1000 mode=644 size=10 blocks=8inode가 가진 핵심 필드. uid는 숫자
df -i /data → 65536256MB ext4 볼륨의 inode 총량 (기본 비율 적용)
/mnt/small Inodes 32 IUsed 1232개 중 12개는 루트·예약 inode·lab 디렉터리가 사용
touch f21 실패f1~f20의 20개로 남은 inode 20개를 모두 소진
No space left on device용량 부족과 같은 메시지
이후 df -h → 1% / df -i → 100%용량은 충분하지만 inode가 없다
debugfs Inode: 11 Type: regular Mode: 0644inode 11의 종류·권한
User: 1000 Group: 1000이름이 아닌 번호로 저장됨
ctime: 0x6ab47e53:15dc9d98앞은 Unix 초(16진), 뒤는 나노초 관련 확장 필드
crtime생성 시각(birth). stat의 Birth 값의 출처
EXTENTS: (0):4139파일의 0번째 논리 블록이 디스크 블록 4139에 있음
debugfs ls -l / → 11 100644 ... a.txt이름 a.txt는 루트 디렉터리(inode 2)의 엔트리 에 있다. 100644 = 일반 파일(100) + 권한 644

sync를 먼저 실행한 이유도 중요하다. 마운트 중인 파일 시스템의 변경 내용은 메모리에 먼저 쌓이므로, 디스크 이미지를 직접 읽는 도구는 아직 기록되지 않은 변경을 보지 못할 수 있다. 이 점은 라이브 시스템 포렌식에서도 동일하게 적용된다.


7. 보안 관점

주제내용
서비스 거부일반 사용자라도 쓰기 가능한 공용 경로(/tmp)에 대량의 빈 파일을 만들면 같은 파일 시스템의 inode를 소진시킬 수 있다. /tmp를 별도 파티션이나 tmpfs로 분리하는 이유 중 하나다
로그 공백/var의 inode가 고갈되면 새 로그 파일(로테이션)이 생성되지 않아 관제 데이터가 끊긴다
제한디스크 쿼터는 블록뿐 아니라 inode 수(파일 개수) 도 사용자별로 제한할 수 있다
증거의 한계inode에는 이름·경로·계정명이 없다. "누가 만들었나"는 UID → 당시 계정 매핑으로 추가 확인이 필요하다
debugfs 사용 흔적root 권한으로 debugfs -w를 쓰면 ctime까지 바꿀 수 있다. 따라서 타임스탬프는 로그 등 다른 증거와 교차 검증 해야 한다

8. 보안관제 관점

[Detection]  모니터링: /var 파일 시스템 inode 사용률 95% 초과 경보
     ↓
[확인]       df -i /var → IUse% 100
             find /var -xdev -type f -newermt '1 hour ago' | cut -d/ -f1-4 | sort | uniq -c | sort -rn | head
     ↓
[판단]       특정 디렉터리에 1시간 동안 수십만 개 파일 생성 → 장애 또는 악의적 대량 생성
     ↓
[Evidence]   생성 파일 소유 UID, 생성 프로세스(auditd), 최초 생성 시각(birth)
     ↓
[Response]   원인 프로세스 중지 → 불필요 파일 정리 → 로그 수집 공백 구간 기록
관점내용
SIEM용량(df -h)만 수집하는 모니터링은 inode 고갈을 놓친다. inode 사용률 지표 를 함께 수집한다
공백 관리로그 수집이 끊긴 구간은 보고서에 "관측 불가 구간"으로 명시한다. 로그가 없다는 것이 행위가 없었다는 뜻은 아니다
Evidence파일 식별은 장치 + inode로 기록한다. 이름은 바뀔 수 있다

9. 실무에서 자주 발생하는 실수

실수결과예방
No space left를 보고 용량만 확인원인 파악 지연df -h와 df -i를 함께
ext4에서 inode 수를 나중에 늘리려 함불가능작은 파일이 많은 용도는 mkfs 시 -i/-N 조정 또는 xfs 사용
마운트 중인 디스크를 debugfs -w로 수정파일 시스템 손상읽기 전용 조회만, 수정은 언마운트 후
inode 번호만으로 파일 식별다른 FS의 같은 번호와 혼동장치 번호와 함께 기록
수십만 파일 디렉터리에서 rm *인자 길이 초과 오류find DIR -type f -delete

10. 실습 체크리스트

[ ] stat 으로 inode 번호·링크 수·UID·크기를 확인했다
[ ] df -i 로 inode 사용량을 확인했다
[ ] 작은 테스트 볼륨에서 inode 고갈을 재현했다
[ ] 용량은 남았지만 파일 생성이 실패하는 것을 확인했다
[ ] debugfs 로 inode 필드와 extent 를 읽었다
[ ] inode 에 파일 이름이 없다는 것을 debugfs 로 확인했다

11. 핵심 정리

  • inode는 종류·권한·UID/GID·크기·링크 수·타임스탬프·블록 위치를 저장한다. 이름은 없다.
  • inode 번호는 파일 시스템 안에서만 고유하다. 식별은 장치 + inode로 한다.
  • ext4는 mkfs 시점에 inode 수가 고정되고, xfs는 동적으로 할당한다.
  • inode가 고갈되면 용량이 남아도 No space left on device가 발생한다.
  • /var inode 고갈은 로그 생성 실패 → 관제 공백으로 이어진다. inode 사용률도 모니터링한다.
  • debugfs는 읽기 전용으로 조회하고, 타임스탬프는 다른 증거와 교차 검증한다.

12. 다음 편 예고

다음 글 「14. 하드 링크와 심볼릭 링크」 에서는 한 inode에 이름을 여러 개 붙이는 하드 링크와, 경로 문자열을 저장하는 심볼릭 링크를 비교한다. 원본 이름을 바꿨을 때 두 링크가 어떻게 다르게 반응하는지, 그리고 링크가 권한 검사를 우회하지 못한다 는 점을 실제로 확인한다.


참고 자료


시리즈 이동

profile
코드에 숨겨진 위협을 읽고 AI로 보안의 미래를 설계합니다. 프론트엔드 개발 경험을 자산 삼아 더 견고하고 지능적인 보안 운영 시스템을 구축해 나가는 과정을 기록합니다

0개의 댓글