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

1. 들어가며

13편에서 inode에는 이름이 없고 이름은 디렉터리 엔트리에 있다는 것을 확인했다. 그렇다면 하나의 inode에 이름을 두 개 붙일 수 있을까? 가능하다. 그것이 하드 링크다. 반면 심볼릭 링크는 이름이 아니라 "대상 경로를 적어 둔 작은 파일" 이다.

두 링크는 겉보기에 비슷하지만 동작은 완전히 다르다. 이번 글에서는 원본 이름을 바꿨을 때 두 링크가 어떻게 반응하는지, 파일 시스템 경계와 디렉터리에서 어떤 제약이 있는지, 그리고 링크가 권한 검사를 우회하지 못한다 는 것을 실습으로 확인한다.


2. 핵심 개념

  • 같은 inode를 가리키는 또 하나의 디렉터리 엔트리
  • 원본과 사본의 구분이 없다. 모든 이름이 동등하다
  • inode의 링크 수가 1 증가한다
  • 만들기: ln 원본 새이름
  • 별도의 inode를 가진 파일이며, 데이터로 대상 경로 문자열 을 저장한다
  • 접근할 때마다 커널이 그 경로를 다시 해석한다
  • 대상이 없어도 존재할 수 있다 (dangling link)
  • 만들기: ln -s 대상 링크이름

2-3. 비교

항목하드 링크심볼릭 링크
inode원본과 같음별도
원본 이름 변경·삭제영향 없음링크 끊어짐
다른 파일 시스템불가가능
디렉터리 대상불가 (루프 방지)가능
크기 표시원본 크기경로 문자열 길이

3. 동작 원리

Hard Link vs Symbolic Link

3-1. 하드 링크가 파일 시스템 경계를 넘지 못하는 이유

디렉터리 엔트리는 "이름 → inode 번호"만 저장한다. inode 번호는 파일 시스템 안에서만 의미가 있으므로(13편), 다른 파일 시스템의 inode를 가리킬 방법이 없다. 커널은 EXDEV(Invalid cross-device link)를 반환한다.

3-2. 디렉터리 하드 링크가 금지된 이유

디렉터리에 하드 링크를 허용하면 a/b/→a 같은 순환이 생겨 find, du, 파일 시스템 검사 도구가 무한 루프에 빠질 수 있고, ..이 가리킬 상위가 여러 개가 된다. 그래서 커널은 .과 .. 외의 디렉터리 하드 링크를 허용하지 않는다.

3-3. 링크와 권한

  • 하드 링크: 같은 inode이므로 권한도 같다. 이름을 하나 더 만든다고 권한이 바뀌지 않는다.
  • 심볼릭 링크: 링크 자체는 항상 lrwxrwxrwx로 보이지만 이 권한은 사용되지 않는다. 커널은 링크를 따라간 대상 파일의 권한 을 검사한다.

즉, 링크는 권한 우회 수단이 아니다. 위험은 다른 곳에 있다. root 권한 프로세스가 사용자가 만든 링크를 따라가 파일을 쓰거나 권한을 바꾸는 경우다. 이를 막기 위해 커널에는 fs.protected_symlinks와 fs.protected_hardlinks 보호 설정이 있다. 커널 자체 기본값은 0이지만, Rocky와 Ubuntu는 systemd 기본 설정(/usr/lib/sysctl.d/50-default.conf 등)으로 부팅 시 1(활성)을 적용한다.


4. 명령어 실습

cd /data && mkdir lab14 && cd lab14

# 1) 하드 링크와 심볼릭 링크 만들기
echo "original" > target.txt
ln target.txt hard.txt
ln -s target.txt soft.txt
ls -li

# 2) 하드 링크로 수정하면 원본도 바뀐다 (같은 inode)
echo "appended via hard" >> hard.txt && cat target.txt

# 3) 원본 이름을 바꾸면?
mv target.txt moved.txt
cat hard.txt
cat soft.txt
ls -l soft.txt
readlink soft.txt ; readlink -f soft.txt

# 4) 같은 inode를 가진 모든 이름 찾기
find . -samefile moved.txt

# 5) 제약 확인
ln /data/lab14/moved.txt /dev/shm/cross.txt   # 다른 파일 시스템
ln /data/lab14 /data/dirlink                   # 디렉터리

# 6) 링크는 권한을 우회하지 못한다
ln -s /etc/shadow shadow-link && ls -l shadow-link && cat shadow-link

5. 실행 결과

