为什么看到具有400个权限的文件可由root写入但由用户只读?


10

如果我以非特权用户身份创建文件,然后将权限模式更改为400,则该用户将其正确地视为只读:

$ touch somefile
$ chmod 400 somefile
$ [ -w somefile ] && echo rw || echo ro
ro

一切都很好。

但是随后出现了root:

# [ -w somefile ] && echo rw || echo ro
rw

有没有搞错?当然,root可以写入只读文件,但不应养成它的习惯:最佳实践将倾向于指示我应该能够测试写入许可位,如果没有,则设置它这种方式是有原因的。

我想我既想了解为什么会这样,又要在测试未设置写位的文件时如何得到错误的返回码?


顺便说一句,我同时使用RHEL6(4.1.2(1)-release)和RHEL7(4.2.46(2)-release)。
丰富的

16
“最佳实践将倾向于指示我应该能够测试写许可位,如果没有,那么出于某种原因将其设置为这种方式。” -实际上,最佳做法是“不要以root身份运行内容”。如果您以root用户身份运行,则已经决定绕过权限检查。在用户空间中手动重新实现那些权限检查是灾难的根源
凯文

@Kevin如果您可以运行无特权的内容,对您有好处。这是用于操作的/etc/dhcp/dhcpd.conf,它是root拥有的。我正在使用供应商提供的dhcpd。完全是灾难,是吗?该文件已签入RCS,我正在自动使用rcsdiffci并且co因为我们有需要...操作的运算符。权限位检查(-w,由详述test(1))将是失败的第一行,其工作原理是ci -u使文件保持只读状态。我放弃了,直接去rcsdiff -q检查$?。没灾难dhcpd吗?它将归dhcpd
Rich

1
这是一个潜在的灾难,因为您现在有两种不同的权限检查实现:一种在内核中,另一种在用户空间中。更糟糕的是,这些实现甚至都不打算产生相同的结果,因此您不能仅仅对它们进行模糊测试。因此,现在您有两条访问路径必须彼此独立地锁定和保护。
凯文

@Kevin当然,它们不会产生相同的结果,并且不打算(尽管手册页中的细节很少),但是我明确地想检查写权限位;和的手册页bashtest使我相信这就是[ -w目的。
Rich

Answers:


26

test -waka [ -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

注意,子外壳$(...)需要一个0前缀,以便的输出stat被解释为八进制(( ... ))


感谢您的简洁。善用(( ... & ... ))。纠正了一种错字:-)
丰富的

设为3 ...不需要if,八进制权限输出%a不是%d,并且(( ... ))需要前缀0以将输出解释stat为八进制。
Rich

@Patrick我man stat说“%d个设备编号以十进制表示”,但是我们想要的是“访问权限”,不是吗?您关于需要0前缀的观点是做得很好的,但是我想我们只需要在其中加入:)。
sourcejedi

2
stat -c 0%a...
sourcejedi

@sourcejedi ack,您是对的。由于某种原因,我认为%d是十进制的访问权限。恢复了编辑。谢谢:-)
帕特里克

30

我认为您已经误解了-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并不能阻止其可写...


不,“误解”将读取错误的手册页,原因是-wtest(1)是明确的:“文件已存在并且已授予写许可权”,而不是“ 当前用户可能会写文件 ”。与覆盖权限无关,也与ACL无关。bash(1)乱七八糟:“如果文件存在并且可写,则为真。” ksh(1)对恶作剧有一个微妙的提示:“ -w file //是,如果文件存在并且可以被当前进程写入,则为true 。” zsh(1)对应于test(1),用zshmisc(1)表示ksh(1),并zshexpn(1)详细说明了一些有趣的基于权限的切换。csh(1)很简单:“写访问权限”。

顺便说一句:我接受了帕特里克(Patrick)的回答:1.因为您没有充分回答引导问题:测试未设置写位的文件时,如何得到错误的返回码?2.由于难以理解的导入,我误解了手册页。
Rich

3
@Rich我读这篇文章的方式,我想您的评论也有点陈词滥调。我并不是说您写的任何东西都是错误的,只是如果以更礼貌的方式表达,它可能会变得更好。
大卫Z

3
“我认为你被误解了……”并不刻薄。您的回应不过是100%的陈词滥调。
烧烤

@Rich另外,尽管联机帮助页可能不是很清楚,但斯蒂芬说您可能“误解了-w做什么 ”,而不是联机帮助说的是什么,前者似乎是这种情况,因此是一个问题
Sebi

1

root用户可以随意进行操作,“普通”文件权限没有限制。没有任何eXecute权限,它不会直接执行普通文件,只是为了防止脚步练习。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.