For OFD ("file private") locks, the Linux kernel explicitly disables 32bit offset support, in do_flock(): #if BITS_PER_LONG != 32 /* 32-bit arches must use fcntl64() */ case F_OFD_GETLK: #endif ... #if BITS_PER_LONG != 32 /* 32-bit arches must use fcntl64() */ case F_OFD_SETLK: case F_OFD_SETLKW: #endif and the fcntl64 syscall passes the argument as struct flock64 to fcntl_getlk64 / fcntl_setlk64. When a program is compiled as 32bit without using the _FILE_OFFSET_BITS=64 or _LARGEFILE64_SOURCE interfaces, struct flock members are treated as 32bit, but the flock64 syscall is used, causing garbage to be passed in the upper 32bits to fcntl_getlk64 / fcntl_setlk64. SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd, unsigned long, arg) { ... case F_OFD_GETLK: err = fcntl_getlk64(f.file, cmd, (struct flock64 __user *) arg); break; ... case F_OFD_SETLK: case F_OFD_SETLKW: err = fcntl_setlk64(fd, f.file, cmd, (struct flock64 __user *) arg); break; The glibc OFD example also suffers from this, if you compile manual/examples/ofdlocks.c as -m32, it hangs. Using _FILE_OFFSET_BITS=64 or struct flock64 directly "fixes" the problem. I'm not sure how to best solve this without breaking compatibility, maybe an error should be returned by fcntl(), as OFD locks are not supported with 32bit struct flock members? The kernel already seems to return EINVAL for "my" garbage, but probing using systemtap confirms that the garbage is being passed all the way to the kernel - maybe glibc could return EINVAL right away? Alternatively, is there any way to make such 32bit programs use 64bit offsets (struct flock64) by default, silently? The BITS_PER_LONG #if was added with the original "file private locks" commit, 5d50ffd7c31dab47c6b828841ca1ec70a1b40169, mentioning: Also, note that with this implementation the new cmd values are only available via fcntl64() on 32-bit arches. There's little need to add support for legacy apps on a new interface like this. See also Linux Test Project thread: http://lists.linux.it/pipermail/ltp/2016-June/001986.html Tested on (updated) Fedora 23, glibc-2.22-17.fc23 gcc-5.3.1-6.fc23 Thanks.
Hi, Note that we've hit this bug with MIT Kerberos project, see: http://krbdev.mit.edu/rt/Ticket/Display.html?id=8474 I was wondering if this could be solved by libc allocating flock64 on stack and copy the members before calling the syscall (and back after it returns). Regards, Isaac B.
If userland is passing a 32-bit struct flock to fcntl64, then that's pretty broken. The whole point of that syscall was so that we could pass the kernel a struct flock64. IIRC, the idea at the time we merged this was to just make it so that 32-bit programs built without large file offset support couldn't use F_OFD_* constants. That may still be the right thing to do, but Isacc's idea might be better. There's no reason we couldn't support OFD locks with 32-bit offsets if such a thing were desirable.
Unfortunately fcntl is different than other interfaces which have different symbols for non-LFS and LFS (pread for interface), so glibc can not really tell whether the arguments used was the flock or flock64. An option would be: 1. provide a LFS fcntl64 with the usual magic to select it for FILE_OFFSET_BITS=64. 2. Set the fcntl to use a stack allocated struct flock64 for F_OFD_{GETLK,SETLK,SETLKW} and copy the results for the user provided struct. 3. Keep a compat symbol with old broken semantic for architectures that do not define __OFF_T_MATCHES_OFF64_T.
Care to propose a patch? I'm not as familiar with the glibc internals so I'd appreciate some guidance here. FWIW, I don't see how we can fix this at runtime. I was only proposing a build-time fix. i.e.: ensure that non-LFS programs that try to use OFD locks will fail to build. If you see some way to reliably cope with this for programs already built, then maybe that would be better. At the time this was implemented though, the idea was to forbid its usage on non-LFS platforms. We could revisit that decision, but I don't really see the point in supporting what amounts to a legacy flock struct with this.
(In reply to jlayton@poochiereds.net from comment #4) > Care to propose a patch? I'm not as familiar with the glibc internals so I'd > appreciate some guidance here. I am checking on it. > > FWIW, I don't see how we can fix this at runtime. I was only proposing a > build-time fix. i.e.: ensure that non-LFS programs that try to use OFD locks > will fail to build. If you see some way to reliably cope with this for > programs already built, then maybe that would be better. An option for former would be just to avoid define OFD locks commands for non-LFS configurations, but I think we can make it work at runtime. > > At the time this was implemented though, the idea was to forbid its usage on > non-LFS platforms. We could revisit that decision, but I don't really see > the point in supporting what amounts to a legacy flock struct with this. The idea is GLIBC abi might not be tied to kernel in a sense it might define strucs with different layout than what kernel expect. We try to avoid it, since it requires a lot of boilerplate code to transform from and to the syscall itself. But to correctly fix this issue I can't really think a different way than provided both LFS and non-LFS symbol (the default and *64 variant). And by using 2 different symbols it is safe the variadic argument to non-LFS flock or just return EINVAL (I do not have a strong preference here). However we still need to provide a compat symbol with current semantic.
I sent a fix for upstream review [1], if you could take a look to check if this fixes the issues it would helpful. [1] https://sourceware.org/ml/libc-alpha/2018-04/msg00124.html
Looks good to me, but I'm not as well-versed in glibc code. I'll trust that you tested that it does the right thing on the relevant arches. Many thanks for doing this. In hindsight, I wish I had just wired up the kernel to accept legacy flock structs with OFD locks as well. That would likely have saved some of this trouble. It's a little late to do that now, however...
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GNU C Library master sources". The branch, master-bz20251 has been created at 06ab719d30b01da401150068054d3b8ea93dd12f (commit) - Log ----------------------------------------------------------------- https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=06ab719d30b01da401150068054d3b8ea93dd12f commit 06ab719d30b01da401150068054d3b8ea93dd12f Author: Adhemerval Zanella <adhemerval.zanella@linaro.org> Date: Wed Apr 4 11:24:15 2018 -0300 Fix Linux fcntl OFD locks for non-LFS architectures (BZ#20251) This patch fixes the OFD ("file private") locks for architectures that support non-LFS flock definition (__USE_FILE_OFFSET64 not defined). The issue in this case is both F_OFD_{GETLK,SETLK,SETLKW} and F_{SET,GET}L{W}K64 expects a flock64 argument and when using old F_OFD_* flags with a non LFS flock argument the kernel might interpret the underlying data wrongly. Kernel idea originally was to avoid using such flags in non-LFS syscall, but since GLIBC uses fcntl with LFS semantic as default it is possible to provide the functionality and avoid the bogus struct kernel passing by adjusting the struct manually for the required flags. The idea follows other LFS interfaces that provide two symbols: 1. A new LFS fcntl64 is added on default ABI with the usual macros to select it for FILE_OFFSET_BITS=64. 2. The Linux non-LFS fcntl use a stack allocated struct flock64 for F_OFD_{GETLK,SETLK,SETLKW} copy the results on the user provided struct. 3. Keep a compat symbol with old broken semantic for architectures that do not define __OFF_T_MATCHES_OFF64_T. So for architectures which defines __USE_FILE_OFFSET64, fcntl64 will aliased to fcntl and no adjustment would be required. So to actually use F_OFD_* with LFS support the source must be built with LFS support (_FILE_OFFSET_BITS=64). Also F_OFD_SETLKW command is handled a cancellation point, as for F_SETLKW{64}. Checked on x86_64-linux-gnu and i686-linux-gnu. [BZ #20251] * NEWS: Mention fcntl64 addition. * csu/check_fds.c: Replace __fcntl_nocancel by __fcntl64_nocancel. * login/utmp_file.c: Likewise. * sysdeps/posix/fdopendir.c: Likewise. * sysdeps/posix/opendir.c: Likewise. * sysdeps/unix/pt-fcntl.c: Likewise. * include/fcntl.h (__libc_fcntl64, __fcntl64, __fcntl64_nocancel_adjusted): New prototype. (__fcntl_nocancel_adjusted): Remove prototype. * io/Makefile (routines): Add fcntl64. (CFLAGS-fcntl64.c): New rule. * io/Versions [GLIBC_2.28] (fcntl64): New symbol. [GLIBC_PRIVATE] (__libc_fcntl): Rename to __libc_fcntl64. * io/fcntl.h (fcntl64): Add prototype and redirect if __USE_FILE_OFFSET64 is defined. * io/fcntl64.c: New file. * manual/llio.text: Add a note for which commands fcntl acts a cancellation point. * nptl/Makefile (CFLAGS-fcntl64.c): New rule. * sysdeps/mach/hurd/fcntl.c: Alias fcntl to fcntl64 symbols. * sysdeps/mach/hurd/i386/libc.abilist [GLIBC_2.28] (fcntl, fcntl64): New symbols. * sysdeps/unix/sysv/linux/fcntl.c (__libc_fcntl): Fix F_GETLK64, F_OFD_GETLK, F_SETLK64, F_SETLKW64, F_OFD_SETLK, and F_OFD_SETLKW for non-LFS case. * sysdeps/unix/sysv/linux/fcntl64.c: New file. * sysdeps/unix/sysv/linux/fcntl_nocancel.c (__fcntl_nocancel): Rename to __fcntl64_nocancel. (__fcntl_nocancel_adjusted): Rename to __fcntl64_nocancel_adjusted. * sysdeps/unix/sysv/linux/not-cancel.h (__fcntl_nocancel): Rename to __fcntl64_nocancel. * sysdeps/unix/sysv/linux/tst-ofdlocks.c: New file. * sysdeps/unix/sysv/linux/tst-ofdlocks-compat.c: Likewise. * sysdeps/unix/sysv/linux/Makefile (tests): Add tst-ofdlocks. (tests-internal): Add tst-ofdlocks-compat. * sysdeps/unix/sysv/linux/aarch64/libc.abilist [GLIBC_2.28] (fcntl64): New symbol. * sysdeps/unix/sysv/linux/alpha/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/ia64/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist: Likewise. * sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/x86_64/64/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/arm/libc.abilist [GLIBC_2.28] (fcntl, fcntl64): Likewise. * sysdeps/unix/sysv/linux/hppa/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/i386/libc.abilis: Likewise. * sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/microblaze/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/nios2/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/sh/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist: Likewise. -----------------------------------------------------------------------
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GNU C Library master sources". The branch, master has been updated via 06ab719d30b01da401150068054d3b8ea93dd12f (commit) from 124e025864bb39732c71fc60c1443d5680881a0a (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=06ab719d30b01da401150068054d3b8ea93dd12f commit 06ab719d30b01da401150068054d3b8ea93dd12f Author: Adhemerval Zanella <adhemerval.zanella@linaro.org> Date: Wed Apr 4 11:24:15 2018 -0300 Fix Linux fcntl OFD locks for non-LFS architectures (BZ#20251) This patch fixes the OFD ("file private") locks for architectures that support non-LFS flock definition (__USE_FILE_OFFSET64 not defined). The issue in this case is both F_OFD_{GETLK,SETLK,SETLKW} and F_{SET,GET}L{W}K64 expects a flock64 argument and when using old F_OFD_* flags with a non LFS flock argument the kernel might interpret the underlying data wrongly. Kernel idea originally was to avoid using such flags in non-LFS syscall, but since GLIBC uses fcntl with LFS semantic as default it is possible to provide the functionality and avoid the bogus struct kernel passing by adjusting the struct manually for the required flags. The idea follows other LFS interfaces that provide two symbols: 1. A new LFS fcntl64 is added on default ABI with the usual macros to select it for FILE_OFFSET_BITS=64. 2. The Linux non-LFS fcntl use a stack allocated struct flock64 for F_OFD_{GETLK,SETLK,SETLKW} copy the results on the user provided struct. 3. Keep a compat symbol with old broken semantic for architectures that do not define __OFF_T_MATCHES_OFF64_T. So for architectures which defines __USE_FILE_OFFSET64, fcntl64 will aliased to fcntl and no adjustment would be required. So to actually use F_OFD_* with LFS support the source must be built with LFS support (_FILE_OFFSET_BITS=64). Also F_OFD_SETLKW command is handled a cancellation point, as for F_SETLKW{64}. Checked on x86_64-linux-gnu and i686-linux-gnu. [BZ #20251] * NEWS: Mention fcntl64 addition. * csu/check_fds.c: Replace __fcntl_nocancel by __fcntl64_nocancel. * login/utmp_file.c: Likewise. * sysdeps/posix/fdopendir.c: Likewise. * sysdeps/posix/opendir.c: Likewise. * sysdeps/unix/pt-fcntl.c: Likewise. * include/fcntl.h (__libc_fcntl64, __fcntl64, __fcntl64_nocancel_adjusted): New prototype. (__fcntl_nocancel_adjusted): Remove prototype. * io/Makefile (routines): Add fcntl64. (CFLAGS-fcntl64.c): New rule. * io/Versions [GLIBC_2.28] (fcntl64): New symbol. [GLIBC_PRIVATE] (__libc_fcntl): Rename to __libc_fcntl64. * io/fcntl.h (fcntl64): Add prototype and redirect if __USE_FILE_OFFSET64 is defined. * io/fcntl64.c: New file. * manual/llio.text: Add a note for which commands fcntl acts a cancellation point. * nptl/Makefile (CFLAGS-fcntl64.c): New rule. * sysdeps/mach/hurd/fcntl.c: Alias fcntl to fcntl64 symbols. * sysdeps/mach/hurd/i386/libc.abilist [GLIBC_2.28] (fcntl, fcntl64): New symbols. * sysdeps/unix/sysv/linux/fcntl.c (__libc_fcntl): Fix F_GETLK64, F_OFD_GETLK, F_SETLK64, F_SETLKW64, F_OFD_SETLK, and F_OFD_SETLKW for non-LFS case. * sysdeps/unix/sysv/linux/fcntl64.c: New file. * sysdeps/unix/sysv/linux/fcntl_nocancel.c (__fcntl_nocancel): Rename to __fcntl64_nocancel. (__fcntl_nocancel_adjusted): Rename to __fcntl64_nocancel_adjusted. * sysdeps/unix/sysv/linux/not-cancel.h (__fcntl_nocancel): Rename to __fcntl64_nocancel. * sysdeps/unix/sysv/linux/tst-ofdlocks.c: New file. * sysdeps/unix/sysv/linux/tst-ofdlocks-compat.c: Likewise. * sysdeps/unix/sysv/linux/Makefile (tests): Add tst-ofdlocks. (tests-internal): Add tst-ofdlocks-compat. * sysdeps/unix/sysv/linux/aarch64/libc.abilist [GLIBC_2.28] (fcntl64): New symbol. * sysdeps/unix/sysv/linux/alpha/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/ia64/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist: Likewise. * sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/x86_64/64/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/arm/libc.abilist [GLIBC_2.28] (fcntl, fcntl64): Likewise. * sysdeps/unix/sysv/linux/hppa/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/i386/libc.abilis: Likewise. * sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/microblaze/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/nios2/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/sh/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist: Likewise. ----------------------------------------------------------------------- Summary of changes: ChangeLog | 68 +++++++++++++++ NEWS | 6 ++ csu/check_fds.c | 2 +- include/fcntl.h | 7 ++- io/Makefile | 3 +- io/Versions | 5 +- io/fcntl.h | 11 +++ io/fcntl64.c | 38 ++++++++ login/utmp_file.c | 4 +- manual/llio.texi | 13 ++-- nptl/Makefile | 1 + sysdeps/generic/not-cancel.h | 4 +- sysdeps/mach/hurd/bits/errno.h | 9 ++ sysdeps/mach/hurd/fcntl.c | 5 + sysdeps/mach/hurd/i386/libc.abilist | 2 + sysdeps/posix/fdopendir.c | 2 +- sysdeps/posix/opendir.c | 2 +- sysdeps/unix/pt-fcntl.c | 2 +- sysdeps/unix/sysv/linux/Makefile | 4 +- sysdeps/unix/sysv/linux/aarch64/libc.abilist | 1 + sysdeps/unix/sysv/linux/alpha/libc.abilist | 1 + sysdeps/unix/sysv/linux/arm/libc.abilist | 2 + sysdeps/unix/sysv/linux/fcntl.c | 90 +++++++++++++++++--- sysdeps/unix/sysv/linux/fcntl64.c | 63 ++++++++++++++ sysdeps/unix/sysv/linux/fcntl_nocancel.c | 8 +- sysdeps/unix/sysv/linux/hppa/libc.abilist | 2 + sysdeps/unix/sysv/linux/i386/libc.abilist | 2 + sysdeps/unix/sysv/linux/ia64/libc.abilist | 1 + sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist | 2 + sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist | 2 + sysdeps/unix/sysv/linux/microblaze/libc.abilist | 2 + .../unix/sysv/linux/mips/mips32/fpu/libc.abilist | 2 + .../unix/sysv/linux/mips/mips32/nofpu/libc.abilist | 2 + .../unix/sysv/linux/mips/mips64/n32/libc.abilist | 2 + .../unix/sysv/linux/mips/mips64/n64/libc.abilist | 1 + sysdeps/unix/sysv/linux/nios2/libc.abilist | 2 + sysdeps/unix/sysv/linux/not-cancel.h | 4 +- .../sysv/linux/powerpc/powerpc32/fpu/libc.abilist | 2 + .../linux/powerpc/powerpc32/nofpu/libc.abilist | 2 + .../sysv/linux/powerpc/powerpc64/libc-le.abilist | 1 + .../unix/sysv/linux/powerpc/powerpc64/libc.abilist | 1 + sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist | 1 + sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist | 2 + sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist | 1 + sysdeps/unix/sysv/linux/sh/libc.abilist | 2 + sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist | 2 + sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist | 1 + sysdeps/unix/sysv/linux/tst-ofdlocks-compat.c | 84 ++++++++++++++++++ sysdeps/unix/sysv/linux/tst-ofdlocks.c | 76 +++++++++++++++++ sysdeps/unix/sysv/linux/x86_64/64/libc.abilist | 1 + sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist | 1 + 51 files changed, 519 insertions(+), 35 deletions(-) create mode 100644 io/fcntl64.c create mode 100644 sysdeps/unix/sysv/linux/fcntl64.c create mode 100644 sysdeps/unix/sysv/linux/tst-ofdlocks-compat.c create mode 100644 sysdeps/unix/sysv/linux/tst-ofdlocks.c
Fixed by 06ab719d30b01da401150068054d3b8ea93dd12f.