readdir() returns NULL (errno=EOVERFLOW) for 32-bit user-static qemu on 64-bit host
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
QEMU |
Expired
|
Undecided
|
Unassigned |
Bug Description
This can be simply reproduced by compiling and running the attached C code (readdir-bug.c) under 32-bit user-static qemu, such as qemu-arm-static:
# Setup docker for user-static binfmt
docker run --rm --privileged multiarch/
# Compile the code and run (readdir for / is fine, so create a new directory /test).
docker run -v /path/to/
dir=0xff5b4150
readdir(dir)=(nil)
errno=75: Value too large for defined data type
Do remember to replace the /path/to/
The root cause is in glibc: https:/
By C standard, the return type of readdir() is DIR*, in which the inode number and offset are 32-bit integers, therefore, glibc calls getdents64() and check if the inode number and offset fits the 32-bit range, and reports EOVERFLOW if not.
The problem here is for 32-bit user-static qemu running on 64-bit host, getdents64 simply passing through the inode number and offset from underlying getdents64 syscall (from 64-bit kernel), which is very likely to not fit into 32-bit range. On real hardware, the 32-bit kernel creates 32-bit inode numbers, therefore works properly.
The glibc code makes sense to do the check to be conformant with C standard, therefore ideally it should be a fix on qemu side. I admit this is difficult because qemu has to maintain a mapping between underlying 64-bit inode numbers and 32-bit inode numbers, which would severely hurt the performance. I don't expect this could be fix anytime soon (or even there would be a fix), but it would be worthwhile to surface this issue.
tags: |
added: linux-user removed: linux user-static |
tags: | added: syscall-abi |
Changed in qemu: | |
status: | New → Confirmed |
More notes: this bug hits glibc-2.28 and later. It works on glibc-2.27. Therefore to reproduce it it needs ubuntu 18.10 or later. Seems like it works for 18.04.
This bug affects all Java programs that (implicitly) uses File.list() or File.listFiles(). Also it makes dash not expanding wildcard /some/directory/* . However, bash works because it uses glob() instead of readdir().