Description
Documentation
I ran into an issue with running Python 3.13 under QEMU on Ubuntu 22.04.
>>> subprocess.run([sys.executable], check=True)
Traceback (most recent call last):
File "<python-input-10>", line 1, in <module>
subprocess.run([sys.executable], check=True)
~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.13/subprocess.py", line 577, in run
raise CalledProcessError(retcode, process.args,
output=stdout, stderr=stderr)
subprocess.CalledProcessError: Command '['/usr/local/bin/python3']' returned non-zero exit status 127.
>>> subprocess._USE_POSIX_SPAWN = False
>>> subprocess.run([sys.executable], check=True)
Python 3.13.1 (main, Jan 21 2025, 16:37:53) [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
Note that rc 127 is:
#define SPAWN_ERROR 127
I traced this down to 2b93f52 from #113118 which added support for using posix_spawn
if posix_spawn_file_actions_addclosefrom_np
exists.
The problem seems to be that while the libc may support posix_spawn_file_actions_addclosefrom_np
, there needs to be equivalent support within the QEMU user emulator to support any syscalls made.
In this case, glibc uses the close_range
syscall.
186898 Unknown syscall 436
On arm64, syscall 436 is close_range
. (https://gpages.juszkiewicz.com.pl/syscalls-table/syscalls.html)
We'd expect:
27184 close_range(3,4294967295,0) = 0
glibc does try to fall back to closefrom
, however that call can fail if the foreign chroot doesn't have /proc/
mounted, which is a situation often encountered when building foreign chroots without privilege escalation.
279077 openat(AT_FDCWD,"/proc/self/fd/",O_RDONLY|O_DIRECTORY) = -1 errno=2 (No such file or directory)
279077 exit_group(127)
= 279077
close_range
wasn't stubbed out in QEMU until 7.2 qemu/qemu@af804f39cc, meaning anyone running Ubuntu 22.04, Debian Bullseye, or potentially other non-EOL distributions are likely to run into problems unless they:
- deploy a hand built QEMU
- pull a newer QEMU package from a newer version of their distro
- upgrade their distribution
I don't think there's a great way to determine if the interpreter is running under user emulation, so Python likely can't handle this itself and avoid the posix_spawn
call. The knob to disable posix_spawn
, _USE_POSIX_SPAWN
, requires manually flipping the flag which may not be possible when invoking scripts maintained by others (In my case, trying to install Poetry will call ensurepip
which uses subprocess
). There doesn't appear to be any environment variable knob for this either, so it's not as simple as exporting a variable when you know you're running a script in an emulated environment (though i'm not sure environment variable hand off is always guaranteed).
I'm wondering if there needs to be some documentation somewhere, either in subprocess
or os.posix_spawn
that calls out that users running Python under QEMU user emulation needs to have an emulator capable of handling this syscall, hopefully just to save them time debugging the issue.
I realize that making support guarantees under user emulation would be difficult, it's definitely not listed in the support tiers https://peps.python.org/pep-0011/ so understand if this gets closed without further discussion.
Tangentially related, os.closerange
falls back to alternative solutions if close_range
returns an error. The way Python has it wrapped, most cases will not use closefrom
unless the caller specifies a rather large number for the high FD. This could cause problems for environments that don't have a mounted /proc
since the libc implementation of closefrom
raises an error if it can't query this directory.
@gpshead sorry to ping you but saw you looked over the original PR so figured I'd ask if you had thoughts on this?
Linked PRs
Metadata
Metadata
Assignees
Projects
Status