From nobody Wed Jan 22 10:04:30 2025 Received: from smtpout.efficios.com (smtpout.efficios.com [158.69.130.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 53EE71F76AF for ; Tue, 21 Jan 2025 21:34:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=158.69.130.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737495257; cv=none; b=lwasRxgvxvZBysQXI09a3Ui57JMSjKGSOvMuF9Xd8z+eV5KLeGX7todTBaQ6a0FTASj1khGfhijJVkrxnhVrRO96konswjt2nP/nOVBV8D+MCkg7ad0fwl3K+eO+3siwSt2pHN/05ab2eT9Bvqz5lmLJvcNd/rk8JkvLyKa7uXk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737495257; c=relaxed/simple; bh=1iQxGU8KGK+COGYhwnHWdXoxFBDY49QlthvUPb4KkLQ=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=Z+JN9+AOjkM2jJ8hpbmCzD3d1DvCBBCwDc33UN4bBCXHndT9oNu2Hsrp/E8K065if6h2CgKV9W0HjTkXHoKk9fgR8NV1s6U/KRxIz/sKKicQPeZrhFUauXgECQK1IScwQZ3HlO2W0stG/sWXWh6x5J8Cr2HbI9yZ8D6NVY86MHA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=efficios.com; spf=pass smtp.mailfrom=efficios.com; dkim=pass (2048-bit key) header.d=efficios.com header.i=@efficios.com header.b=Mhif2Tzk; arc=none smtp.client-ip=158.69.130.18 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=efficios.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=efficios.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=efficios.com header.i=@efficios.com header.b="Mhif2Tzk" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=efficios.com; s=smtpout1; t=1737495248; bh=1iQxGU8KGK+COGYhwnHWdXoxFBDY49QlthvUPb4KkLQ=; h=From:To:Cc:Subject:Date:From; b=Mhif2TzkDT/WYLRZs9GOet/XtzNW7VkiEStf3/hX9kehFPtZrctHVTsql57b5GA/L 3oc8AsO2KpdS+EP3f1jAPUVLzcXkeQZfvn0YpF46HHQP17OPhYxAEmq+wwrsOitOgM lrAPftdM06hK39Y1VvVATzUz2QxgTW4jE8x54hHogsCXQfgYgbPrYiXlGkRfQi0dab o/fCV0TCbP74h+BQsQYA/AH/CGO9EZ/v8Uztb8V4O7DRm66KDhiKXPwZ4hssyFYE7y Kr/R0/xiLgKags4pIX8I0oYWYUQdrFrb+GBpAvisz0hYGlbkmOxdHlbEIV/ULoYyQt IUPcIfJ0SCJZg== Received: from laptop-mjeanson.internal.efficios.com (96-127-217-162.qc.cable.ebox.net [96.127.217.162]) by smtpout.efficios.com (Postfix) with ESMTPSA id 4Yd0p82SY4zt9J; Tue, 21 Jan 2025 16:34:08 -0500 (EST) From: Michael Jeanson To: linux-kernel@vger.kernel.org Cc: Michael Jeanson , Mathieu Desnoyers , Peter Zijlstra , Ingo Molnar , Shuah Khan Subject: [PATCH] selftests/rseq: add rseq syscall errors test Date: Tue, 21 Jan 2025 16:33:52 -0500 Message-ID: <20250121213402.1754762-1-mjeanson@efficios.com> X-Mailer: git-send-email 2.43.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This test adds coverage of expected errors during rseq registration and unregistration, it disables glibc integration and will thus always exercise the rseq syscall explictly. Signed-off-by: Michael Jeanson Reviewed-by: Mathieu Desnoyers Cc: Peter Zijlstra Cc: Ingo Molnar Cc: Shuah Khan --- tools/testing/selftests/rseq/.gitignore | 1 + tools/testing/selftests/rseq/Makefile | 9 +- tools/testing/selftests/rseq/rseq.c | 6 +- tools/testing/selftests/rseq/rseq.h | 5 + .../selftests/rseq/run_syscall_errors_test.sh | 5 + .../selftests/rseq/syscall_errors_test.c | 124 ++++++++++++++++++ 6 files changed, 145 insertions(+), 5 deletions(-) create mode 100755 tools/testing/selftests/rseq/run_syscall_errors_test.sh create mode 100644 tools/testing/selftests/rseq/syscall_errors_test.c diff --git a/tools/testing/selftests/rseq/.gitignore b/tools/testing/selfte= sts/rseq/.gitignore index 16496de5f6ce..0fda241fa62b 100644 --- a/tools/testing/selftests/rseq/.gitignore +++ b/tools/testing/selftests/rseq/.gitignore @@ -9,3 +9,4 @@ param_test_compare_twice param_test_mm_cid param_test_mm_cid_benchmark param_test_mm_cid_compare_twice +syscall_errors_test diff --git a/tools/testing/selftests/rseq/Makefile b/tools/testing/selftest= s/rseq/Makefile index 5a3432fceb58..0d0a5fae5954 100644 --- a/tools/testing/selftests/rseq/Makefile +++ b/tools/testing/selftests/rseq/Makefile @@ -16,11 +16,12 @@ OVERRIDE_TARGETS =3D 1 =20 TEST_GEN_PROGS =3D basic_test basic_percpu_ops_test basic_percpu_ops_mm_ci= d_test param_test \ param_test_benchmark param_test_compare_twice param_test_mm_cid \ - param_test_mm_cid_benchmark param_test_mm_cid_compare_twice + param_test_mm_cid_benchmark param_test_mm_cid_compare_twice \ + syscall_errors_test =20 TEST_GEN_PROGS_EXTENDED =3D librseq.so =20 -TEST_PROGS =3D run_param_test.sh +TEST_PROGS =3D run_param_test.sh run_syscall_errors_test.sh =20 TEST_FILES :=3D settings =20 @@ -54,3 +55,7 @@ $(OUTPUT)/param_test_mm_cid_benchmark: param_test.c $(TES= T_GEN_PROGS_EXTENDED) \ $(OUTPUT)/param_test_mm_cid_compare_twice: param_test.c $(TEST_GEN_PROGS_E= XTENDED) \ rseq.h rseq-*.h $(CC) $(CFLAGS) -DBUILDOPT_RSEQ_PERCPU_MM_CID -DRSEQ_COMPARE_TWICE $< $(L= DLIBS) -lrseq -o $@ + +$(OUTPUT)/syscall_errors_test: syscall_errors_test.c $(TEST_GEN_PROGS_EXTE= NDED) \ + rseq.h rseq-*.h + $(CC) $(CFLAGS) $< $(LDLIBS) -lrseq -o $@ diff --git a/tools/testing/selftests/rseq/rseq.c b/tools/testing/selftests/= rseq/rseq.c index 5b9772cdf265..4c06b8f61fe5 100644 --- a/tools/testing/selftests/rseq/rseq.c +++ b/tools/testing/selftests/rseq/rseq.c @@ -88,7 +88,7 @@ static int sys_getcpu(unsigned *cpu, unsigned *node) return syscall(__NR_getcpu, cpu, node, NULL); } =20 -int rseq_available(void) +bool rseq_available(void) { int rc; =20 @@ -97,9 +97,9 @@ int rseq_available(void) abort(); switch (errno) { case ENOSYS: - return 0; + return false; case EINVAL: - return 1; + return true; default: abort(); } diff --git a/tools/testing/selftests/rseq/rseq.h b/tools/testing/selftests/= rseq/rseq.h index 4e217b620e0c..7c3c018d2ba0 100644 --- a/tools/testing/selftests/rseq/rseq.h +++ b/tools/testing/selftests/rseq/rseq.h @@ -150,6 +150,11 @@ int32_t rseq_fallback_current_cpu(void); */ int32_t rseq_fallback_current_node(void); =20 +/* + * Returns true if rseq is supported. + */ +bool rseq_available(void); + /* * Values returned can be either the current CPU number, -1 (rseq is * uninitialized), or -2 (rseq initialization has failed). diff --git a/tools/testing/selftests/rseq/run_syscall_errors_test.sh b/tool= s/testing/selftests/rseq/run_syscall_errors_test.sh new file mode 100755 index 000000000000..9272246b39f2 --- /dev/null +++ b/tools/testing/selftests/rseq/run_syscall_errors_test.sh @@ -0,0 +1,5 @@ +#!/bin/bash +# SPDX-License-Identifier: MIT +# SPDX-FileCopyrightText: 2024 Michael Jeanson + +GLIBC_TUNABLES=3D"${GLIBC_TUNABLES:-}:glibc.pthread.rseq=3D0" ./syscall_er= rors_test diff --git a/tools/testing/selftests/rseq/syscall_errors_test.c b/tools/tes= ting/selftests/rseq/syscall_errors_test.c new file mode 100644 index 000000000000..a5d9e1f8a2dc --- /dev/null +++ b/tools/testing/selftests/rseq/syscall_errors_test.c @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: MIT +// SPDX-FileCopyrightText: 2024 Michael Jeanson + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include + +#include "rseq.h" + +static int sys_rseq(void *rseq_abi, uint32_t rseq_len, + int flags, uint32_t sig) +{ + return syscall(__NR_rseq, rseq_abi, rseq_len, flags, sig); +} + +/* + * Check the value of errno on some expected failures of the rseq syscall. + */ + +int main(void) +{ + struct rseq_abi *global_rseq =3D rseq_get_abi(); + int ret; + int errno_copy; + + if (!rseq_available()) { + fprintf(stderr, "rseq syscall unavailable"); + goto error; + } + + /* The current thread is NOT registered. */ + + /* EINVAL */ + errno =3D 0; + ret =3D sys_rseq(global_rseq, 32, -1, RSEQ_SIG); + errno_copy =3D errno; + fprintf(stderr, "Registration with invalid flag fails with errno set to E= INVAL (ret =3D %d, errno =3D %s)\n", ret, strerrorname_np(errno_copy)); + if (ret =3D=3D 0 || errno_copy !=3D EINVAL) + goto error; + + errno =3D 0; + ret =3D sys_rseq((char *) global_rseq + 1, 32, 0, RSEQ_SIG); + errno_copy =3D errno; + fprintf(stderr, "Registration with unaligned rseq_abi fails with errno se= t to EINVAL (ret =3D %d, errno =3D %s)\n", ret, strerrorname_np(errno_copy)= ); + if (ret =3D=3D 0 || errno_copy !=3D EINVAL) + goto error; + + errno =3D 0; + ret =3D sys_rseq(global_rseq, 31, 0, RSEQ_SIG); + errno_copy =3D errno; + fprintf(stderr, "Registration with invalid size fails with errno set to E= INVAL (ret =3D %d, errno =3D %s)\n", ret, strerrorname_np(errno_copy)); + if (ret =3D=3D 0 || errno_copy !=3D EINVAL) + goto error; + + +#if defined(__LP64__) && (!defined(__s390__) && !defined(__s390x__)) + /* + * We haven't found a reliable way to find an invalid address when + * running a 32bit userspace on a 64bit kernel, so only run this test + * on 64bit builds for the moment. + * + * Also exclude architectures that select + * CONFIG_ALTERNATE_USER_ADDRESS_SPACE where the kernel and userspace + * have their own address space and this failure can't happen. + */ + + /* EFAULT */ + errno =3D 0; + ret =3D sys_rseq((void *) -4096UL, 32, 0, RSEQ_SIG); + errno_copy =3D errno; + fprintf(stderr, "Registration with invalid address fails with errno set t= o EFAULT (ret =3D %d, errno =3D %s)\n", ret, strerrorname_np(errno_copy)); + if (ret =3D=3D 0 || errno_copy !=3D EFAULT) + goto error; +#endif + + errno =3D 0; + ret =3D sys_rseq(global_rseq, 32, 0, RSEQ_SIG); + errno_copy =3D errno; + fprintf(stderr, "Registration succeeds for the current thread (ret =3D %d= , errno =3D %s)\n", ret, strerrorname_np(errno_copy)); + if (ret !=3D 0 && errno !=3D 0) + goto error; + + /* The current thread is registered. */ + + /* EBUSY */ + errno =3D 0; + ret =3D sys_rseq(global_rseq, 32, 0, RSEQ_SIG); + errno_copy =3D errno; + fprintf(stderr, "Double registration fails with errno set to EBUSY (ret = =3D %d, errno =3D %s)\n", ret, strerrorname_np(errno_copy)); + if (ret =3D=3D 0 || errno_copy !=3D EBUSY) + goto error; + + /* EPERM */ + errno =3D 0; + ret =3D sys_rseq(global_rseq, 32, RSEQ_ABI_FLAG_UNREGISTER, RSEQ_SIG + 1); + errno_copy =3D errno; + fprintf(stderr, "Unregistration with wrong RSEQ_SIG fails with errno to E= PERM (ret =3D %d, errno =3D %s)\n", ret, strerrorname_np(errno_copy)); + if (ret =3D=3D 0 || errno_copy !=3D EPERM) + goto error; + + errno =3D 0; + ret =3D sys_rseq(global_rseq, 32, RSEQ_ABI_FLAG_UNREGISTER, RSEQ_SIG); + errno_copy =3D errno; + fprintf(stderr, "Unregistration succeeds for the current thread (ret =3D = %d, errno =3D %s)\n", ret, strerrorname_np(errno_copy)); + if (ret !=3D 0) + goto error; + + errno =3D 0; + ret =3D sys_rseq(global_rseq, 32, RSEQ_ABI_FLAG_UNREGISTER, RSEQ_SIG); + errno_copy =3D errno; + fprintf(stderr, "Double unregistration fails with errno set to EINVAL (re= t =3D %d, errno =3D %s)\n", ret, strerrorname_np(errno_copy)); + if (ret =3D=3D 0 || errno_copy !=3D EINVAL) + goto error; + + return 0; +error: + return -1; +} --=20 2.43.0