F Florian Weimer #
Message details and related content
We have a bit of an interesting problem with respect to the d_off field in struct dirent. When running a 64-bit kernel on certain file systems, notably ext4, this field uses the full 63 bits even for small directories (strace -v output, wrapped here for readability): getdents(3, [ {d_ino=1494304, d_off=3901177228673045825, d_reclen=40, d_name="authorized_keys", d_type=DT_REG}, {d_ino=1494277, d_off=7491915799041650922, d_reclen=24, d_name=".", d_type=DT_DIR}, {d_ino=1314655, d_off=9223372036854775807, d_reclen=24, d_name="..", d_type=DT_DIR} ], 32768) = 88 When running in 32-bit compat mode, this value is somehow truncated to 31 bits, for both the getdents and the getdents64 (!) system call (at least on i386). In an effort to simplify support for future architectures which only have the getdents64 system call, we changed glibc 2.28 to use the getdents64 system call unconditionally, and perform translation if necessary. This translation is noteworthy because it includes overflow checking for the d_ino and d_off members of struct dirent. We did not initially observe a regression because the kernel performs consistent d_off truncation (with the ext4 file system; small directories do not show this issue on XFS), so the overflow check does not fire. However, both qemu-user and the 9p file system can run in such a way that the kernel is entered from a 64-bit process, but the actual usage is from a 32-bit process: <https://sourceware.org/bugzilla/show_bug.cgi?id=23960> I think diagrammatically, this looks like this: guest process (32-bit) | getdents64, 32-bit UAPI qemu-user (64-bit) | getdents, 64-bit UAPI host kernel (64-bit)