25.04.2024 05:31, Al Viro пишет:
Incidentally, suppose you have the same process run with stdin opened (r/o) by root. F_SETFD it to O_CLOEXEC, then use your open with dirfd being 0, pathname - "" and flags - O_RDWR.
I actually checked this with the test-case. It seems to return ENOENT: Breakpoint 1, openat2 (dirfd=0, pathname=0x7fffffffdbee "", how=0x7fffffffd5e0, size=24) at tst.c:13 13 return syscall(SYS_openat2, dirfd, pathname, how, size); (gdb) fin Run till exit from #0 openat2 (dirfd=0, pathname=0x7fffffffdbee "", how=0x7fffffffd5e0, size=24) at tst.c:13 0x000000000040167b in main (argc=3, argv=0x7fffffffd7b8) at tst.c:140 140 fd = openat2(0, efile, &how1, sizeof(how1)); Value returned is $1 = -1 (gdb) list 135 err = fcntl(0, F_SETFD, O_CLOEXEC); 136 if (err) { 137 perror("fcntl(F_SETFD)"); 138 return EXIT_FAILURE; 139 } 140 fd = openat2(0, efile, &how1, sizeof(how1)); 141 if (fd == -1) { 142 perror("openat2(1)"); 143 // return EXIT_FAILURE; 144 } else { (gdb) p errno $2 = 2 So it seems the creds can't be stolen from a non-dir fd, but I wonder why ENOENT is returned instead of ENOTDIR. Such ENOENT is not dicumented in a man page of openat2(), so I guess there is some problem here even w/o my patch. :)