Commit 03f5c027 authored by Mathieu Desnoyers's avatar Mathieu Desnoyers Committed by Peter Zijlstra

selftests/rseq: Use ELF auxiliary vector for extensible rseq

Use the ELF auxiliary vector AT_RSEQ_FEATURE_SIZE to detect the RSEQ
features supported by the kernel.
Signed-off-by: default avatarMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Signed-off-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/r/20221122203932.231377-6-mathieu.desnoyers@efficios.com
parent cbae6bac
......@@ -146,6 +146,11 @@ struct rseq_abi {
* this thread.
*/
__u32 flags;
/*
* Flexible array member at end of structure, after last feature field.
*/
char end[];
} __attribute__((aligned(4 * sizeof(__u64))));
#endif /* _RSEQ_ABI_H */
......@@ -28,6 +28,8 @@
#include <limits.h>
#include <dlfcn.h>
#include <stddef.h>
#include <sys/auxv.h>
#include <linux/auxvec.h>
#include "../kselftest.h"
#include "rseq.h"
......@@ -36,20 +38,38 @@ static const ptrdiff_t *libc_rseq_offset_p;
static const unsigned int *libc_rseq_size_p;
static const unsigned int *libc_rseq_flags_p;
/* Offset from the thread pointer to the rseq area. */
/* Offset from the thread pointer to the rseq area. */
ptrdiff_t rseq_offset;
/* Size of the registered rseq area. 0 if the registration was
unsuccessful. */
/*
* Size of the registered rseq area. 0 if the registration was
* unsuccessful.
*/
unsigned int rseq_size = -1U;
/* Flags used during rseq registration. */
unsigned int rseq_flags;
/*
* rseq feature size supported by the kernel. 0 if the registration was
* unsuccessful.
*/
unsigned int rseq_feature_size = -1U;
static int rseq_ownership;
static int rseq_reg_success; /* At least one rseq registration has succeded. */
/* Allocate a large area for the TLS. */
#define RSEQ_THREAD_AREA_ALLOC_SIZE 1024
/* Original struct rseq feature size is 20 bytes. */
#define ORIG_RSEQ_FEATURE_SIZE 20
/* Original struct rseq allocation size is 32 bytes. */
#define ORIG_RSEQ_ALLOC_SIZE 32
static
__thread struct rseq_abi __rseq_abi __attribute__((tls_model("initial-exec"))) = {
__thread struct rseq_abi __rseq_abi __attribute__((tls_model("initial-exec"), aligned(RSEQ_THREAD_AREA_ALLOC_SIZE))) = {
.cpu_id = RSEQ_ABI_CPU_ID_UNINITIALIZED,
};
......@@ -84,10 +104,16 @@ int rseq_register_current_thread(void)
/* Treat libc's ownership as a successful registration. */
return 0;
}
rc = sys_rseq(&__rseq_abi, sizeof(struct rseq_abi), 0, RSEQ_SIG);
if (rc)
rc = sys_rseq(&__rseq_abi, rseq_size, 0, RSEQ_SIG);
if (rc) {
if (RSEQ_READ_ONCE(rseq_reg_success)) {
/* Incoherent success/failure within process. */
abort();
}
return -1;
}
assert(rseq_current_cpu_raw() >= 0);
RSEQ_WRITE_ONCE(rseq_reg_success, 1);
return 0;
}
......@@ -99,12 +125,28 @@ int rseq_unregister_current_thread(void)
/* Treat libc's ownership as a successful unregistration. */
return 0;
}
rc = sys_rseq(&__rseq_abi, sizeof(struct rseq_abi), RSEQ_ABI_FLAG_UNREGISTER, RSEQ_SIG);
rc = sys_rseq(&__rseq_abi, rseq_size, RSEQ_ABI_FLAG_UNREGISTER, RSEQ_SIG);
if (rc)
return -1;
return 0;
}
static
unsigned int get_rseq_feature_size(void)
{
unsigned long auxv_rseq_feature_size, auxv_rseq_align;
auxv_rseq_align = getauxval(AT_RSEQ_ALIGN);
assert(!auxv_rseq_align || auxv_rseq_align <= RSEQ_THREAD_AREA_ALLOC_SIZE);
auxv_rseq_feature_size = getauxval(AT_RSEQ_FEATURE_SIZE);
assert(!auxv_rseq_feature_size || auxv_rseq_feature_size <= RSEQ_THREAD_AREA_ALLOC_SIZE);
if (auxv_rseq_feature_size)
return auxv_rseq_feature_size;
else
return ORIG_RSEQ_FEATURE_SIZE;
}
static __attribute__((constructor))
void rseq_init(void)
{
......@@ -117,16 +159,24 @@ void rseq_init(void)
rseq_offset = *libc_rseq_offset_p;
rseq_size = *libc_rseq_size_p;
rseq_flags = *libc_rseq_flags_p;
rseq_feature_size = get_rseq_feature_size();
if (rseq_feature_size > rseq_size)
rseq_feature_size = rseq_size;
return;
}
rseq_ownership = 1;
if (!rseq_available()) {
rseq_size = 0;
rseq_feature_size = 0;
return;
}
rseq_offset = (void *)&__rseq_abi - rseq_thread_pointer();
rseq_size = sizeof(struct rseq_abi);
rseq_flags = 0;
rseq_feature_size = get_rseq_feature_size();
if (rseq_feature_size == ORIG_RSEQ_FEATURE_SIZE)
rseq_size = ORIG_RSEQ_ALLOC_SIZE;
else
rseq_size = RSEQ_THREAD_AREA_ALLOC_SIZE;
}
static __attribute__((destructor))
......@@ -136,6 +186,7 @@ void rseq_exit(void)
return;
rseq_offset = 0;
rseq_size = -1U;
rseq_feature_size = -1U;
rseq_ownership = 0;
}
......
......@@ -47,14 +47,24 @@
#include "rseq-thread-pointer.h"
/* Offset from the thread pointer to the rseq area. */
/* Offset from the thread pointer to the rseq area. */
extern ptrdiff_t rseq_offset;
/* Size of the registered rseq area. 0 if the registration was
unsuccessful. */
/*
* Size of the registered rseq area. 0 if the registration was
* unsuccessful.
*/
extern unsigned int rseq_size;
/* Flags used during rseq registration. */
/* Flags used during rseq registration. */
extern unsigned int rseq_flags;
/*
* rseq feature size supported by the kernel. 0 if the registration was
* unsuccessful.
*/
extern unsigned int rseq_feature_size;
static inline struct rseq_abi *rseq_get_abi(void)
{
return (struct rseq_abi *) ((uintptr_t) rseq_thread_pointer() + rseq_offset);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment