On Tue, Oct 13, 2020 at 12:06:20AM +0200, Linus Walleij wrote: > It was brought to my attention that this bug from 2018 was > still unresolved: 32 bit emulators like QEMU were given > 64 bit hashes when running 32 bit emulation on 64 bit systems. > > This adds a flag to the fcntl() F_GETFD and F_SETFD operations > to set the underlying filesystem into 32bit mode even if the > file handle was opened using 64bit mode without the compat > syscalls. > > Programs that need the 32 bit file system behavior need to > issue a fcntl() system call such as in this example: > > #define FD_32BIT_MODE 2 > > int main(int argc, char** argv) { > DIR* dir; > int err; > int fd; > > dir = opendir("/boot"); > fd = dirfd(dir); > err = fcntl(fd, F_SETFD, FD_32BIT_MODE); > if (err) { > printf("fcntl() failed! err=%d\n", err); > return 1; > } > printf("dir=%p\n", dir); > printf("readdir(dir)=%p\n", readdir(dir)); > printf("errno=%d: %s\n", errno, strerror(errno)); > return 0; > } > > This can be pretty hard to test since C libraries and linux > userspace security extensions aggressively filter the parameters > that are passed down and allowed to commit into actual system > calls. > > Cc: Florian Weimer <fw@xxxxxxxxxxxxx> > Cc: Peter Maydell <peter.maydell@xxxxxxxxxx> > Cc: Andy Lutomirski <luto@xxxxxxxxxx> > Suggested-by: Theodore Ts'o <tytso@xxxxxxx> > Link: https://bugs.launchpad.net/qemu/+bug/1805913 > Link: https://lore.kernel.org/lkml/87bm56vqg4.fsf@xxxxxxxxxxxxxxxxx/ > Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=205957 > Signed-off-by: Linus Walleij <linus.walleij@xxxxxxxxxx> > --- > ChangeLog v3->v3 RESEND 1: > - Resending during the v5.10 merge window to get attention. > ChangeLog v2->v3: > - Realized that I also have to clear the flag correspondingly > if someone ask for !FD_32BIT_MODE after setting it the > first time. > ChangeLog v1->v2: > - Use a new flag FD_32BIT_MODE to F_GETFD and F_SETFD > instead of a new fcntl operation, there is already a fcntl > operation to set random flags. > - Sorry for taking forever to respin this patch :( > --- > fs/fcntl.c | 7 +++++++ > include/uapi/asm-generic/fcntl.h | 8 ++++++++ > 2 files changed, 15 insertions(+) > > diff --git a/fs/fcntl.c b/fs/fcntl.c > index 19ac5baad50f..6c32edc4099a 100644 > --- a/fs/fcntl.c > +++ b/fs/fcntl.c > @@ -335,10 +335,17 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg, > break; > case F_GETFD: > err = get_close_on_exec(fd) ? FD_CLOEXEC : 0; > + /* Report 32bit file system mode */ > + if (filp->f_mode & FMODE_32BITHASH) > + err |= FD_32BIT_MODE; > break; > case F_SETFD: > err = 0; > set_close_on_exec(fd, arg & FD_CLOEXEC); > + if (arg & FD_32BIT_MODE) > + filp->f_mode |= FMODE_32BITHASH; > + else > + filp->f_mode &= ~FMODE_32BITHASH; This seems inconsistent? F_SETFD is for setting flags on a file descriptor. Won't setting a flag on filp here instead cause the behaviour to change for all file descriptors across the system that are open on this struct file? Compare set_close_on_exec(). I don't see any discussion on whether this should be an F_SETFL or an F_SETFD, though I see F_SETFD was Ted's suggestion originally. [...] Cheers ---Dave