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: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://lore.kernel.org/r/20221122203932.231377-6-mathieu.desnoyers@efficios.com
This commit is contained in:
parent
cbae6bac29
commit
03f5c0272d
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user