실제 실행 결과 — Rocky Linux 9.8 · analyst@rocky9-lab — 하드 링크와 심볼릭 링크

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

[analyst@rocky9-lab ~]$ cd /data && mkdir lab14 && cd lab14
[analyst@rocky9-lab lab14]$ echo "original" > target.txt
[analyst@rocky9-lab lab14]$ ln target.txt hard.txt
[analyst@rocky9-lab lab14]$ ln -s target.txt soft.txt
[analyst@rocky9-lab lab14]$ ls -li
total 8
12 -rw-r--r-- 2 analyst analyst  9 Sep 24 10:35 hard.txt
13 lrwxrwxrwx 1 analyst analyst 10 Sep 24 10:35 soft.txt -> target.txt
12 -rw-r--r-- 2 analyst analyst  9 Sep 24 10:35 target.txt
[analyst@rocky9-lab lab14]$ echo "appended via hard" >> hard.txt && cat target.txt
original
appended via hard
[analyst@rocky9-lab lab14]$ mv target.txt moved.txt
[analyst@rocky9-lab lab14]$ cat hard.txt
original
appended via hard
[analyst@rocky9-lab lab14]$ cat soft.txt
cat: soft.txt: No such file or directory
[analyst@rocky9-lab lab14]$ ls -l soft.txt
lrwxrwxrwx 1 analyst analyst 10 Sep 24 10:35 soft.txt -> target.txt
[analyst@rocky9-lab lab14]$ readlink soft.txt ; readlink -f soft.txt
target.txt
/data/lab14/target.txt
[analyst@rocky9-lab lab14]$ find . -samefile moved.txt
./moved.txt
./hard.txt
[analyst@rocky9-lab lab14]$ ln /data/lab14/moved.txt /dev/shm/cross.txt
ln: failed to create hard link '/dev/shm/cross.txt' => '/data/lab14/moved.txt': Invalid cross-device link
[analyst@rocky9-lab lab14]$ ln /data/lab14 /data/dirlink
ln: /data/lab14: hard link not allowed for directory
[analyst@rocky9-lab lab14]$ ln -s /etc/shadow shadow-link && ls -l shadow-link && cat shadow-link
lrwxrwxrwx 1 analyst analyst 11 Sep 24 10:35 shadow-link -> /etc/shadow
cat: shadow-link: Permission denied

6. 결과 해석

출력해석
12 ... 2 ... hard.txt / 12 ... 2 ... target.txt같은 inode 12, 링크 수 2
13 lrwxrwxrwx ... soft.txt -> target.txt 크기 10별도 inode 13, 크기는 target.txt 문자열 길이
cat target.txt에 추가 내용 표시하드 링크로 쓴 내용이 원본 이름으로도 보임 (같은 데이터)
이름 변경 후 cat hard.txt 정상하드 링크는 이름과 무관하게 inode를 직접 가리킴
cat soft.txt → No such file or directory심볼릭 링크는 target.txt라는 경로 를 찾는데 그 이름이 사라짐
readlink → target.txt / readlink -f → /data/lab14/target.txt링크 내용 / 절대경로로 해석한 대상 (대상이 없어도 경로는 계산됨)
find -samefile → hard.txt, moved.txt같은 inode를 가진 이름을 모두 찾음
Invalid cross-device linkext4(/data) → tmpfs(/dev/shm) 하드 링크 불가
hard link not allowed for directory디렉터리 하드 링크 금지
shadow-link -> /etc/shadow 생성 성공, cat → Permission denied링크는 누구나 어디로든 만들 수 있지만, 읽기 권한은 대상 /etc/shadow가 결정한다

마지막 줄이 보안 관점의 핵심이다. 링크 생성 자체는 권한 상승이 아니다. 문제는 권한이 높은 프로세스가 링크를 따라갈 때 다.


7. 보안 관점

주제설명대응
심볼릭 링크 경쟁(TOCTOU)root 스크립트가 /tmp/report.txt에 쓰려는 순간, 그 이름이 사용자가 만든 링크로 바뀌어 있으면 링크 대상 파일이 root 권한으로 덮어써질 수 있다mktemp 사용, fs.protected_symlinks=1 유지
하드 링크 고정사용자가 SUID 파일에 하드 링크를 만들어 두면 패키지 업데이트 후에도 취약한 옛 버전 inode가 남는다fs.protected_hardlinks=1 (본인 소유가 아니고 읽기·쓰기 권한도 없는 파일에는 하드 링크 금지)
로그 무력화로그·히스토리 파일을 /dev/null 링크로 교체find / -type l -lname /dev/null
웹 루트 링크업로드 디렉터리에 /etc 등을 가리키는 링크 → 웹 서버가 따라가면 정보 노출웹 서버의 심볼릭 링크 추종 옵션 제한 (FollowSymLinks 등)
링크를 따라간 권한 변경root가 chown -R/chmod -R 실행 시 링크 대상 변경 위험-h 옵션, find -type f로 대상 한정

