특수 권한은 9비트 권한 표시의 x 자리에 겹쳐서 나타난다. SetUID는 owner의 x 자리에, SetGID는 group의 x 자리에, Sticky는 other의 x 자리에 표시된다. 원래 x가 있으면 소문자(s/t), x가 없으면 대문자(S/T)로 나온다. 대문자는 "특수 권한은 켜졌지만 실행 권한이 없어 사실상 무의미"한 경고 신호다.
SetUID가 걸린 실행 파일은, 누가 실행하든 그 파일 소유자의 권한으로 동작한다. 대표 예가 /usr/bin/passwd다.
ls -l /usr/bin/passwd# -rwsr-xr-x 1 root root ... /usr/bin/passwd# └ owner의 x 자리에 s = SetUID
passwd 명령은 /etc/shadow를 수정해야 하는데, 이 파일은 root만 쓸 수 있다(권한 000 또는 400). 일반 사용자 alice가 자기 암호를 바꾸려면? passwd에 SetUID가 걸려 있어 소유자(root) 권한으로 실행되기 때문에, alice가 실행하는 순간 그 프로세스는 root 권한으로 shadow를 수정할 수 있다. SetUID가 없으면 일반 사용자는 자기 암호조차 바꿀 수 없다. 이것이 SetUID의 존재 이유다.
⚠️ 함정: SetUID는 최대의 보안 위협 지점이다. SetUID가 걸린 프로그램에 취약점이 있으면 공격자가 root 권한을 탈취(권한 상승)할 수 있다. 특히 셸 스크립트나 vi, cp 같은 범용 도구에 SetUID를 거는 것은 절대 금물이다(cp에 root SetUID가 있으면 누구나 임의 파일을 덮어쓸 수 있음). 그래서 리눅스 커널은 셸 스크립트의 SetUID를 아예 무시한다. 시스템에 의도치 않은 SetUID 파일이 있는지 정기 점검하는 명령이 시험에 나온다:
# SetUID 파일 전체 탐색(보안 감사 표준)find / -perm -4000 -type f 2>/dev/null# SetGID 파일 탐색find / -perm -2000 -type f 2>/dev/null# SetUID + SetGID 모두find / -perm /6000 -type f 2>/dev/null
디렉터리에 걸면(시험 핵심): 그 안에 새로 만드는 파일·하위 디렉터리의 소유 그룹이 자동으로 그 디렉터리의 그룹이 된다.
보통은 파일 생성자의 기본 그룹이 소유 그룹이 되는데, SetGID 디렉터리에서는 디렉터리의 그룹을 물려받는다.
mkdir /project && chgrp dev /project && chmod 2775 /project# 이제 누가 /project 안에 파일을 만들어도 그룹은 항상 dev
SetGID 디렉터리는 그룹 협업의 핵심 도구다. 여러 사람이 한 디렉터리에서 협업할 때, 각자 만든 파일의 그룹이 제각각이면 서로 접근이 막힌다. SetGID를 걸면 모든 파일이 공통 그룹을 갖게 되어, 그 그룹에 그룹-쓰기(g+w)를 부여하면 팀 전체가 서로의 파일을 자유롭게 편집할 수 있다. Day 3에서 "새 파일의 그룹은 생성자의 기본 그룹"이라 했는데, SetGID 디렉터리가 바로 그 예외다.
Day 3에서 "디렉터리에 w 권한이 있으면 그 안의 파일을 (소유자가 아니어도) 삭제할 수 있다"고 했다.
/tmp처럼 모두가 쓰는 디렉터리에서 이건 재앙이다 — 아무나 남의 임시 파일을 지울 수 있다. Sticky bit가 이를 막는다.
ls -ld /tmp# drwxrwxrwt 10 root root ... /tmp# └ other의 x 자리에 t = Sticky
Sticky bit가 걸린 디렉터리에서는, 디렉터리에 w 권한이 있어도 파일의 소유자(또는 디렉터리 소유자, 또는 root)만 그 파일을 삭제·이름 변경할 수 있다. /tmp가 1777(rwxrwxrwt)인 이유가 이것이다. 모두가 파일을 만들 수는 있지만(공용), 남의 파일은 못 지운다(보호). Sticky bit가 없으면 /tmp에서 누구나 남의 파일을 지울 수 있어 보안·안정성 문제가 생긴다.
⚠️ 함정: Sticky bit는 오늘날 디렉터리에만 의미가 있다. 과거(초기 유닉스)에는 실행 파일에 걸어 "프로그램을 메모리/스왑에 상주"시키는 용도였으나(이름 "sticky"의 유래), 현대 커널은 파일에 대한 sticky를 무시한다. 시험에서 "Sticky bit는 파일의 메모리 상주를 위해 쓴다"는 현대 기준 오답이다.
# 직접 쳐보기 — 특수 권한 관찰과 실험ls -l /usr/bin/passwd /usr/bin/sudo # SetUID(s) 확인ls -ld /tmp /var/tmp # Sticky(t) 확인mkdir testdir && chmod 2775 testdir && ls -ld testdir # SetGID(s) 확인touch testdir/a && ls -l testdir/a # 그룹 상속 관찰
1990년대 한 대학 서버에서 /tmp에 Sticky bit가 빠진 적이 있었다. 한 학생이 다른 학생의 컴파일 임시 파일을 장난삼아 지우자 빌드가 줄줄이 실패했고, 더 심각하게는 일부 프로그램이 /tmp에 만든 lock 파일을 누군가 지우거나 심볼릭 링크로 바꿔치기하는 "심링크 공격(symlink attack)"이 가능했다. Sticky bit 도입 후 이런 공격 표면이 닫혔다. 그래서 모든 공유 쓰기 디렉터리(/tmp, /var/tmp)는 반드시 Sticky가 걸려 있어야 한다.
표준 권한의 근본 한계: 한 파일에 대해 단 하나의 소유자, 단 하나의 그룹만 지정할 수 있다.
"alice에게는 rw, bob에게는 r, dev 그룹에게는 rw, 그 외엔 차단"처럼 세분화된 요구는 3칸으로 표현 불가능하다.
ACL(Access Control List)은 파일마다 "사용자별·그룹별 권한 항목 목록"을 추가로 붙여 이 한계를 푼다.
getfacl file.txt # ACL 조회setfacl -m u:bob:r file.txt # bob에게 읽기 부여(-m = modify)setfacl -m g:dev:rw file.txt # dev 그룹에 읽기/쓰기setfacl -x u:bob file.txt # bob의 ACL 항목 제거(-x)setfacl -b file.txt # 모든 ACL 제거(-b = remove all)setfacl -m d:u:bob:rw dir # 기본(default) ACL — 하위에 상속setfacl -R -m u:bob:rw dir # 재귀 적용
getfacl의 출력 구조:
# file: file.txt# owner: alice# group: devuser::rw- ← 소유자(표준 owner)user:bob:r-- ← bob 개별 ACLgroup::rw- ← 소유 그룹(표준 group)group:audit:r-- ← audit 그룹 개별 ACLmask::rw- ← 마스크(ACL 권한의 상한)other::r-- ← 기타(표준 other)
ACL이 설정된 파일은 ls -l에서 권한 끝에 + 기호가 붙는다(-rw-rwxr--+). 이 +를 보면 "이 파일엔 표준 권한 외에 ACL이 있다"는 신호다. 시험에서 "권한 표시 끝의 +는 무엇?"의 정답은 ACL 존재 표시다.
ACL의 mask가 까다로운 포인트다. mask는 "named user/group(이름이 붙은 ACL 항목)과 소유 그룹이 가질 수 있는 권한의 상한선"이다. setfacl -m u:bob:rwx로 bob에게 rwx를 줬어도 mask가 r--이면 bob의 유효 권한은 r에 그친다. getfacl은 마스크에 의해 깎인 항목에 #effective: 주석을 달아 실제 권한을 보여준다. chmod로 그룹 권한을 바꾸면 사실 mask가 바뀌는 것이라, ACL이 있는 파일에 chmod를 걸 때 주의해야 한다.
ACL이 있어도 표준 owner/group/other 권한은 그대로 존재하며, 접근 판정 순서가 있다. ① 사용자가 소유자면 owner 권한 적용 → ② named user ACL에 있으면 그 항목 적용 → ③ 소유 그룹이거나 named group ACL에 있으면 그 중 적용(mask로 제한) → ④ 아무에도 안 맞으면 other 적용. "ACL을 줬는데 권한이 안 먹는다" 류 문제는 대개 mask가 깎고 있거나, 소유자라서 owner 권한이 먼저 적용되는 경우다.
한 회사의 감사팀(audit 그룹)이 특정 로그 디렉터리를 "읽기만" 할 수 있어야 했다. 그런데 그 디렉터리는 이미 ops 그룹 소유였고 표준 권한의 group 칸은 ops가 차지하고 있었다. 두 번째 그룹을 표준 권한으로는 넣을 수 없어, setfacl -m g:audit:rX -R /var/log/app으로 audit 그룹에 읽기+디렉터리진입 ACL을 추가했다. 표준 권한 모델로는 불가능했던 "두 그룹에 서로 다른 권한"을 ACL이 해결한 전형적 사례다. (X 대문자는 Day 3에서 본 대로 디렉터리/실행파일에만 x 부여.)
# 직접 쳐보기 — ACL 실험touch acltest.txtsetfacl -m u:nobody:rw acltest.txtls -l acltest.txt # 끝에 + 확인getfacl acltest.txt # ACL 항목과 mask 확인setfacl -b acltest.txt && ls -l acltest.txt # 제거 후 + 사라짐