dash not expanding glob wildcards in chroot

I have the exact same symptoms on my machine, even though I am working on a different project (based on docker, not on QEMU), so I cannot prove that it is the issue in your case, but it probably is.

I have a build which is sometimes working, and sometimes failing, because the wildcard does not always get expanded (I am doing ls /tmp/linux*deb).

Strace shows that for the failing case, a call to getdents is returning -1 EOVERFLOW (Value too large for defined data type)

Working case:

[pid 29791] open("/tmp", O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC) = 3
[pid 29791] fstat64(3, {st_mode=S_IFDIR|S_ISVTX|0777, st_size=4096, ...}) = 0
[pid 29791] getdents(3, /* 3 entries */, 32768) = 60
[pid 29791] getdents(3, /* 0 entries */, 32768) = 0
[pid 29791] close(3)                    = 0

Failing case:

[pid 25606] open("/tmp", O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC) = 3
[pid 25606] fstat64(3, {st_mode=S_IFDIR|S_ISVTX|0777, st_size=100, ...}) = 0
[pid 25606] getdents(3, /* 1 entries */, 32768) = 16
[pid 25606] getdents(3, 0x585a831c, 32768) = -1 EOVERFLOW (Value too large for defined data type)
[pid 25606] close(3)                    = 0

I found a couple of bug-reports referencing the issue (getdents returns a 64 bits value, but the caller expects a 32 bits value in this case):

  • https://github.com/moby/moby/issues/39732
  • https://bugs.launchpad.net/qemu/+bug/1805913
  • https://bugzilla.kernel.org/show_bug.cgi?id=205957

Cause

As Étienne found out (please, upvote them for the research effort), the root cause seems to be a change in glibc 2.28.

  • getdents64 on 64-bit Linux can return d_off values that don't fit in a 32-bit int. On 32-bit systems it only returns 32-bit values.
  • qemu-user that emulates a 32-bit system on 64-bit Linux just passes the syscall through, so a 32-bit userland process can get overflowing values.
  • glibc 2.28 has a change that makes readdir always use getdents64 and error out if d_off doesn't fit. On real 32-bit systems, this must not be causing problems because glibc went through with it. (Previously it called getdents on 32-bit systems, this returns 32-bit values and the kernel does any truncating.)

Fix (or the lack thereof)

This glibc bug is currently tracking progress on this issue. It'll take its time to be fixed and eventually deployed to your distribution.

Workarounds

  • The simplest workaround I can see is running these builds on a system with a 32-bit Linux kernel.
  • If you can downgrade the glibc version (in the chroot!) to 2.27 that would fix the problem, but that might cause dependency problems and will alter the image you're building.
  • One can also apply one of the many patches in the linked threads, but that will require compiling (and probably detaching from your package manager) either your kernel, glibc or (probably the easiest) QEMU.