如果我以非特权用户身份创建一个文件,并将权限模式更改为400
,则该用户会正确地将其视为只读:
$ touch somefile
$ chmod 400 somefile
$ [ -w somefile ] && echo rw || echo ro
ro
一切都很好。
但随后 root 出现了:
# [ -w somefile ] && echo rw || echo ro
rw
有没有搞错?当然,root 可以写入只读文件,但它不应该养成这种习惯:最佳实践倾向于规定我应该能够测试写入权限位,如果不是,则已设置那样是有原因的。
我想我想同时理解为什么这正在发生,并且如何我可以得到一个错误的测试未设置写入位的文件时返回代码?
答案1
我想你误解-w
了什么。它不会检查文件是否具有“写入权限”,而是检查文件是否可被写入调用用户。
更具体地说,它称为access(2)
或类似。
例如,如果一个脚本有if [ -w /etc/shadow ]
那么如果您运行strace
该脚本,您可能会看到类似于以下的行
faccessat(AT_FDCWD, "/etc/shadow", W_OK)
由于root
可以写入文件,因此返回 0。
例如作为普通用户:
faccessat(AT_FDCWD, "/etc/shadow", W_OK) = -1 EACCES (Permission denied)
作为根用户
faccessat(AT_FDCWD, "/etc/shadow", W_OK) = 0
尽管事实上我的机器/etc/shadow
已获得许可。000
---------- 1 root root 4599 Jan 29 20:08 /etc/shadow
现在你想做的事情得到了有趣的并没有那么简单。
如果您想检查简单的权限,请检查ls
输出,或调用stat
或类似的。但要意识到 ACL 可以覆盖这些权限。仅仅因为文件的权限为 400 并不能阻止它可写......
答案2
test -w
又名[ -w
不检查文件模式。它检查它是否可写。对于root来说,确实如此。
$ help test | grep '\-w'
-w FILE True if the file is writable by you.
我测试的方法是对stat(1)
(“%a
八进制访问权限”)的输出进行按位比较。
(( 0$(stat -c %a somefile) & 0200 )) && echo rw || echo ro
请注意,子 shell$(...)
需要一个0
前缀,以便 的输出stat
被 解释为八进制(( ... ))
。
答案3
root用户可以为所欲为,“普通”文件权限没有限制。它不会在没有任何 eXecute 权限的情况下直接执行普通文件,只是为了防止脚部目标练习。