Study · 운영체제 · 권한 검사 · 계정과 권한
열기를 막는 자리는 한 곳이 아니다
cat /etc/shadow 가 Permission denied 로 막힌다. 커널은 어느 지점에서 무엇을 보고 막았을까? 그리고 막는 자리는 하나일까?
tghan@ubuntu:~$ cat /etc/shadow
cat: /etc/shadow: Permission denied
# 왜 막혔는지는 이 화면만 봐서는 알 수 없다 — 막는 자리가 둘이라서다
아래 재생기의 ▶를 누르면 한 스텝씩 진행된다. 금색 테두리가 지금 이야기하는 곳이고, 캡션이 무슨 일이 일어났는지 말해 준다. 굵게 밑줄 친 말은 누르면 뜻이 나온다. 빨간 딱지는 그때 벌어지는 일의 이름이고, 캡션 바로 위 회색 글자는 지금 스텝이 속한 묶음의 이름이다.
카드 아래 회색 줄은 그 일이 실제로 적혀 있는 소스의 파일 이름 : 줄 번호와 함수 이름이다. 글 안에 (:669)처럼 줄 번호만 적힌 것은 바로 앞에 적은 파일의 그 줄이라는 뜻이다. 캡션 한가운데 박힌 긴 영어 이름과 괄호 속 파일 · 줄 번호도 같다 — 건너뛰고 한글만 읽어도 뜻이 통하게 써 두었다.
▶ 를 누르면 cat /etc/shadow 가 어디서 무엇 때문에 막히는지 따라간다. 막는 관문이 하나가 아니라는 것, 그리고 화면에 찍히는 Permission denied 만으로는 어느 관문에서 막혔는지 알 수 없다는 것이 이 장면의 요지다.
키보드 · ← → 한 스텝 · Space 재생/멈춤 · Home 처음
막는 자리는 하나가 아니다. rwx 검사와 LSM 판정이 서로 다른 지점에서 일어나고, 둘 중 하나만 막아도 열기는 실패한다.
어떻게 확인했나
소스 어디를 보고 적었는지와 무엇을 돌려서 쟀는지를 남긴 자리다. 처음 읽을 때는 건너뛰어도 된다.
- inode_permission(fs/namei.c:628)은 rwx 결과를 그대로 돌려주지 않는다 — 마지막 줄이 return security_inode_permission(inode, mask);(:661)이고 그것이 security/security.c:1838 로 간다. 소스에서 확인했다.
- rwx 는 do_inode_permission(fs/namei.c:653) → generic_permission(:521) → acl_permission_check(:438) 순으로 내려간다. 주인 · 그룹 · 나머지 셋 중 하나만 보고 끝나는 것(:468 주인 분기, :471 · :496 의 두 -EACCES)을 확인했다.
- 경로를 지나는 디렉터리마다 x 를 본다 — link_path_walk(fs/namei.c:2578)이 칸마다 may_lookup(:1955)을 부르고, 경로 끝에서만 may_open(:4231)이 inode_permission(:4269)을 부른다.
- root 가 통과하는 것은 rwx 비트 때문이 아니라 능력 때문이다 — generic_permission 이 -EACCES 직전에 CAP_DAC_OVERRIDE(fs/namei.c:558-561)를 본다.
- 이 커널에서 inode_permission 훅을 등록하는 모듈은 SELinux(security/selinux/hooks.c:7710 → 함수는 :3251)와 Smack(security/smack/smack_lsm.c:5178)뿐이다. AppArmor 의 훅 목록에는 없다 — AppArmor 는 file_open(security/apparmor/lsm.c:1790 → 함수는 :464)과 file_permission(:1792) 쪽에 꽂힌다. 목록을 직접 세어 확인했다.
- avc_has_perm_noaudit(security/selinux/avc.c:1144)의 판정은 selinux_inode_permission 안의 rc 에 담긴다(security/selinux/hooks.c:3288). 기록할 것이 없으면 그 값이 그대로 돌아가고(:3296-3297), 기록할 것이 있으면 audit_inode_permission(:3299)을 거친 뒤 역시 같은 rc 를 돌려준다(:3303). 앞서 같은 판정을 캐시에서 찾으면 avc 까지 가지도 않고 0 을 돌려준다(:3270).
- 우분투 24.04(커널 7.0.0-31-generic)에서 확인했다. 켜져 있는 LSM 은 lockdown,capability,landlock,yama,apparmor,ima,evm 이고 — 목록에 apparmor 가 들어 있으며 /sys/module/apparmor/parameters/enabled 도 Y 다. /etc/apparmor.d 에 프로파일 112개가 실려 있다. 그러니 우분투 기본이 AppArmor 라는 것이 맞다. 다만 일반 계정 셸은 /proc/self/attr/apparmor/current 가 unconfined 라 어느 프로파일에도 안 갇혀 있다. 그 상태에서 cat /etc/shadow 를 하니 여전히 EACCES 로 막혔다 — AppArmor 가 이 프로세스를 안 가두는데도 막혔으니, 막은 것은 AppArmor 가 아니라 rwx 검사다. 앞서 소스에서 「AppArmor 훅에 inode_permission 이 없다」고 읽은 것이 실제 기계에서 그대로 나왔다. (이 컴퓨터의 도커로는 못 쟀다 — 컨테이너가 쓰는 호스트 커널이 우분투 커널이 아니라 WSL2 커널이라 AppArmor 가 없다. 같은 랜의 우분투 기계로 쟀다.)
- openat 에서 나온다. 일반 계정으로 strace -e trace=openat cat /etc/shadow 를 하니 openat(AT_FDCWD, "/etc/shadow", O_RDONLY) = -1 EACCES (Permission denied) 한 줄이 찍혔다 — 읽기 전에 여는 자리에서 이미 막힌다.
항목 지도목차 ›
- 계정과 권한
- 1 로그인 — 로그인하면 무슨 일이 일어나나
- 2 계정 만들기 — 계정을 만들면 어디에 무엇이 쓰이나
- 3 권한 주기 — chmod 가 바꾸는 것은 어디에 있나
- 4 권한 검사 — 파일을 열 때 권한을 언제 보나
- 파일과 디렉터리
- 5 파일 만들기 — 파일을 만들면 무엇이 생기나
- 6 디렉터리 — 디렉터리를 만들면 무엇이 생기나
- 7 파일 읽기 — 파일을 읽으면 어디를 거치나
- 8 파일 지우기 — 파일을 지우면 정말 사라지나
- 프로세스
- 9 명령 실행 — 명령 하나를 치면 무슨 일이 벌어지나
- 10 파일 디스크립터 — 프로세스가 파일을 열면 무엇이 늘어나나
- 11 CPU 나누기 — CPU 하나를 여럿이 어떻게 나눠 쓰나
- 메모리
- 12 메모리 요청 — 메모리를 달라고 하면 바로 주나
- 13 페이지 폴트 — 처음 건드릴 때 무슨 일이 일어나나
- 14 OOM — 메모리가 모자라면 누가 죽나
- 네트워크
- 15 소켓 만들기 — 소켓을 만들면 무엇을 받나
- 16 연결 받기 — 연결이 들어오면 누가 먼저 받나
- 17 주고받기 — 데이터가 오갈 때 무엇이 움직이나