Merge branch 'fix-futex-time64-usage-android-30' into 'main'

glib/gthread-posix: Block futex_time64 usage on Android API level < 30

See merge request GNOME/glib!3987
This commit is contained in:
Philip Withnall 2024-04-02 09:10:31 +00:00
commit b907e28454
3 changed files with 54 additions and 14 deletions

View File

@ -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
@ -1620,8 +1624,12 @@ 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
{
#endif
struct
{
gint64 tv_sec;
@ -1637,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);
@ -1649,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
@ -1681,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 ();

View File

@ -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 runtimes API level is lower than 30, as its 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(HAVE_FUTEX) && defined(HAVE_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,7 +115,8 @@ struct _GRealThread
} \
} \
G_STMT_END
#elif defined(__NR_futex_time64)
#endif /* defined(__BIONIC__) */
#elif defined(HAVE_FUTEX_TIME64)
#define g_futex_simple(uaddr, futex_op, ...) \
G_STMT_START \
{ \
@ -96,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 \
{ \
@ -108,9 +140,9 @@ 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"
#endif /* 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(HAVE_FUTEX) && defined(HAVE_FUTEX_TIME64) */
#endif

View File

@ -994,7 +994,7 @@ if cc.compiles('''#include <linux/futex.h>
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