为什么rename()系统调用禁止移动我无法写入其他目录的目录?

时间:2010-03-31 14:56:18

标签: unix filesystems system-calls

我试图理解为什么这个设计决定是用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创建新链接以及更改权限来非原子地实现相同的效果。 (留给读者练习)

。并且..已经特殊套装,所以我并不特别认为,直观的是,如果我不能写一个目录,我就不能“改变......”这就是消息来源所暗示的。除了它是代码作者感知到的正确行为之外,还有什么理由吗?如果我们让人们在他们可以写的目录之间以原子方式移动目录(他们无法写入)会有什么不好的事情吗?

3 个答案:

答案 0 :(得分:2)

我认为Andrew McGregor很可能是对的。不一定UFS 以这种方式工作,但实现者(Kirk McKusick)只是扩展了文件系统权限的逻辑以涵盖这种情况。因此,如果您对目标目录没有写权限,则无法更改其“..”条目。

但是在看你的例子时,脑海中浮现出另一种可能性。可能是关注不是像您所示,单个用户拥有所有相关目录的情况,而是一个目录由不同用户拥有的情况。换句话说,此检查阻止我在您具有写入权限的父目录之间移动您拥有的目录。当然,假设你没有在你的目录中给我写入权限。

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

一个明显的反驳论点是,如果我们想要担心这种情况,那么我们也希望阻止人们在他们拥有写权限的目录之间移动他们不拥有的文件......

答案 1 :(得分:0)

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

换句话说,为了使目录在移动后格式良好,您必须更改其中的..链接,您无权这样做。所以这只是权限方案的一个逻辑部分,虽然不是非常明显的一部分。

答案 2 :(得分:0)

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

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

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