From 06ea9aed58c6372b4138d3668ef0f93465ab70d0 Mon Sep 17 00:00:00 2001 From: "L. E. Segovia" Date: Mon, 1 Apr 2024 23:55:01 -0300 Subject: [PATCH 1/3] glib/gthread-posix: Block futex_time64 usage on Android API level < 30 This syscall is seccomp blocked on all lower API levels: https://github.com/aosp-mirror/platform_bionic/commit/ee7bc3002dc3127faac110167d28912eb0e86a20 --- glib/gthread-posix.c | 12 ++++++++++-- glib/gthreadprivate.h | 34 +++++++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/glib/gthread-posix.c b/glib/gthread-posix.c index ad4c006fd..a8cd6314e 100644 --- a/glib/gthread-posix.c +++ b/glib/gthread-posix.c @@ -1605,12 +1605,16 @@ g_cond_wait_until (GCond *cond, * To get around this problem we * a) check if `futex_time64` is available, which only exists on 32-bit * platforms and always uses 64-bit `time_t`. - * b) otherwise (or if that returns `ENOSYS`), we call the normal `futex` + * b) if `futex_time64` is available, but the Android runtime's API level + * is < 30, `futex_time64` is blocked by seccomp and using it will cause + * the app to be terminated. Skip to c). + * https://android-review.googlesource.com/c/platform/bionic/+/1094758 + * c) otherwise (or if that returns `ENOSYS`), we call the normal `futex` * syscall with the `struct timespec` used by the kernel. By default, we * use `__kernel_long_t` for both its fields, which is equivalent to * `__kernel_old_time_t` and is available in the kernel headers for a * longer time. - * c) With very old headers (~2.6.x), `__kernel_long_t` is not available, and + * d) With very old headers (~2.6.x), `__kernel_long_t` is not available, and * we use an older definition that uses `__kernel_time_t` and `long`. * * Also some 32-bit systems do not define `__NR_futex` at all and only @@ -1621,7 +1625,11 @@ g_cond_wait_until (GCond *cond, g_mutex_unlock (mutex); #ifdef __NR_futex_time64 +#if defined(__BIONIC__) + if (__builtin_available (android 30, *)) { +#else { +#endif struct { gint64 tv_sec; diff --git a/glib/gthreadprivate.h b/glib/gthreadprivate.h index 61dfdae34..e2e322763 100644 --- a/glib/gthreadprivate.h +++ b/glib/gthreadprivate.h @@ -64,10 +64,41 @@ struct _GRealThread * with the normal `futex` syscall. This can happen if newer kernel headers * are used than the kernel that is actually running. * + * The `futex_time64` syscall is also skipped in favour of `futex` if the + * Android runtime’s API level is lower than 30, as it’s blocked by seccomp + * there and using it will cause the app to be terminated: + * https://android-review.googlesource.com/c/platform/bionic/+/1094758 + * https://github.com/aosp-mirror/platform_bionic/commit/ee7bc3002dc3127faac110167d28912eb0e86a20 + * * This must not be called with a timeout parameter as that differs * in size between the two syscall variants! */ #if defined(__NR_futex) && defined(__NR_futex_time64) +#if defined(__BIONIC__) +#define g_futex_simple(uaddr, futex_op, ...) \ + G_STMT_START \ + { \ + int res = 0; \ + if (__builtin_available (android 30, *)) \ + { \ + res = syscall (__NR_futex_time64, uaddr, (gsize) futex_op, __VA_ARGS__); \ + if (res < 0 && errno == ENOSYS) \ + { \ + errno = saved_errno; \ + res = syscall (__NR_futex, uaddr, (gsize) futex_op, __VA_ARGS__); \ + } \ + } \ + else \ + { \ + res = syscall (__NR_futex, uaddr, (gsize) futex_op, __VA_ARGS__); \ + } \ + if (res < 0 && errno == EAGAIN) \ + { \ + errno = saved_errno; \ + } \ + } \ + G_STMT_END +#else #define g_futex_simple(uaddr, futex_op, ...) \ G_STMT_START \ { \ @@ -84,6 +115,7 @@ struct _GRealThread } \ } \ G_STMT_END +#endif /* defined(__BIONIC__) */ #elif defined(__NR_futex_time64) #define g_futex_simple(uaddr, futex_op, ...) \ G_STMT_START \ @@ -109,7 +141,7 @@ struct _GRealThread } \ G_STMT_END #else /* !defined(__NR_futex) && !defined(__NR_futex_time64) */ -#error "Neither __NR_futex nor __NR_futex_time64 are defined but were found by meson" +#error "Neither __NR_futex nor __NR_futex_time64 are available" #endif /* defined(__NR_futex) && defined(__NR_futex_time64) */ #endif From ffa639f0b7aae99cffd657bf306358dd623ca9d0 Mon Sep 17 00:00:00 2001 From: "L. E. Segovia" Date: Mon, 1 Apr 2024 23:55:39 -0300 Subject: [PATCH 2/3] glib/gthread-posix: Fix name of the futex_time64(2) test in the Meson log --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 5328adc3a..f0c5e070b 100644 --- a/meson.build +++ b/meson.build @@ -994,7 +994,7 @@ if cc.compiles('''#include int main (int argc, char ** argv) { syscall (__NR_futex_time64, NULL, FUTEX_WAKE, FUTEX_WAIT); return 0; - }''', name : 'futex(2) system call') + }''', name : 'futex_time64(2) system call') glib_conf.set('HAVE_FUTEX_TIME64', 1) endif From 049c8e70c8f759d36bcf70f773e2e748f0f77738 Mon Sep 17 00:00:00 2001 From: "L. E. Segovia" Date: Mon, 1 Apr 2024 23:57:46 -0300 Subject: [PATCH 3/3] glib/gthread-posix: Use the config.h macros to detect futex support --- glib/gthread-posix.c | 10 +++++----- glib/gthreadprivate.h | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/glib/gthread-posix.c b/glib/gthread-posix.c index a8cd6314e..fe2fa23ff 100644 --- a/glib/gthread-posix.c +++ b/glib/gthread-posix.c @@ -1624,7 +1624,7 @@ g_cond_wait_until (GCond *cond, sampled = cond->i[0]; g_mutex_unlock (mutex); -#ifdef __NR_futex_time64 +#if defined(HAVE_FUTEX_TIME64) #if defined(__BIONIC__) if (__builtin_available (android 30, *)) { #else @@ -1645,9 +1645,9 @@ g_cond_wait_until (GCond *cond, * normal `futex` syscall. This can happen if newer kernel headers are * used than the kernel that is actually running. */ -# ifdef __NR_futex +# if defined(HAVE_FUTEX) if (res >= 0 || errno != ENOSYS) -# endif /* defined(__NR_futex) */ +# endif /* defined(HAVE_FUTEX) */ { success = (res < 0 && errno == ETIMEDOUT) ? FALSE : TRUE; g_mutex_lock (mutex); @@ -1657,7 +1657,7 @@ g_cond_wait_until (GCond *cond, } #endif -#ifdef __NR_futex +#if defined(HAVE_FUTEX) { # ifdef __kernel_long_t # define KERNEL_SPAN_SEC_TYPE __kernel_long_t @@ -1689,7 +1689,7 @@ g_cond_wait_until (GCond *cond, return success; } # undef KERNEL_SPAN_SEC_TYPE -#endif /* defined(__NR_futex) */ +#endif /* defined(HAVE_FUTEX) */ /* We can't end up here because of the checks above */ g_assert_not_reached (); diff --git a/glib/gthreadprivate.h b/glib/gthreadprivate.h index e2e322763..7bc28a834 100644 --- a/glib/gthreadprivate.h +++ b/glib/gthreadprivate.h @@ -73,7 +73,7 @@ struct _GRealThread * This must not be called with a timeout parameter as that differs * in size between the two syscall variants! */ -#if defined(__NR_futex) && defined(__NR_futex_time64) +#if defined(HAVE_FUTEX) && defined(HAVE_FUTEX_TIME64) #if defined(__BIONIC__) #define g_futex_simple(uaddr, futex_op, ...) \ G_STMT_START \ @@ -116,7 +116,7 @@ struct _GRealThread } \ G_STMT_END #endif /* defined(__BIONIC__) */ -#elif defined(__NR_futex_time64) +#elif defined(HAVE_FUTEX_TIME64) #define g_futex_simple(uaddr, futex_op, ...) \ G_STMT_START \ { \ @@ -128,7 +128,7 @@ struct _GRealThread } \ } \ G_STMT_END -#elif defined(__NR_futex) +#elif defined(HAVE_FUTEX) #define g_futex_simple(uaddr, futex_op, ...) \ G_STMT_START \ { \ @@ -140,9 +140,9 @@ struct _GRealThread } \ } \ G_STMT_END -#else /* !defined(__NR_futex) && !defined(__NR_futex_time64) */ +#else /* !defined(HAVE_FUTEX) && !defined(HAVE_FUTEX_TIME64) */ #error "Neither __NR_futex nor __NR_futex_time64 are available" -#endif /* defined(__NR_futex) && defined(__NR_futex_time64) */ +#endif /* defined(HAVE_FUTEX) && defined(HAVE_FUTEX_TIME64) */ #endif