Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
:mod:`os` and :mod:`signal`: Use glibc functions instead of ``syscall()``:
``pidfd_open()``, ``pidfd_getfd()`` and ``pidfd_send_signal()`` (glibc 2.36),
``gettid()`` and ``getdents64()`` (glibc 2.30), and ``getrandom()`` (glibc
2.25). Patch by Victor Stinner.
32 changes: 23 additions & 9 deletions Modules/_posixsubprocess.c
Original file line number Diff line number Diff line change
Expand Up @@ -388,20 +388,26 @@ _close_range_except(int start_fd,
return 0;
}

#if defined(__linux__) && defined(HAVE_SYS_SYSCALL_H)
#if defined(HAVE_GETDENTS64) \
|| (defined(__linux__) && defined(HAVE_SYS_SYSCALL_H))

#ifdef HAVE_GETDENTS64
# define py_dirent64 dirent64
#else
/* It doesn't matter if d_name has room for NAME_MAX chars; we're using this
* only to read a directory of short file descriptor number names. The kernel
* will return an error if we didn't give it enough space. Highly Unlikely.
* This structure is very old and stable: It will not change unless the kernel
* chooses to break compatibility with all existing binaries. Highly Unlikely.
*/
struct linux_dirent64 {
struct py_dirent64 {
unsigned long long d_ino;
long long d_off;
unsigned short d_reclen; /* Length of this linux_dirent */
unsigned char d_type;
char d_name[256]; /* Filename (null-terminated) */
};
#endif // !HAVE_GETDENTS64

static int
_brute_force_closer(int first, int last)
Expand Down Expand Up @@ -441,19 +447,27 @@ _close_open_fds_safe(int start_fd, int *fds_to_keep, Py_ssize_t fds_to_keep_len)
_brute_force_closer);
return;
} else {
char buffer[sizeof(struct linux_dirent64)];
int bytes;
while ((bytes = syscall(SYS_getdents64, fd_dir_fd,
(struct linux_dirent64 *)buffer,
sizeof(buffer))) > 0) {
struct linux_dirent64 *entry;
char buffer[sizeof(struct py_dirent64)];
Py_ssize_t bytes;
while (1) {
#ifdef HAVE_GETDENTS64
bytes = getdents64(fd_dir_fd, buffer, sizeof(buffer));
#else
bytes = syscall(SYS_getdents64, fd_dir_fd,
(struct py_dirent64 *)buffer, sizeof(buffer));
#endif
if (bytes <= 0) {
break;
}

struct py_dirent64 *entry;
int offset;
#ifdef _Py_MEMORY_SANITIZER
__msan_unpoison(buffer, bytes);
#endif
for (offset = 0; offset < bytes; offset += entry->d_reclen) {
int fd;
entry = (struct linux_dirent64 *)(buffer + offset);
entry = (struct py_dirent64 *)(buffer + offset);
if ((fd = _pos_int_from_ascii(entry->d_name)) < 0)
continue; /* Not a number. */
if (fd != fd_dir_fd && fd >= start_fd &&
Expand Down
36 changes: 24 additions & 12 deletions Modules/clinic/posixmodule.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 20 additions & 8 deletions Modules/clinic/signalmodule.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

36 changes: 27 additions & 9 deletions Modules/posixmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@
# include "emscripten.h" // emscripten_debugger()
#endif

#ifdef HAVE_SYS_RANDOM_H
# include <sys/random.h> // getrandom()
#endif

#ifdef HAVE_SYS_UIO_H
# include <sys/uio.h>
#endif
Expand Down Expand Up @@ -10810,8 +10814,9 @@ os_wait_impl(PyObject *module)


// This system call always crashes on older Android versions.
#if defined(__linux__) && defined(__NR_pidfd_open) && \
!(defined(__ANDROID__) && __ANDROID_API__ < 31)
#if defined(HAVE_PIDFD_OPEN) \
|| (defined(__linux__) && defined(__NR_pidfd_open) \
&& !(defined(__ANDROID__) && __ANDROID_API__ < 31))
/*[clinic input]
os.pidfd_open
pid: pid_t
Expand All @@ -10827,7 +10832,11 @@ static PyObject *
os_pidfd_open_impl(PyObject *module, pid_t pid, unsigned int flags)
/*[clinic end generated code: output=5c7252698947dc41 input=03058b32c389f874]*/
{
#ifdef HAVE_PIDFD_OPEN
int fd = pidfd_open(pid, flags);
#else
int fd = syscall(__NR_pidfd_open, pid, flags);
#endif
if (fd < 0) {
return posix_error();
}
Expand All @@ -10836,8 +10845,9 @@ os_pidfd_open_impl(PyObject *module, pid_t pid, unsigned int flags)
#endif


#if defined(__linux__) && defined(__NR_pidfd_getfd) && \
!(defined(__ANDROID__) && __ANDROID_API__ < 31)
#if defined(HAVE_PIDFD_GETFD) \
|| (defined(__linux__) && defined(__NR_pidfd_getfd) \
&& !(defined(__ANDROID__) && __ANDROID_API__ < 31))
/*[clinic input]
os.pidfd_getfd
pidfd: int
Expand All @@ -10856,7 +10866,11 @@ os_pidfd_getfd_impl(PyObject *module, int pidfd, int targetfd,
unsigned int flags)
/*[clinic end generated code: output=e1a1415a13c7137f input=ef6417fb10deb1cc]*/
{
#ifdef HAVE_PIDFD_GETFD
int fd = pidfd_getfd(pidfd, targetfd, flags);
#else
int fd = syscall(__NR_pidfd_getfd, pidfd, targetfd, flags);
#endif
if (fd < 0) {
return posix_error();
}
Expand Down Expand Up @@ -17369,19 +17383,19 @@ os_fspath_impl(PyObject *module, PyObject *path)
return PyOS_FSPath(path);
}

#ifdef HAVE_GETRANDOM_SYSCALL
#if defined(HAVE_GETRANDOM) || defined(HAVE_GETRANDOM_SYSCALL)
/*[clinic input]
os.getrandom

size: Py_ssize_t
flags: int=0
flags: unsigned_int(bitwise=True) = 0

Obtain a series of random bytes.
[clinic start generated code]*/

static PyObject *
os_getrandom_impl(PyObject *module, Py_ssize_t size, int flags)
/*[clinic end generated code: output=b3a618196a61409c input=59bafac39c594947]*/
os_getrandom_impl(PyObject *module, Py_ssize_t size, unsigned int flags)
/*[clinic end generated code: output=c2163c05f0e1d0a1 input=e0174983f5703f82]*/
{
if (size < 0) {
errno = EINVAL;
Expand All @@ -17396,7 +17410,11 @@ os_getrandom_impl(PyObject *module, Py_ssize_t size, int flags)

Py_ssize_t n;
while (1) {
#ifdef HAVE_GETRANDOM
n = getrandom(data, size, flags);
#else
n = syscall(SYS_getrandom, data, size, flags);
#endif
if (n < 0 && errno == EINTR) {
if (PyErr_CheckSignals() < 0) {
goto error;
Expand Down Expand Up @@ -18504,7 +18522,7 @@ all_ins(PyObject *m)
if (PyModule_AddIntMacro(m, RTLD_MEMBER)) return -1;
#endif

#ifdef HAVE_GETRANDOM_SYSCALL
#if defined(HAVE_GETRANDOM) || defined(HAVE_GETRANDOM_SYSCALL)
if (PyModule_AddIntMacro(m, GRND_RANDOM)) return -1;
if (PyModule_AddIntMacro(m, GRND_NONBLOCK)) return -1;
#endif
Expand Down
22 changes: 16 additions & 6 deletions Modules/signalmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@
# include <pthread.h>
#endif

#ifdef HAVE_SYS_PIDFD_H
# include <sys/pidfd.h> // pidfd_send_signal()
#endif

#ifndef SIG_ERR
# define SIG_ERR ((PyOS_sighandler_t)(-1))
#endif
Expand Down Expand Up @@ -1300,31 +1304,37 @@ signal_pthread_kill_impl(PyObject *module, unsigned long thread_id,


// This system call always crashes on older Android versions.
#if defined(__linux__) && defined(__NR_pidfd_send_signal) && \
!(defined(__ANDROID__) && __ANDROID_API__ < 31)
#if defined(HAVE_PIDFD_SEND_SIGNAL) \
|| (defined(__linux__) && defined(__NR_pidfd_send_signal) \
&& !(defined(__ANDROID__) && __ANDROID_API__ < 31))
/*[clinic input]
signal.pidfd_send_signal

pidfd: int
signalnum: int
siginfo: object = None
flags: int = 0
flags: unsigned_int(bitwise=True) = 0
/

Send a signal to a process referred to by a pid file descriptor.
[clinic start generated code]*/

static PyObject *
signal_pidfd_send_signal_impl(PyObject *module, int pidfd, int signalnum,
PyObject *siginfo, int flags)
/*[clinic end generated code: output=2d59f04a75d9cbdf input=2a6543a1f4ac2000]*/
PyObject *siginfo, unsigned int flags)
/*[clinic end generated code: output=1804b5a19d269104 input=a6e82a3c264fa19d]*/

{
if (siginfo != Py_None) {
PyErr_SetString(PyExc_TypeError, "siginfo must be None");
return NULL;
}
if (syscall(__NR_pidfd_send_signal, pidfd, signalnum, NULL, flags) < 0) {
#ifdef HAVE_PIDFD_SEND_SIGNAL
int res = pidfd_send_signal(pidfd, signalnum, NULL, flags);
#else
int res = syscall(__NR_pidfd_send_signal, pidfd, signalnum, NULL, flags);
#endif
if (res < 0) {
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
Expand Down
Loading
Loading