pythonsubprocesssudo

sudo + fork + Python subprocess = [Errno 38] Function not implemented


Here's a simplified Python script (henceforth app.py) that forks a child which then runs a subprocess:

import os
import subprocess

if os.fork() > 0:
    os._exit(0)

subprocess.run(["/bin/true"])

When run as a normal user, it works:

$ python3 app.py
$ echo $?
0

When run as root from a sudo-launched parent shell, it works:

$ sudo bash
# python3 app.py
#

However when the parent is sudo, it fails in a bizarre way:

$ sudo python3 app.py
$ Traceback (most recent call last):
  File "/tmp/app.py", line 7, in <module>
    subprocess.run(["/bin/true"])
  File "/usr/lib/python3.11/subprocess.py", line 548, in run
    with Popen(*popenargs, **kwargs) as process:
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/subprocess.py", line 1026, in __init__
    self._execute_child(args, executable, preexec_fn, close_fds,
  File "/usr/lib/python3.11/subprocess.py", line 1955, in _execute_child
    raise child_exception_type(errno_num, err_msg, err_filename)
OSError: [Errno 38] Function not implemented: '/bin/true'

and:

$ sudo bash
# exec python3 app.py
$ Traceback ... (same error message as above)

Apparently something in the child process created by subprocess.run it getting ENOSYS, but it's a mystery to me how having sudo as the parent can cause this.

Update: The system in question is TrueNAS SCALE (Debian-derived Linux) with Python 3.11.9. Since posting I discovered that this does not repro on another Linux system, so I now suspect it is somehow related to sudo configuration or kernel security options.


Solution

  • The culprit for this was the log_subcmds option in sudoers, which itself uses ptrace and seccomp and has some documented limitations.

    Thanks to DymOK on the TrueNAS forum who figured this out.