在 fakeroot 中,為什麼 chown 即使成功也回到 EPERM(但沒有成功)?

在 fakeroot 中,為什麼 chown 即使成功也回到 EPERM(但沒有成功)?

我在使用時遇到了奇怪的行為莊(2)在 fakeroot 環境中。下面的最小程式說明了這個問題:

#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;
}

假設是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

我們在這裡能看到什麼?

  1. 通話chown失敗並顯示 EPERM(不允許操作)。
  2. 隨後stat顯示st_uid=1001, st_gid=100哪一個是我真實的(非假的)UID 和 GID(這很奇怪,因為如果我正確理解 fakeroot,它至少應該顯示st_uid=0, st_gid=0)。
  3. ls -l同一文件的後續內容顯示,chown儘管chown報告失敗,但後續內容stat已確認,但仍成功。

這到底是怎麼回事?我是否發現了 fakeroot 中的錯誤,或者這只是對 fakeroot 工作原理的誤解?

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

更新:Jonas Wielicki 正確地指出 strace 在系統呼叫層級運作,因此具有誤導性,因為系統呼叫的結果在返回程式本身之前會被 libfakeroot 破壞。事實證明,在 之後stat(path, &s)struct stat s包含新的 UID 和 GID。但chownEPERM 失敗仍然令人困惑。

答案1

chown事實上,在 下運行時返回零fakeroot。因此,根據errno(3)

只有當呼叫的返回值指示錯誤時,其值才有意義(即,大多數系統呼叫為 -1;大多數函式庫函數為 -1 或 NULL);成功的函數可以更改 errno。

的價值errno並不重要,而且chown事實上並沒有失敗。

正如評論中已經討論的那樣,strace輸出包含 EPERM 和預期的非偽造 uids/gids,如stracefakerootLD_PRELOAD庫下面的追蹤一樣。從程式列印 uid/gid 顯示正確的(偽造的)輸出。

相關內容