두 커널 보호 설정의 동작:

설정값 1일 때
fs.protected_symlinksSticky Bit가 있는 공용 디렉터리(/tmp)에서, 링크 소유자와 따라가는 프로세스가 다르고 디렉터리 소유자도 아니면 따라가기 거부
fs.protected_hardlinks본인 소유가 아니고 읽기·쓰기 권한도 없는 파일에 대해 하드 링크 생성 거부

8. 보안관제 관점

[Detection]  FIM: /var/www/html/upload/ 에 심볼릭 링크 생성 (→ /etc)
     ↓
[Evidence]   ls -la → cfg -> /etc  (owner=www-data)
             stat cfg → birth 02:31:07
     ↓
[판단]       웹 계정이 업로드 폴더에 시스템 경로 링크 생성 → 파일 노출 시도
     ↓
[Investigation] 웹 로그: GET /upload/cfg/passwd 요청 여부와 응답 코드
     ↓
[Response]   링크 제거, 웹 서버 링크 추종 설정 점검, 업로드 기능 확인
관점내용
점검sysctl fs.protected_symlinks fs.protected_hardlinks 값이 1인지 확인
탐지공용·웹 디렉터리의 신규 심볼릭 링크, /dev/null을 가리키는 로그 파일
IOC 분석하드 링크는 이름이 달라도 같은 inode. 악성 파일 삭제 후에도 다른 이름이 남아 있는지 find -samefile로 확인
Evidence링크는 ls -l의 -> 뒤 경로와 링크 자체의 stat(생성 시각·소유자)을 함께 기록

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

실수결과예방
상대경로 심볼릭 링크를 다른 위치로 이동링크 끊어짐필요한 경우 절대경로 링크
악성 파일 한 이름만 삭제하드 링크로 다른 이름이 남음링크 수 확인 후 find -samefile
lrwxrwxrwx를 보고 "권한 과다"로 판단오탐링크 권한은 사용되지 않음, 대상 권한 확인
cp -r로 링크 포함 디렉터리 백업대상 내용이 복사되거나 순환cp -a, rsync -a
보호 설정을 끄고 문제 해결링크 공격에 노출애플리케이션 경로 설계 수정

10. 실습 체크리스트

[ ] 하드 링크와 원본의 inode 가 같음을 확인했다
[ ] 원본 이름 변경 시 하드 링크는 유지, 심볼릭 링크는 끊어짐을 확인했다
[ ] find -samefile 로 같은 inode 의 이름을 모두 찾았다
[ ] 다른 FS·디렉터리 하드 링크가 거부됨을 확인했다
[ ] /etc/shadow 링크가 권한을 우회하지 못함을 확인했다
[ ] fs.protected_symlinks / protected_hardlinks 의 역할을 설명할 수 있다

11. 핵심 정리

  • 하드 링크는 같은 inode에 붙은 또 하나의 이름이다. 원본·사본 구분이 없다.
  • 심볼릭 링크는 대상 경로 문자열을 담은 별도 파일이며, 대상이 사라지면 끊어진다.
  • 하드 링크는 다른 파일 시스템과 디렉터리에 만들 수 없다.
  • 링크는 권한을 우회하지 못한다. 접근 권한은 항상 대상 inode가 결정한다.
  • 위험은 권한 높은 프로세스가 링크를 따라갈 때 생기며, 커널 보호 설정(protected_symlinks, protected_hardlinks)이 이를 완화한다.
  • 악성 파일 대응 시 링크 수를 확인해 다른 이름이 남아 있는지 점검한다.

12. 다음 편 예고

다음 글 「15. Linux 파일 timestamp 이해하기 (atime·mtime·ctime)」 에서는 네 가지 시간이 각각 어떤 동작에서 바뀌는지 를 하나씩 실험하고, 파일을 두 번 읽어도 atime이 한 번만 바뀌는 relatime 정책을 확인한다.


참고 자료


시리즈 이동

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

0개의 댓글