1

我试图理解为什么这个设计决定是使用 4.2BSD 中的 rename() 系统调用做出的。我在这里没有要解决的问题,只需了解行为本身的基本原理即可。

4.2BSD 引入了 rename() 系统调用,目的是允许对文件进行原子重命名/移动。从 4.3BSD-Reno/src/sys/ufs/ufs_vnops.c:

 /*
  * If ".." must be changed (ie the directory gets a new
  * parent) then the source directory must not be in the
  * directory heirarchy above the target, as this would
  * orphan everything below the source directory. Also
  * the user must have write permission in the source so
  * as to be able to change "..". We must repeat the call 
  * to namei, as the parent directory is unlocked by the
  * call to checkpath().
  */

 if (oldparent != dp->i_number)
  newparent = dp->i_number;
 if (doingdirectory && newparent) {
  VOP_LOCK(fndp->ni_vp);
  error = ufs_access(fndp->ni_vp, VWRITE, tndp->ni_cred);
  VOP_UNLOCK(fndp->ni_vp);

很明显,这个检查是故意添加的。我的问题是——为什么?这种行为应该是直观的吗?

这样做的效果是不能将一个不能写入的目录(位于一个可以写入的目录中)移动到另一个可以原子写入的目录。但是,您可以创建一个新目录,移动链接(假设一个人对该目录具有读取权限),然后删除一个人对该目录的写入位。你不能原子地这样做。

% cd /tmp
% mkdir stackoverflow-question
% cd stackoverflow-question
% mkdir directory-1
% mkdir directory-2
% mkdir directory-1/directory-i-cant-write
% echo "foo" > directory-1/directory-i-cant-write/contents
% chmod 000 directory-1/directory-i-cant-write/contents
% chmod 000 directory-1/directory-i-cant-write
% mv directory-1/directory-i-cant-write directory-2
mv: rename directory-1/directory-i-cant-write to directory-2/directory-i-cant-write: Permission denied

我们现在有一个我无法写入的目录,其中包含我无法读取的内容,我无法以原子方式移动。但是,我可以通过更改权限、创建新目录、使用 ln 创建新链接以及更改权限来非原子地实现相同的效果。(留给读者作为练习)

. 和 .. 已经是特殊情况了,所以我并不特别相信,如果我不能写一个目录,我就不能“改变 ..”,这就是消息来源所暗示的。除了代码作者认为正确的行为之外,还有什么理由吗?如果我们让人们在他们可以写的目录之间原子地移动目录(他们不能写),会发生什么不好的事情吗?

4

3 回答 3

2

我认为安德鲁·麦格雷戈很有可能是对的。不一定 UFS必须以这种方式工作,而是实现者 (Kirk McKusick) 只是简单地扩展了文件系统权限的逻辑来涵盖这种情况。因此,如果您对目标目录没有写权限,则不应更改其“..”条目。

但是在查看您的示例时,我想到了另一种可能性。可能不像您所展示的那样,关注的不是单个用户拥有所有相关目录的情况,而是目录由不同用户拥有的情况。换句话说,这个检查阻止我在我有写权限的父目录之间移动你拥有的目录。当然,假设您没有在您的目录中授予我写权限。

诚然,在正常使用中可能出现这种情况的情况很少见。但是内核必须担心所有奇怪的用例以及常见的用例。

An obvious counter argument is that if we wanted to worry about this scenario, then we would also want to stop people from moving files they don't own between directories they have write permissions on...

于 2010-04-06T02:17:43.617 回答
0

Also the user must have write permission in the source so as to be able to change "..".

换句话说,为了在移动后目录格式正确,您必须更改其中的 .. 链接,而您无权执行此操作。所以这只是权限方案的一个逻辑部分,尽管不是一个非常明显的部分。

于 2010-03-31T15:24:48.283 回答
0

存在许多专门的程序,它们允许非特权用户在某些狭义的条件下执行某些通常特权的操作。此类程序通常使用 setuid 标志工作。在程序中,它检查以确保满足特殊条件,如果满足,则执行特权操作。

有时需要按名称引用文件,例如,如果要执行将文件名作为参数的程序。如果必须首先执行检查,如果非特权用户可以在检查时间和使用时间之间重命名路径名的任何部分,这可能会导致危险的竞争条件。这有时可以通过要求包含每个指定路径组件的目录对非特权用户没有写入权限来解决,确保在此期间非特权用户不能重命名(或取消链接和重新创建)任何路径组件来引用与被检查了。如果非特权用户即使没有对该目录的写权限也可以更改“..”所指的内容,这将造成安全漏洞。

此外,更新目录中的“..”需要写入该目录的数据块,并且还会更新目录的最后修改时间,至少在传统的 Unix 和 BSD 文件系统上(我知道 Apple 不是这种情况) HFS+,其中“..”是合成的)。似乎很直观,关闭其他用户的写权限将禁止他们进行任何会写入目录或更改其最后修改时间的操作。

于 2010-03-31T23:22:20.837 回答