selftests/rseq: Fix mm_cid test failure
commit a0cc649353bb726d4aa0db60dce467432197b746 upstream.
Adapt the rseq.c/rseq.h code to follow GNU C library changes introduced by:
glibc commit 2e456ccf0c34 ("Linux: Make __rseq_size useful for feature detection (bug 31965)")
Without this fix, rseq selftests for mm_cid fail:
./run_param_test.sh
Default parameters
Running test spinlock
Running compare-twice test spinlock
Running mm_cid test spinlock
Error: cpu id getter unavailable
Fixes: 18c2355838
("selftests/rseq: Implement rseq mm_cid field support")
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Peter Zijlstra <peterz@infradead.org>
CC: Boqun Feng <boqun.feng@gmail.com>
CC: "Paul E. McKenney" <paulmck@kernel.org>
Cc: Shuah Khan <skhan@linuxfoundation.org>
CC: Carlos O'Donell <carlos@redhat.com>
CC: Florian Weimer <fweimer@redhat.com>
CC: linux-kselftest@vger.kernel.org
CC: stable@vger.kernel.org
Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
87070a96b1
commit
73a4f5a704
|
@ -60,12 +60,6 @@ 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. */
|
||||
|
||||
|
@ -111,6 +105,43 @@ int rseq_available(void)
|
|||
}
|
||||
}
|
||||
|
||||
/* The rseq areas need to be at least 32 bytes. */
|
||||
static
|
||||
unsigned int get_rseq_min_alloc_size(void)
|
||||
{
|
||||
unsigned int alloc_size = rseq_size;
|
||||
|
||||
if (alloc_size < ORIG_RSEQ_ALLOC_SIZE)
|
||||
alloc_size = ORIG_RSEQ_ALLOC_SIZE;
|
||||
return alloc_size;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the feature size supported by the kernel.
|
||||
*
|
||||
* Depending on the value returned by getauxval(AT_RSEQ_FEATURE_SIZE):
|
||||
*
|
||||
* 0: Return ORIG_RSEQ_FEATURE_SIZE (20)
|
||||
* > 0: Return the value from getauxval(AT_RSEQ_FEATURE_SIZE).
|
||||
*
|
||||
* It should never return a value below ORIG_RSEQ_FEATURE_SIZE.
|
||||
*/
|
||||
static
|
||||
unsigned int get_rseq_kernel_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;
|
||||
}
|
||||
|
||||
int rseq_register_current_thread(void)
|
||||
{
|
||||
int rc;
|
||||
|
@ -119,7 +150,7 @@ int rseq_register_current_thread(void)
|
|||
/* Treat libc's ownership as a successful registration. */
|
||||
return 0;
|
||||
}
|
||||
rc = sys_rseq(&__rseq_abi, rseq_size, 0, RSEQ_SIG);
|
||||
rc = sys_rseq(&__rseq_abi, get_rseq_min_alloc_size(), 0, RSEQ_SIG);
|
||||
if (rc) {
|
||||
if (RSEQ_READ_ONCE(rseq_reg_success)) {
|
||||
/* Incoherent success/failure within process. */
|
||||
|
@ -140,28 +171,12 @@ int rseq_unregister_current_thread(void)
|
|||
/* Treat libc's ownership as a successful unregistration. */
|
||||
return 0;
|
||||
}
|
||||
rc = sys_rseq(&__rseq_abi, rseq_size, RSEQ_ABI_FLAG_UNREGISTER, RSEQ_SIG);
|
||||
rc = sys_rseq(&__rseq_abi, get_rseq_min_alloc_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)
|
||||
{
|
||||
|
@ -178,28 +193,54 @@ void rseq_init(void)
|
|||
}
|
||||
if (libc_rseq_size_p && libc_rseq_offset_p && libc_rseq_flags_p &&
|
||||
*libc_rseq_size_p != 0) {
|
||||
unsigned int libc_rseq_size;
|
||||
|
||||
/* rseq registration owned by glibc */
|
||||
rseq_offset = *libc_rseq_offset_p;
|
||||
rseq_size = *libc_rseq_size_p;
|
||||
libc_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;
|
||||
|
||||
/*
|
||||
* Previous versions of glibc expose the value
|
||||
* 32 even though the kernel only supported 20
|
||||
* bytes initially. Therefore treat 32 as a
|
||||
* special-case. glibc 2.40 exposes a 20 bytes
|
||||
* __rseq_size without using getauxval(3) to
|
||||
* query the supported size, while still allocating a 32
|
||||
* bytes area. Also treat 20 as a special-case.
|
||||
*
|
||||
* Special-cases are handled by using the following
|
||||
* value as active feature set size:
|
||||
*
|
||||
* rseq_size = min(32, get_rseq_kernel_feature_size())
|
||||
*/
|
||||
switch (libc_rseq_size) {
|
||||
case ORIG_RSEQ_FEATURE_SIZE:
|
||||
fallthrough;
|
||||
case ORIG_RSEQ_ALLOC_SIZE:
|
||||
{
|
||||
unsigned int rseq_kernel_feature_size = get_rseq_kernel_feature_size();
|
||||
|
||||
if (rseq_kernel_feature_size < ORIG_RSEQ_ALLOC_SIZE)
|
||||
rseq_size = rseq_kernel_feature_size;
|
||||
else
|
||||
rseq_size = ORIG_RSEQ_ALLOC_SIZE;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
/* Otherwise just use the __rseq_size from libc as rseq_size. */
|
||||
rseq_size = libc_rseq_size;
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
rseq_ownership = 1;
|
||||
if (!rseq_available()) {
|
||||
rseq_size = 0;
|
||||
rseq_feature_size = 0;
|
||||
return;
|
||||
}
|
||||
rseq_offset = (void *)&__rseq_abi - rseq_thread_pointer();
|
||||
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))
|
||||
|
@ -209,7 +250,6 @@ void rseq_exit(void)
|
|||
return;
|
||||
rseq_offset = 0;
|
||||
rseq_size = -1U;
|
||||
rseq_feature_size = -1U;
|
||||
rseq_ownership = 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -68,12 +68,6 @@ extern unsigned int rseq_size;
|
|||
/* 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;
|
||||
|
||||
enum rseq_mo {
|
||||
RSEQ_MO_RELAXED = 0,
|
||||
RSEQ_MO_CONSUME = 1, /* Unused */
|
||||
|
@ -193,7 +187,7 @@ static inline uint32_t rseq_current_cpu(void)
|
|||
|
||||
static inline bool rseq_node_id_available(void)
|
||||
{
|
||||
return (int) rseq_feature_size >= rseq_offsetofend(struct rseq_abi, node_id);
|
||||
return (int) rseq_size >= rseq_offsetofend(struct rseq_abi, node_id);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -207,7 +201,7 @@ static inline uint32_t rseq_current_node_id(void)
|
|||
|
||||
static inline bool rseq_mm_cid_available(void)
|
||||
{
|
||||
return (int) rseq_feature_size >= rseq_offsetofend(struct rseq_abi, mm_cid);
|
||||
return (int) rseq_size >= rseq_offsetofend(struct rseq_abi, mm_cid);
|
||||
}
|
||||
|
||||
static inline uint32_t rseq_current_mm_cid(void)
|
||||
|
|
Loading…
Reference in New Issue