3

I've been running into bizarre behavior when using chown(2) within a fakeroot environment. The following minimal program illustrates the issue:

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

Suppose that is main.c. Now I run the following within 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

What can we see here?

  1. The chown call failed with EPERM (Operation Not Permitted).
  2. The subsequent stat shows st_uid=1001, st_gid=100 which is my real (non-fake) UID and GID (which is weird because, if I understand fakeroot correctly, it should at least show st_uid=0, st_gid=0).
  3. The subsequent ls -l on the same file shows that the chown SUCCEEDED even though chown reported failure and the subsequent stat confirmed that.

What the heck is going on here? Have I found a bug in fakeroot, or is this just a misunderstanding of how fakeroot works?

(My fakeroot is version 1.20.2, and my system is Arch Linux with all updates.)

Update: It has been correctly pointed out by Jonas Wielicki that strace works on the syscall level and thus is misleading since the results of the syscalls will be mangled by libfakeroot before being returned to the program itself. It turns out that after stat(path, &s), the struct stat s contains the new UID and GID. But it's still confusing that chown fails with EPERM.

1
  • 2
    That strace shows incorrect values is not that surprising, I would in fact expect it to see what the system actually returns, not what fakeroot layers above that; same for the error values. Printing the uid and gid from the main.c shows the correct (faked, that is = 4444) values. However, adding perror() and printf(… errno) calls to your code shows that the errors propagate outside of the chown(2) call in the C code. Oddly enough, with a small python (3.4) test, I am not getting exceptions and the values returned are as expected. Without fakeroot, the python script throws PermissionError. Oct 31, 2015 at 19:40

1 Answer 1

5

chown in fact returns zero when run under fakeroot. Thus, according to errno(3):

Its value is significant only when the return value of the call indicated an error (i.e., -1 from most system calls; -1 or NULL from most library functions); a function that succeeds is allowed to change errno.

The value in errno is not significant and chown did in fact not fail.

As already discussed in the comments, the strace output contains EPERM and non-faked uids/gids as expected, as strace traces below the fakeroot LD_PRELOAD library. Printing the uid/gid from the program shows the correct (faked) output.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .