Hello. Sorry for the late reply.
Paul Eggert wrote in <4d962618-fee0-4cbb-b769-6ca61a96a...@cs.ucla.edu>: |On 2025-09-13 10:36, Steffen Nurpmeso wrote: |> Paul Eggert wrote in |>|that cp fails because fchmodat2 fails. So it sounds like we have been |>|barking up the wrong tree by worrying about the chown-related syscalls, |>|and that we should instead worry about chmod-related syscalls. |> |> Seems like that. | |On further looking at your trace in |<https://debbugs.gnu.org/cgi/bugreport.cgi?bug=79433#23> it seems that I |was mistaken. Even though the fchmodat2 syscall fails with ENOSYS, it Please stop right here. I followed your advice and rebuilt coreutils 9.7. I cannot reproduce the error, strace(1)d flows change due to fchmodat2(). I give the logs below. $ grep chown /usr/include/asm/unistd_64.h #define __NR_chown 92 #define __NR_fchown 93 #define __NR_lchown 94 #define __NR_fchownat 260 $ grep fchmod /usr/include/asm/unistd_64.h #define __NR_fchmod 91 #define __NR_fchmodat 268 $ ll /bin/cp -rwxr-xr-x 1 root root 126240 Apr 29 11:59 /bin/cp* $ ll src/cp -rwxr-x--- 1 steffen steffen 480888 Sep 16 01:18 src/cp* On my box, since April, quite some things changed (CRUX is rolling release, except for certain core ports which only get bugfixes). I cannot reconstruct exact software environment from April. $ strings /bin/cp | grep -i gcc: GCC: (CRUX-x86_64-multilib) 14.2.0 $ strings src/cp | grep -i gcc: GCC: (CRUX-x86_64-multilib) 14.3.0 That. glibc 2.40 is here since last Octobre (20th) i would think, it was updated three or four times (CVEs .. at least). Kernel is 6.1.* ever since it was declared LTS. |appears that the glibc fchmodat library function then calls openat with |O_NOFOLLOW|O_PATH and then calls fstatat+AT_EMPTY_PATH, determines that |"c" is a symlink, and then returns -1 with errno=ENOTSUP. | |But then I'm lost. If b is a symlink, I don't see why 'cp -a b c' would |ever call fchmodat. The coreutils 9.7 source code says that fopr |symlinks copy_internal should call symlinkat via force_symlinkat |(copy.c:3117), then fchownat via lchownat (copy.c:3152), then utimensat |(copy.c:3227), but it should never call fchmodat. | |Could you investigate why coreutils 9.7 cp is not behaving the way the |source code says it should? You can use a debugger, or insert print |statements, to figure out why in this particular case it is going awry. | |Lets get the chmod issue figured out first. We can worry about the chown |issue later; one thing at a time. So i instrumented the code paths first, which was stupid, since it just works if compiled now. I do have the /bin/cp from April. Here is the diff. --- _bin_cp.log 2025-09-16 01:22:35.366585945 +0200 +++ _src_cp.log 2025-09-16 01:23:14.693251872 +0200 @@ -1,40 +1,40 @@ -execve("/bin/cp", ["/bin/cp", "-a", "xb", "xc"], 0x7ffee5e2ffb8 /* 94 vars */) = 0 -brk(NULL) = 0x55d3bf6d7000 -mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fbbd5a6c000 +execve("src/cp", ["src/cp", "-a", "xb", "xc"], 0x7ffcd92e2298 /* 94 vars */) = 0 +brk(NULL) = 0x55b6475d1000 +mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f3595bd8000 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) ... openat(AT_FDCWD, "/usr/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) @@ -43,52 +43,106 @@ read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0 ... prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0 -getrandom("\x03\x0b\xe6\x00\xb2\xbe\xbd\x51", 8, GRND_NONBLOCK) = 8 -brk(NULL) = 0x55d3bf6d7000 -brk(0x55d3bf6f8000) = 0x55d3bf6f8000 +getrandom("\x4f\x4b\xf5\x75\x90\xf4\x18\xef", 8, GRND_NONBLOCK) = 8 +brk(NULL) = 0x55b6475d1000 +brk(0x55b6475f2000) = 0x55b6475f2000 openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3 fstat(3, {st_mode=S_IFREG|0644, st_size=3061520, ...}) = 0 -mmap(NULL, 3061520, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fbbd5400000 +mmap(NULL, 3061520, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f3595600000 close(3) = 0 geteuid() = 1000 +write(2, "PRE DO_COPY\n", 12PRE DO_COPY +) = 12 +write(2, "DO_COPY\n", 8DO_COPY +) = 8 openat(AT_FDCWD, "xc", O_RDONLY|O_PATH|O_DIRECTORY) = -1 ENOTDIR (Not a directory) +write(2, "WORK2 xb xc\n", 12WORK2 xb xc +) = 12 +write(2, "COPY_INTERNAL xb -> xc\n", 23COPY_INTERNAL xb -> xc +) = 23 newfstatat(AT_FDCWD, "xb", {st_mode=S_IFLNK|0777, st_size=2, ...}, AT_SYMLINK_NOFOLLOW) = 0 +write(2, " 10\n", 9 10 +) = 9 newfstatat(AT_FDCWD, "xc", {st_mode=S_IFLNK|0777, st_size=2, ...}, AT_SYMLINK_NOFOLLOW) = 0 unlinkat(AT_FDCWD, "xc", 0) = 0 readlink("xb", "xa", 3) = 2 symlinkat("xa", AT_FDCWD, "xc") = 0 ==DIVERT -newfstatat(AT_FDCWD, "xc", {st_mode=S_IFLNK|0777, st_size=2, ...}, AT_SYMLINK_NOFOLLOW) = 0 -lchown("xc", 1000, 1000) = 0 -fchmodat2(AT_FDCWD, "xc", 0777, AT_SYMLINK_NOFOLLOW) = -1 ENOSYS (Function not implemented) -openat(AT_FDCWD, "xc", O_RDONLY|O_NOFOLLOW|O_CLOEXEC|O_PATH) = 3 -newfstatat(3, "", {st_mode=S_IFLNK|0777, st_size=2, ...}, AT_EMPTY_PATH) = 0 -close(3) = 0 Like you say -- sysdeps/unix/sysv/linux/fchmodat.c went over fchmodat_fallback(). How did it get here at all is your question; well, /bin/cp is stripped, CRUX strips stuff. -fcntl(1, F_GETFL) = 0x2 (flags O_RDWR) -write(2, "cp: ", 4cp: ) = 4 -write(2, "failed to preserve ownership for"..., 35failed to preserve ownership for xc) = 35 -write(2, ": Operation not supported", 25: Operation not supported) = 25 -write(2, "\n", 1 -) = 1 +write(2, " 314\n", 10 314 +) = 10 ... +write(2, " 316\n", 10 316 +) = 10 +fchownat(AT_FDCWD, "xc", 1000, 1000, AT_SYMLINK_NOFOLLOW) = 0 +write(2, " 320\n", 10 320 +) = 10 .. +utimensat(AT_FDCWD, "xc", [{tv_sec=1757977042, tv_nsec=253998375} /* 2025-09-16T00:57:22.253998375+0200 */, {tv_sec=1757977033, tv_nsec=957331866} /* 2025-09-16T00:57:13.957331866+0200 */], AT_SYMLINK_NOFOLLOW) = 0 +llistxattr("xb", NULL, 0) = 0 +llistxattr("xb", 0x7ffdb169b050, 0) = 0 +write(2, "do_copy returns 1\n", 18do_copy returns 1 +) = 18 lseek(0, 0, SEEK_CUR) = -1 ESPIPE (Illegal seek) close(0) = 0 close(1) = 0 close(2) = 0 -exit_group(1) = ? -+++ exited with 1 +++ +exit_group(0) = ? ++++ exited with 0 +++ I do have that /bin/cp. Btw i note that if i strip src/cp it is much smaller than /bin/cp, but, different compiler etc. Well, that will be hard, to get more out of that. I do not use debuggers. Well, i guess i could install gdb and set breakpoint around symlinkat(), then step and try to look around. --End of <4d962618-fee0-4cbb-b769-6ca61a96a...@cs.ucla.edu> How likely is a miscompilation of gcc 4.2.0? --steffen | |Der Kragenbaer, The moon bear, |der holt sich munter he cheerfully and one by one |einen nach dem anderen runter wa.ks himself off |(By Robert Gernhardt)