From: Daan De Meyer Date: Fri, 12 Sep 2025 09:57:42 +0000 (+0200) Subject: Revert "sandbox: Work around extra file descriptor opened by importing ctypes since... X-Git-Tag: v26~119^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3fa5c9e1cf72dbacdd722e4ba9877e1dcff0f3d8;p=thirdparty%2Fmkosi.git Revert "sandbox: Work around extra file descriptor opened by importing ctypes since python 3.14" This reverts commit 694c8d2721cd6d1081caf39641f615aa81d5f8a0. --- diff --git a/mkosi/sandbox.py b/mkosi/sandbox.py index a265e5276..d210c8f1d 100755 --- a/mkosi/sandbox.py +++ b/mkosi/sandbox.py @@ -8,6 +8,7 @@ minimum, please don't import any extra modules if it can be avoided. """ +import ctypes import os import sys import warnings # noqa: F401 (loaded lazily by os.execvp() which happens too late) @@ -32,6 +33,7 @@ EPERM = 1 ENOENT = 2 ENOSYS = 38 F_DUPFD = 0 +F_GETFD = 1 FS_IOC_GETFLAGS = 0x80086601 FS_IOC_SETFLAGS = 0x40086602 FS_NOCOW_FL = 0x00800000 @@ -64,59 +66,6 @@ SD_LISTEN_FDS_START = 3 SIGSTOP = 19 -def is_valid_fd(fd: int) -> bool: - try: - os.close(os.dup(fd)) - except OSError as e: - if e.errno != EBADF: - raise - - return False - - return True - - -def open_file_descriptors() -> list[int]: - fds = [] - - with os.scandir("/proc/self/fd") as it: - for e in it: - if not e.is_symlink() and (e.is_file() or e.is_dir()): - continue - - try: - fd = int(e.name) - except ValueError: - continue - - fds.append(fd) - - # os.scandir() either opens a file descriptor to the given path or dups the given file descriptor. Either - # way, there will be an extra file descriptor in the fds array that's not valid anymore now, so find out - # which one and drop it. - return sorted(fd for fd in fds if is_valid_fd(fd)) - - -class CloseNewFileDescriptors: - def __enter__(self) -> None: - self.fds = set(open_file_descriptors()) - - def __exit__(self, *args: object, **kwargs: object) -> None: - for fd in open_file_descriptors(): - if fd not in self.fds: - os.close(fd) - - -# Since python 3.14, importing ctypes opens an extra file descriptor which is used to allocate libffi -# closures which are in turn used by ctypes to pass python functions as C callback function pointers. We -# don't use this functionality, yet the file descriptor is still opened and messes with the file descriptor -# packing logic since the file descriptor to libffi will be passed as a packed file descriptor to the -# executable we're invoking. To avoid that from happening, we close libffi's file descriptor after importing -# ctypes. See https://github.com/python/cpython/issues/135893. -with CloseNewFileDescriptors(): - import ctypes - - class mount_attr(ctypes.Structure): _fields_ = [ ("attr_set", ctypes.c_uint64), @@ -560,7 +509,27 @@ def is_relative_to(one: str, two: str) -> bool: def pack_file_descriptors() -> int: - fds = [fd for fd in open_file_descriptors() if fd >= SD_LISTEN_FDS_START] + fds = [] + + with os.scandir("/proc/self/fd") as it: + for e in it: + if not e.is_symlink() and (e.is_file() or e.is_dir()): + continue + + try: + fd = int(e.name) + except ValueError: + continue + + if fd < SD_LISTEN_FDS_START: + continue + + fds.append(fd) + + # os.scandir() either opens a file descriptor to the given path or dups the given file descriptor. Either + # way, there will be an extra file descriptor in the fds array that's not valid anymore now, so find out + # which one and drop it. + fds = sorted(fd for fd in fds if libc.fcntl(fd, F_GETFD, 0) >= 0) # The following is a reimplementation of pack_fds() in systemd.