mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 04:18:58 +00:00
linux_kselftest-fixes-6.12-rc3
This kselftest update for Linux 6.12-rc3 consists of several fixes for build, run-time errors, and reporting errors: -- ftrace: regression test for a kernel crash when running function graph tracing and then enabling function profiler. -- rseq: fix for mm_cid test failure. -- vDSO: - fixes to reporting skip and other error conditions. - changes unconditionally build chacha and getrandom tests on all architectures to make it easier for them to run in CIs. - build error when sched.h to bring in CLONE_NEWTIME define. -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEPZKym/RZuOCGeA/kCwJExA0NQxwFAmcJnTAACgkQCwJExA0N QxxG0w/6AnqINbQIrpn8OmdublNPfh+fMpRFPYQLqDFJhFl7vc8Qp/m0kApcFQCC B15LSnxSdy4imhCYjtLaXsKsd6oFL4cv0sFswHCT7YFOd4q8yPzU7SvDERetFKJV 1/nhq2VR86jVMnoZioiHvb96xVrCw+YUtbJrG6qUfAO7nlnZ2Rtme5ZUSZ5EhEtt i5UGolc1qeCOF01H2Cg+Y4SZp1pP4YBZuV04miK3xvzrRx3sB9U8Rzd/1yVAbD1d BuQ5fIogu0+DiL5yIADaY6KB1IYfQojOtU0lOFCHyn7cpOpH0XT3pmRy+SrYf094 nX+UFDdHuX0565rZJMzqGryqrc3sZz/wtVHrMD04NqwkdNEfoHL2ABlrGepTBMbd Tqs7BpKnvuBz+WlM7oDTu3S94ZwukT3tZ6A6VOYQDSflOIYLbmVTK4DvG5yVAmoW u4LxCDC9ODuUTvxeGmHlI4UpR7f0EArY3Rf2UeCGHaHwKgAhAY4Ti/gwmddpg60i 2nbZ2cneTqtVn0C0fc612EXv6uqlk8onj+1Usp9PVqeYrhGKl2DPuFDoBVpBGr0W Mi0CISrgrFngsVxsLlaHnn31e4SyWSLODKp2y5H7WfFU0eZCRb3efleVADpmEqRr NI0Pzhw1cvz72G1XFvVZtALeEPdA5cdKwTuutxfgGlkjwAKyw5M= =1etd -----END PGP SIGNATURE----- Merge tag 'linux_kselftest-fixes-6.12-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest Pull kselftest fixes from Shuah Khan: "Fixes for build, run-time errors, and reporting errors: - ftrace: regression test for a kernel crash when running function graph tracing and then enabling function profiler. - rseq: fix for mm_cid test failure. - vDSO: - fixes to reporting skip and other error conditions - changes unconditionally build chacha and getrandom tests on all architectures to make it easier for them to run in CIs - build error when sched.h to bring in CLONE_NEWTIME define" * tag 'linux_kselftest-fixes-6.12-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest: ftrace/selftest: Test combination of function_graph tracer and function profiler selftests/rseq: Fix mm_cid test failure selftests: vDSO: Explicitly include sched.h selftests: vDSO: improve getrandom and chacha error messages selftests: vDSO: unconditionally build getrandom test selftests: vDSO: unconditionally build chacha test
This commit is contained in:
commit
09f6b0c890
@ -1 +0,0 @@
|
||||
../../../arch/arm64/kernel/vdso
|
@ -1 +0,0 @@
|
||||
../../../arch/loongarch/vdso
|
@ -1 +0,0 @@
|
||||
../../../arch/powerpc/kernel/vdso
|
@ -1 +0,0 @@
|
||||
../../../arch/s390/kernel/vdso64
|
@ -1 +0,0 @@
|
||||
../../../arch/x86/entry/vdso/
|
@ -0,0 +1,31 @@
|
||||
#!/bin/sh
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# description: ftrace - function profiler with function graph tracing
|
||||
# requires: function_profile_enabled set_ftrace_filter function_graph:tracer
|
||||
|
||||
# The function graph tracer can now be run along side of the function
|
||||
# profiler. But there was a bug that caused the combination of the two
|
||||
# to crash. It also required the function graph tracer to be started
|
||||
# first.
|
||||
#
|
||||
# This test triggers that bug
|
||||
#
|
||||
# We need both function_graph and profiling to run this test
|
||||
|
||||
fail() { # mesg
|
||||
echo $1
|
||||
exit_fail
|
||||
}
|
||||
|
||||
echo "Enabling function graph tracer:"
|
||||
echo function_graph > current_tracer
|
||||
echo "enable profiler"
|
||||
|
||||
# Older kernels do not allow function_profile to be enabled with
|
||||
# function graph tracer. If the below fails, mark it as unsupported
|
||||
echo 1 > function_profile_enabled || exit_unsupported
|
||||
|
||||
# Let it run for a bit to make sure nothing explodes
|
||||
sleep 1
|
||||
|
||||
exit 0
|
@ -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)
|
||||
|
@ -9,10 +9,8 @@ ifeq ($(ARCH),$(filter $(ARCH),x86 x86_64))
|
||||
TEST_GEN_PROGS += vdso_standalone_test_x86
|
||||
endif
|
||||
TEST_GEN_PROGS += vdso_test_correctness
|
||||
ifeq ($(ARCH)$(CONFIG_X86_32),$(filter $(ARCH)$(CONFIG_X86_32),x86 x86_64 loongarch arm64 powerpc s390))
|
||||
TEST_GEN_PROGS += vdso_test_getrandom
|
||||
TEST_GEN_PROGS += vdso_test_chacha
|
||||
endif
|
||||
|
||||
CFLAGS := -std=gnu99 -O2
|
||||
|
||||
@ -37,9 +35,9 @@ $(OUTPUT)/vdso_test_getrandom: CFLAGS += -isystem $(top_srcdir)/tools/include \
|
||||
$(KHDR_INCLUDES) \
|
||||
-isystem $(top_srcdir)/include/uapi
|
||||
|
||||
$(OUTPUT)/vdso_test_chacha: $(top_srcdir)/tools/arch/$(SRCARCH)/vdso/vgetrandom-chacha.S
|
||||
$(OUTPUT)/vdso_test_chacha: vgetrandom-chacha.S
|
||||
$(OUTPUT)/vdso_test_chacha: CFLAGS += -idirafter $(top_srcdir)/tools/include \
|
||||
-idirafter $(top_srcdir)/tools/include/generated \
|
||||
-idirafter $(top_srcdir)/arch/$(SRCARCH)/include \
|
||||
-idirafter $(top_srcdir)/include \
|
||||
-D__ASSEMBLY__ -Wa,--noexecstack
|
||||
-Wa,--noexecstack
|
||||
|
@ -3,6 +3,7 @@
|
||||
* Copyright (C) 2022-2024 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
*/
|
||||
|
||||
#include <linux/compiler.h>
|
||||
#include <tools/le_byteshift.h>
|
||||
#include <sys/random.h>
|
||||
#include <sys/auxv.h>
|
||||
@ -73,10 +74,10 @@ static void reference_chacha20_blocks(uint8_t *dst_bytes, const uint32_t *key, u
|
||||
counter[1] = s[13];
|
||||
}
|
||||
|
||||
typedef uint8_t u8;
|
||||
typedef uint32_t u32;
|
||||
typedef uint64_t u64;
|
||||
#include <vdso/getrandom.h>
|
||||
void __weak __arch_chacha20_blocks_nostack(uint8_t *dst_bytes, const uint32_t *key, uint32_t *counter, size_t nblocks)
|
||||
{
|
||||
ksft_exit_skip("Not implemented on architecture\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
@ -90,10 +91,8 @@ int main(int argc, char *argv[])
|
||||
ksft_set_plan(1);
|
||||
|
||||
for (unsigned int trial = 0; trial < TRIALS; ++trial) {
|
||||
if (getrandom(key, sizeof(key), 0) != sizeof(key)) {
|
||||
printf("getrandom() failed!\n");
|
||||
return KSFT_SKIP;
|
||||
}
|
||||
if (getrandom(key, sizeof(key), 0) != sizeof(key))
|
||||
ksft_exit_skip("getrandom() failed unexpectedly\n");
|
||||
memset(counter1, 0, sizeof(counter1));
|
||||
reference_chacha20_blocks(output1, key, counter1, BLOCKS);
|
||||
for (unsigned int split = 0; split < BLOCKS; ++split) {
|
||||
@ -102,8 +101,10 @@ int main(int argc, char *argv[])
|
||||
if (split)
|
||||
__arch_chacha20_blocks_nostack(output2, key, counter2, split);
|
||||
__arch_chacha20_blocks_nostack(output2 + split * BLOCK_SIZE, key, counter2, BLOCKS - split);
|
||||
if (memcmp(output1, output2, sizeof(output1)) || memcmp(counter1, counter2, sizeof(counter1)))
|
||||
return KSFT_FAIL;
|
||||
if (memcmp(output1, output2, sizeof(output1)))
|
||||
ksft_exit_fail_msg("Main loop outputs do not match on trial %u, split %u\n", trial, split);
|
||||
if (memcmp(counter1, counter2, sizeof(counter1)))
|
||||
ksft_exit_fail_msg("Main loop counters do not match on trial %u, split %u\n", trial, split);
|
||||
}
|
||||
}
|
||||
memset(counter1, 0, sizeof(counter1));
|
||||
@ -113,14 +114,19 @@ int main(int argc, char *argv[])
|
||||
|
||||
reference_chacha20_blocks(output1, key, counter1, BLOCKS);
|
||||
__arch_chacha20_blocks_nostack(output2, key, counter2, BLOCKS);
|
||||
if (memcmp(output1, output2, sizeof(output1)) || memcmp(counter1, counter2, sizeof(counter1)))
|
||||
return KSFT_FAIL;
|
||||
if (memcmp(output1, output2, sizeof(output1)))
|
||||
ksft_exit_fail_msg("Block limit outputs do not match after first round\n");
|
||||
if (memcmp(counter1, counter2, sizeof(counter1)))
|
||||
ksft_exit_fail_msg("Block limit counters do not match after first round\n");
|
||||
|
||||
reference_chacha20_blocks(output1, key, counter1, BLOCKS);
|
||||
__arch_chacha20_blocks_nostack(output2, key, counter2, BLOCKS);
|
||||
if (memcmp(output1, output2, sizeof(output1)) || memcmp(counter1, counter2, sizeof(counter1)))
|
||||
return KSFT_FAIL;
|
||||
if (memcmp(output1, output2, sizeof(output1)))
|
||||
ksft_exit_fail_msg("Block limit outputs do not match after second round\n");
|
||||
if (memcmp(counter1, counter2, sizeof(counter1)))
|
||||
ksft_exit_fail_msg("Block limit counters do not match after second round\n");
|
||||
|
||||
ksft_test_result_pass("chacha: PASS\n");
|
||||
return KSFT_PASS;
|
||||
ksft_exit_pass();
|
||||
return 0;
|
||||
}
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <sched.h>
|
||||
#include <signal.h>
|
||||
#include <sys/auxv.h>
|
||||
#include <sys/mman.h>
|
||||
@ -40,6 +41,9 @@
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#define ksft_assert(condition) \
|
||||
do { if (!(condition)) ksft_exit_fail_msg("Assertion failed: %s\n", #condition); } while (0)
|
||||
|
||||
static struct {
|
||||
pthread_mutex_t lock;
|
||||
void **states;
|
||||
@ -111,26 +115,19 @@ static void vgetrandom_init(void)
|
||||
const char *version = versions[VDSO_VERSION];
|
||||
const char *name = names[VDSO_NAMES][6];
|
||||
unsigned long sysinfo_ehdr = getauxval(AT_SYSINFO_EHDR);
|
||||
size_t ret;
|
||||
ssize_t ret;
|
||||
|
||||
if (!sysinfo_ehdr) {
|
||||
printf("AT_SYSINFO_EHDR is not present!\n");
|
||||
exit(KSFT_SKIP);
|
||||
}
|
||||
if (!sysinfo_ehdr)
|
||||
ksft_exit_skip("AT_SYSINFO_EHDR is not present\n");
|
||||
vdso_init_from_sysinfo_ehdr(sysinfo_ehdr);
|
||||
vgrnd.fn = (__typeof__(vgrnd.fn))vdso_sym(version, name);
|
||||
if (!vgrnd.fn) {
|
||||
printf("%s is missing!\n", name);
|
||||
exit(KSFT_FAIL);
|
||||
}
|
||||
if (!vgrnd.fn)
|
||||
ksft_exit_skip("%s@%s symbol is missing from vDSO\n", name, version);
|
||||
ret = VDSO_CALL(vgrnd.fn, 5, NULL, 0, 0, &vgrnd.params, ~0UL);
|
||||
if (ret == -ENOSYS) {
|
||||
printf("unsupported architecture\n");
|
||||
exit(KSFT_SKIP);
|
||||
} else if (ret) {
|
||||
printf("failed to fetch vgetrandom params!\n");
|
||||
exit(KSFT_FAIL);
|
||||
}
|
||||
if (ret == -ENOSYS)
|
||||
ksft_exit_skip("CPU does not have runtime support\n");
|
||||
else if (ret)
|
||||
ksft_exit_fail_msg("Failed to fetch vgetrandom params: %zd\n", ret);
|
||||
}
|
||||
|
||||
static ssize_t vgetrandom(void *buf, size_t len, unsigned long flags)
|
||||
@ -139,10 +136,7 @@ static ssize_t vgetrandom(void *buf, size_t len, unsigned long flags)
|
||||
|
||||
if (!state) {
|
||||
state = vgetrandom_get_state();
|
||||
if (!state) {
|
||||
printf("vgetrandom_get_state failed!\n");
|
||||
exit(KSFT_FAIL);
|
||||
}
|
||||
ksft_assert(state);
|
||||
}
|
||||
return VDSO_CALL(vgrnd.fn, 5, buf, len, flags, state, vgrnd.params.size_of_opaque_state);
|
||||
}
|
||||
@ -154,7 +148,7 @@ static void *test_vdso_getrandom(void *ctx)
|
||||
for (size_t i = 0; i < TRIALS; ++i) {
|
||||
unsigned int val;
|
||||
ssize_t ret = vgetrandom(&val, sizeof(val), 0);
|
||||
assert(ret == sizeof(val));
|
||||
ksft_assert(ret == sizeof(val));
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@ -164,7 +158,7 @@ static void *test_libc_getrandom(void *ctx)
|
||||
for (size_t i = 0; i < TRIALS; ++i) {
|
||||
unsigned int val;
|
||||
ssize_t ret = getrandom(&val, sizeof(val), 0);
|
||||
assert(ret == sizeof(val));
|
||||
ksft_assert(ret == sizeof(val));
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@ -174,7 +168,7 @@ static void *test_syscall_getrandom(void *ctx)
|
||||
for (size_t i = 0; i < TRIALS; ++i) {
|
||||
unsigned int val;
|
||||
ssize_t ret = syscall(__NR_getrandom, &val, sizeof(val), 0);
|
||||
assert(ret == sizeof(val));
|
||||
ksft_assert(ret == sizeof(val));
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@ -209,7 +203,7 @@ static void bench_multi(void)
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &start);
|
||||
for (size_t i = 0; i < THREADS; ++i)
|
||||
assert(pthread_create(&threads[i], NULL, test_vdso_getrandom, NULL) == 0);
|
||||
ksft_assert(pthread_create(&threads[i], NULL, test_vdso_getrandom, NULL) == 0);
|
||||
for (size_t i = 0; i < THREADS; ++i)
|
||||
pthread_join(threads[i], NULL);
|
||||
clock_gettime(CLOCK_MONOTONIC, &end);
|
||||
@ -218,7 +212,7 @@ static void bench_multi(void)
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &start);
|
||||
for (size_t i = 0; i < THREADS; ++i)
|
||||
assert(pthread_create(&threads[i], NULL, test_libc_getrandom, NULL) == 0);
|
||||
ksft_assert(pthread_create(&threads[i], NULL, test_libc_getrandom, NULL) == 0);
|
||||
for (size_t i = 0; i < THREADS; ++i)
|
||||
pthread_join(threads[i], NULL);
|
||||
clock_gettime(CLOCK_MONOTONIC, &end);
|
||||
@ -227,7 +221,7 @@ static void bench_multi(void)
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &start);
|
||||
for (size_t i = 0; i < THREADS; ++i)
|
||||
assert(pthread_create(&threads[i], NULL, test_syscall_getrandom, NULL) == 0);
|
||||
ksft_assert(pthread_create(&threads[i], NULL, test_syscall_getrandom, NULL) == 0);
|
||||
for (size_t i = 0; i < THREADS; ++i)
|
||||
pthread_join(threads[i], NULL);
|
||||
clock_gettime(CLOCK_MONOTONIC, &end);
|
||||
@ -252,48 +246,46 @@ static void kselftest(void)
|
||||
|
||||
for (size_t i = 0; i < 1000; ++i) {
|
||||
ssize_t ret = vgetrandom(weird_size, sizeof(weird_size), 0);
|
||||
if (ret != sizeof(weird_size))
|
||||
exit(KSFT_FAIL);
|
||||
ksft_assert(ret == sizeof(weird_size));
|
||||
}
|
||||
|
||||
ksft_test_result_pass("getrandom: PASS\n");
|
||||
|
||||
unshare(CLONE_NEWUSER);
|
||||
assert(unshare(CLONE_NEWTIME) == 0);
|
||||
ksft_assert(unshare(CLONE_NEWTIME) == 0);
|
||||
child = fork();
|
||||
assert(child >= 0);
|
||||
ksft_assert(child >= 0);
|
||||
if (!child) {
|
||||
vgetrandom_init();
|
||||
child = getpid();
|
||||
assert(ptrace(PTRACE_TRACEME, 0, NULL, NULL) == 0);
|
||||
assert(kill(child, SIGSTOP) == 0);
|
||||
assert(vgetrandom(weird_size, sizeof(weird_size), 0) == sizeof(weird_size));
|
||||
ksft_assert(ptrace(PTRACE_TRACEME, 0, NULL, NULL) == 0);
|
||||
ksft_assert(kill(child, SIGSTOP) == 0);
|
||||
ksft_assert(vgetrandom(weird_size, sizeof(weird_size), 0) == sizeof(weird_size));
|
||||
_exit(0);
|
||||
}
|
||||
for (;;) {
|
||||
struct ptrace_syscall_info info = { 0 };
|
||||
int status, ret;
|
||||
assert(waitpid(child, &status, 0) >= 0);
|
||||
ksft_assert(waitpid(child, &status, 0) >= 0);
|
||||
if (WIFEXITED(status)) {
|
||||
if (WEXITSTATUS(status) != 0)
|
||||
exit(KSFT_FAIL);
|
||||
ksft_assert(WEXITSTATUS(status) == 0);
|
||||
break;
|
||||
}
|
||||
assert(WIFSTOPPED(status));
|
||||
ksft_assert(WIFSTOPPED(status));
|
||||
if (WSTOPSIG(status) == SIGSTOP)
|
||||
assert(ptrace(PTRACE_SETOPTIONS, child, 0, PTRACE_O_TRACESYSGOOD) == 0);
|
||||
ksft_assert(ptrace(PTRACE_SETOPTIONS, child, 0, PTRACE_O_TRACESYSGOOD) == 0);
|
||||
else if (WSTOPSIG(status) == (SIGTRAP | 0x80)) {
|
||||
assert(ptrace(PTRACE_GET_SYSCALL_INFO, child, sizeof(info), &info) > 0);
|
||||
ksft_assert(ptrace(PTRACE_GET_SYSCALL_INFO, child, sizeof(info), &info) > 0);
|
||||
if (info.op == PTRACE_SYSCALL_INFO_ENTRY && info.entry.nr == __NR_getrandom &&
|
||||
info.entry.args[0] == (uintptr_t)weird_size && info.entry.args[1] == sizeof(weird_size))
|
||||
exit(KSFT_FAIL);
|
||||
ksft_exit_fail_msg("vgetrandom passed buffer to syscall getrandom unexpectedly\n");
|
||||
}
|
||||
assert(ptrace(PTRACE_SYSCALL, child, 0, 0) == 0);
|
||||
ksft_assert(ptrace(PTRACE_SYSCALL, child, 0, 0) == 0);
|
||||
}
|
||||
|
||||
ksft_test_result_pass("getrandom timens: PASS\n");
|
||||
|
||||
exit(KSFT_PASS);
|
||||
ksft_exit_pass();
|
||||
}
|
||||
|
||||
static void usage(const char *argv0)
|
||||
|
18
tools/testing/selftests/vDSO/vgetrandom-chacha.S
Normal file
18
tools/testing/selftests/vDSO/vgetrandom-chacha.S
Normal file
@ -0,0 +1,18 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2024 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
*/
|
||||
|
||||
#define __ASSEMBLY__
|
||||
|
||||
#if defined(__aarch64__)
|
||||
#include "../../../../arch/arm64/kernel/vdso/vgetrandom-chacha.S"
|
||||
#elif defined(__loongarch__)
|
||||
#include "../../../../arch/loongarch/vdso/vgetrandom-chacha.S"
|
||||
#elif defined(__powerpc__) || defined(__powerpc64__)
|
||||
#include "../../../../arch/powerpc/kernel/vdso/vgetrandom-chacha.S"
|
||||
#elif defined(__s390x__)
|
||||
#include "../../../../arch/s390/kernel/vdso64/vgetrandom-chacha.S"
|
||||
#elif defined(__x86_64__)
|
||||
#include "../../../../arch/x86/entry/vdso/vgetrandom-chacha.S"
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user