在 fakeroot 中,为什么 chown 即使成功也返回 EPERM(但后来又没有)?

Ste*_*sky 3 linux chown fakeroot

在 fakeroot 环境中使用chown(2)时,我遇到了奇怪的行为。以下最小程序说明了这个问题:

#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>

int main() {
    //choose a reasonably unique filename
    char path[30];
    sprintf(path, "./file-%d", getpid());

    //create file
    close(creat(path, 0644));

    //chown to some random UID/GID
    chown(path, 4444, 4444);

    //stat again (result can be seen in strace below)
    struct stat s;
    stat(path, &s);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

假设是main.c。现在我在 a 中运行以下内容fakeroot bash

$ gcc -o main main.c
$ strace -v ./main
...
creat("./file-10872", 0644)             = 3
close(3)                                = 0
...
lchown("./file-10872", 84, 84)          = -1 EPERM (Operation not permitted)
stat("./file-10872", {st_dev=makedev(8, 3), st_ino=3932971, st_mode=S_IFREG|0644, st_nlink=1, st_uid=1001, st_gid=100, st_blksize=4096, st_blocks=0, st_size=0, st_atime=2015/10/31-20:12:07, st_mtime=2015/10/31-20:12:07, st_ctime=2015/10/31-20:12:07}) = 0
...
$ ls -l file-10872
-rw-r--r-- 1 4444 4444 0 31. Okt 20:12 file-10872
Run Code Online (Sandbox Code Playgroud)

我们在这里能看到什么?

  1. chown与EPERM失败的呼叫(不允许的操作)。
  2. 随后的stat显示st_uid=1001, st_gid=100是我的真实(非伪造)UID 和 GID(这很奇怪,因为如果我正确理解 fakeroot,它至少应该显示st_uid=0, st_gid=0)。
  3. ls -l同一文件上的后续内容显示chownSUCCEEDED 即使chown报告失败,随后也stat确认了这一点。

这到底是怎么回事?我是否在 fakeroot 中发现了一个错误,或者这只是对 fakeroot 工作原理的误解?

(我fakeroot的版本是 1.20.2,我的系统是 Arch Linux,所有更新。)

更新: Jonas Wielicki 已正确指出 strace 在系统调用级别上工作,因此具有误导性,因为系统调用的结果将在返回到程序本身之前被 libfakeroot 破坏。事实证明,在 之后stat(path, &s)struct stat s包含新的 UID 和 GID。但是chownEPERM 失败仍然令人困惑。

Jon*_*fer 5

chown实际上在 下运行时返回零fakeroot。因此,根据errno(3)

它的值只有在调用的返回值指示错误时才有意义(即,大多数系统调用为 -1;大多数库函数为 -1 或 NULL);允许成功的函数更改 errno。

in 的值errno并不重要chown,实际上并没有失败。

正如评论中已经讨论过的,strace输出包含 EPERM 和非伪造的 uids/gids,如预期的那样,作为stracefakerootLD_PRELOAD库下面的跟踪。从程序打印 uid/gid 会显示正确的(伪造的)输出。