Study · 운영체제 · 권한 주기 · 계정과 권한

권한은 파일 이름이 아니라 알맹이에 붙어 있다

장면

chmod 600 a.txt 를 하면 무엇이 바뀔까? 그 값은 파일 안에 있을까, 아니면 다른 곳에 있을까?

$ ls -l a.txt
-rw-r--r-- 1 tghan tghan 0 Sep 21 14:02 a.txt
$ chmod 600 a.txt
$ ls -l a.txt
-rw------- 1 tghan tghan 0 Sep 21 14:02 a.txt
# 600 은 주인만 읽고 쓰라는 뜻이다. 바꾸기 전 rw-r--r-- 는 남들도 읽을 수 있던 상태다

아래 재생기의 ▶를 누르면 한 스텝씩 진행된다. 금색 테두리가 지금 이야기하는 곳이고, 캡션이 무슨 일이 일어났는지 말해 준다. 굵게 밑줄 친 말은 누르면 뜻이 나온다. 빨간 딱지는 그때 벌어지는 일의 이름이고, 캡션 바로 위 회색 글자는 지금 스텝이 속한 묶음의 이름이다.

카드 아래 회색 줄은 그 일이 실제로 적혀 있는 소스의 파일 이름 : 줄 번호와 함수 이름이다. 글 안에 (:669)처럼 줄 번호만 적힌 것은 바로 앞에 적은 파일의 그 줄이라는 뜻이다. 캡션 한가운데 박힌 긴 영어 이름과 괄호 속 파일 · 줄 번호도 같다 — 건너뛰고 한글만 읽어도 뜻이 통하게 써 두었다.

장면 · 권한은 파일 이름이 아니라 알맹이에 붙어 있다 0 / 10

▶ 를 누르면 chmod 600 a.txt 한 번이 어느 값을 바꾸는지 따라간다. 커널이 받는 것은 파일 이름인데 바꾸는 자리는 이름 쪽이 아니라는 것이 이 장면의 요지다. 이 장면은 우분투 기본 파일 시스템인 ext4 를 기준으로 한다 — XFS 나 Btrfs 면 VFS 아래 절반이 다르다.

키보드 · ← → 한 스텝 · Space 재생/멈춤 · Home 처음

권한 아홉 자리는 이름이 아니라 알맹이에 붙어 있다. 그래서 같은 알맹이에 이름을 둘 걸어 두면 한쪽만 고쳐도 양쪽이 같이 바뀐다.

어떻게 확인했나

소스 어디를 보고 적었는지와 무엇을 돌려서 쟀는지를 남긴 자리다. 처음 읽을 때는 건너뛰어도 된다.

  • 권한이 담기는 필드는 struct inode(include/linux/fs.h:762)의 umode_t i_mode(:763)다. 실제로 값을 쓰는 줄은 setattr_copy(fs/attr.c:354)의 inode->i_mode = mode; 하나다.
  • 이름은 알맹이를 찾는 데만 쓰인다 — chmod_common(fs/open.c:667)이 첫 줄에서 path->dentry->d_inode 로 inode 를 꺼내고(:669) 그 뒤로 이름을 다시 보지 않는 것을 확인했다.
  • chmod · fchmodat · fchmodat2 가 모두 do_fchmodat(fs/open.c:716)으로 모이고, 거기서 filename_lookup(:729) → chmod_common(:731) 차례인 것을 확인했다.
  • 권한 비트만 갈아 끼우고 파일 종류 비트는 보존한다 — newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO)(fs/open.c:684).
  • 바꿀 자격은 setattr_prepare(fs/attr.c:161)의 inode_owner_or_capable(:205)이 본다 — 읽기 권한과는 다른 자리다.
  • ext4 는 메모리의 inode 만 고치고 표시를 남긴다 — setattr_copy 뒤의 mark_inode_dirty(fs/ext4/inode.c:6231-6232).
  • ls -l 이 보는 값도 같은 칸이다 — generic_fillattr(fs/stat.c:82)의 stat->mode = inode->i_mode(:90).
  • 하드 링크를 걸면 a.txt 와 b.txt 가 둘 다 inode=344734 링크=2 로 나오고, a.txt 에만 chmod 644 를 해도 b.txt 의 권한이 같이 644 가 됐다. 권한이 이름이 아니라 알맹이에 붙어 있다는 뜻이다.
  • 표시만 남기고 나중에 내보낸다. 두 손잡이가 시점을 정한다 — /proc/sys/vm/dirty_writeback_centisecs(잰 기계는 1500, 곧 15초마다 청소 스레드가 깨어난다)와 /proc/sys/vm/dirty_expire_centisecs(3000, 곧 더러워진 지 30초가 지나야 내보낸다). 64MB 를 쓰고 바로 /proc/meminfo 를 보니 Dirty 가 12 kB 에서 65,532 kB 로 늘었고, sync 로 강제로 내보낸 뒤 376 kB 로 떨어졌다. 그래서 chmod 직후에 전원이 끊기면 그 변경은 사라질 수 있다.
‹ 이전 다음 항목 ›