GNU bug report logs - #43591
[PATCH core-updates] gnu: glibc-final: Catch all cases of a glibc user not requesting 64-bit offsets and then using readdir.

Previous Next

Package: guix-patches;

Reported by: Danny Milosavljevic <dannym <at> scratchpost.org>

Date: Thu, 24 Sep 2020 14:13:02 UTC

Severity: normal

Tags: patch

Full log


View this message in rfc822 format

From: Danny Milosavljevic <dannym <at> scratchpost.org>
To: Marius Bakke <marius <at> gnu.org>
Cc: 43591 <at> debbugs.gnu.org
Subject: [bug#43591] [PATCH core-updates] gnu: glibc-final: Catch all cases of a glibc user not requesting 64-bit offsets and then using readdir.
Date: Fri, 25 Sep 2020 17:33:20 +0200
[Message part 1 (text/plain, inline)]
Hi,

I wrote a FUSE filesystem to test what happens with big d_off (I just
hard-or-ed a bitmask) and ran it on a real ARMHF machine, then made the program
from before([1] from before) look into that directory.

Result (on ARMHF, so real 32 bit machine!):

$ gcc --version
gcc (Ubuntu/Linaro 5.4.0-6ubuntu1~16.04.12) 5.4.0 20160609
$ gcc a00.c 
$ ./a00 
1737031971 .
1737032035 ..
1737032035 hello
$ gcc -D_FILE_OFFSET_BITS=64 a00.c 
$ ./a.out 
320255973458211 .
320255973458275 ..
320255973458275 hello

(Note: Guix gcc-toolchain 10 on ARMHF is still building from source--and
will continue to do so for some hours I guess)

I only had to patch fuse 2.9.4 (lib/fuse_lowlevel.c) to do this:

char *fuse_add_dirent(char *buf, const char *name, const struct stat *stbuf,
                      off_t off)
{
        unsigned namelen = strlen(name);
        unsigned entlen = FUSE_NAME_OFFSET + namelen;
        unsigned entsize = fuse_dirent_size(namelen);
        unsigned padlen = entsize - entlen;
        struct fuse_dirent *dirent = (struct fuse_dirent *) buf;

        dirent->ino = stbuf->st_ino;
        dirent->off = off | 0x1234567890123; // !!!!
        dirent->namelen = namelen;
        dirent->type = (stbuf->st_mode & 0170000) >> 12;
        strncpy(dirent->name, name, namelen);
        if (padlen)
                memset(buf + entlen, 0, padlen);

        return buf + entsize;
}

(I DID NOT have to patch the kernel or even have root)

So it can happen that you get 64 bit d_off even on real 32 bit machines!

That's what I thought--but I still wanted to make sure.

And the same on Guix i686 (a00 is [1] from my previous e-mail):

$ ./a00-i686
readdir: Value too large for defined data type
$ ./a00-i686_flag_32 
readdir: Value too large for defined data type
$ ./a00-i686_flag_64
320255973458211
320255973458275
320255973458275

So there you have it, even on i686--without emulating anything--you can get a
64 bit d_off value.
[Message part 2 (application/pgp-signature, inline)]

This bug report was last modified 4 years and 250 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.