mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 14:53:58 -04:00
This follow-up patch completes centralization of kselftest.h and ksefltest_harness.h includes in remaining seltests files, replacing all relative paths with a non-relative paths using shared -I include path in lib.mk Tested with gcc-13.3 and clang-18.1, and cross-compiled successfully on riscv, arm64, x86_64 and powerpc arch. [reddybalavignesh9979@gmail.com: add selftests include path for kselftest.h] Link: https://lkml.kernel.org/r/20251017090201.317521-1-reddybalavignesh9979@gmail.com Link: https://lkml.kernel.org/r/20251016104409.68985-1-reddybalavignesh9979@gmail.com Signed-off-by: Bala-Vignesh-Reddy <reddybalavignesh9979@gmail.com> Suggested-by: Andrew Morton <akpm@linux-foundation.org> Link: https://lore.kernel.org/lkml/20250820143954.33d95635e504e94df01930d0@linux-foundation.org/ Reviewed-by: Wei Yang <richard.weiyang@gmail.com> Cc: David Hildenbrand <david@redhat.com> Cc: David S. Miller <davem@davemloft.net> Cc: Eric Dumazet <edumazet@google.com> Cc: Günther Noack <gnoack@google.com> Cc: Jakub Kacinski <kuba@kernel.org> Cc: Liam Howlett <liam.howlett@oracle.com> Cc: Lorenzo Stoakes <lorenzo.stoakes@oracle.com> Cc: Michal Hocko <mhocko@suse.com> Cc: Mickael Salaun <mic@digikod.net> Cc: Ming Lei <ming.lei@redhat.com> Cc: Paolo Abeni <pabeni@redhat.com> Cc: Shuah Khan <shuah@kernel.org> Cc: Simon Horman <horms@kernel.org> Cc: Suren Baghdasaryan <surenb@google.com> Cc: Vlastimil Babka <vbabka@suse.cz> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
185 lines
5.4 KiB
C
185 lines
5.4 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Copyright (C) 2024 ARM Ltd.
|
|
*
|
|
* Author: Dev Jain <dev.jain@arm.com>
|
|
*
|
|
* Test describing a clear distinction between signal states - delivered and
|
|
* blocked, and their relation with ucontext.
|
|
*
|
|
* A process can request blocking of a signal by masking it into its set of
|
|
* blocked signals; such a signal, when sent to the process by the kernel,
|
|
* will get blocked by the process and it may later unblock it and take an
|
|
* action. At that point, the signal will be delivered.
|
|
*
|
|
* We test the following functionalities of the kernel:
|
|
*
|
|
* ucontext_t describes the interrupted context of the thread; this implies
|
|
* that, in case of registering a handler and catching the corresponding
|
|
* signal, that state is before what was jumping into the handler.
|
|
*
|
|
* The thread's mask of blocked signals can be permanently changed, i.e, not
|
|
* just during the execution of the handler, by mangling with uc_sigmask
|
|
* from inside the handler.
|
|
*
|
|
* Assume that we block the set of signals, S1, by sigaction(), and say, the
|
|
* signal for which the handler was installed, is S2. When S2 is sent to the
|
|
* program, it will be considered "delivered", since we will act on the
|
|
* signal and jump to the handler. Any instances of S1 or S2 raised, while the
|
|
* program is executing inside the handler, will be blocked; they will be
|
|
* delivered immediately upon termination of the handler.
|
|
*
|
|
* For standard signals (also see real-time signals in the man page), multiple
|
|
* blocked instances of the same signal are not queued; such a signal will
|
|
* be delivered just once.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <signal.h>
|
|
#include <ucontext.h>
|
|
|
|
#include "kselftest.h"
|
|
|
|
void handler_verify_ucontext(int signo, siginfo_t *info, void *uc)
|
|
{
|
|
int ret;
|
|
|
|
/* Kernel dumps ucontext with USR2 blocked */
|
|
ret = sigismember(&(((ucontext_t *)uc)->uc_sigmask), SIGUSR2);
|
|
ksft_test_result(ret == 1, "USR2 blocked in ucontext\n");
|
|
|
|
/*
|
|
* USR2 is blocked; can be delivered neither here, nor after
|
|
* exit from handler
|
|
*/
|
|
if (raise(SIGUSR2))
|
|
ksft_exit_fail_perror("raise");
|
|
}
|
|
|
|
void handler_segv(int signo, siginfo_t *info, void *uc)
|
|
{
|
|
/*
|
|
* Three cases possible:
|
|
* 1. Program already terminated due to segmentation fault.
|
|
* 2. SEGV was blocked even after returning from handler_usr.
|
|
* 3. SEGV was delivered on returning from handler_usr.
|
|
* The last option must happen.
|
|
*/
|
|
ksft_test_result_pass("SEGV delivered\n");
|
|
}
|
|
|
|
static int cnt;
|
|
|
|
void handler_usr(int signo, siginfo_t *info, void *uc)
|
|
{
|
|
int ret;
|
|
|
|
/*
|
|
* Break out of infinite recursion caused by raise(SIGUSR1) invoked
|
|
* from inside the handler
|
|
*/
|
|
++cnt;
|
|
if (cnt > 1)
|
|
return;
|
|
|
|
/* SEGV blocked during handler execution, delivered on return */
|
|
if (raise(SIGSEGV))
|
|
ksft_exit_fail_perror("raise");
|
|
|
|
ksft_print_msg("SEGV bypassed successfully\n");
|
|
|
|
/*
|
|
* Signal responsible for handler invocation is blocked by default;
|
|
* delivered on return, leading to recursion
|
|
*/
|
|
if (raise(SIGUSR1))
|
|
ksft_exit_fail_perror("raise");
|
|
|
|
ksft_test_result(cnt == 1,
|
|
"USR1 is blocked, cannot invoke handler right now\n");
|
|
|
|
/* Raise USR1 again; only one instance must be delivered upon exit */
|
|
if (raise(SIGUSR1))
|
|
ksft_exit_fail_perror("raise");
|
|
|
|
/* SEGV has been blocked in sa_mask, but ucontext is empty */
|
|
ret = sigismember(&(((ucontext_t *)uc)->uc_sigmask), SIGSEGV);
|
|
ksft_test_result(ret == 0, "SEGV not blocked in ucontext\n");
|
|
|
|
/* USR1 has been blocked, but ucontext is empty */
|
|
ret = sigismember(&(((ucontext_t *)uc)->uc_sigmask), SIGUSR1);
|
|
ksft_test_result(ret == 0, "USR1 not blocked in ucontext\n");
|
|
|
|
/*
|
|
* Mangle ucontext; this will be copied back into ¤t->blocked
|
|
* on return from the handler.
|
|
*/
|
|
if (sigaddset(&((ucontext_t *)uc)->uc_sigmask, SIGUSR2))
|
|
ksft_exit_fail_perror("sigaddset");
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
struct sigaction act, act2;
|
|
sigset_t set, oldset;
|
|
|
|
ksft_print_header();
|
|
ksft_set_plan(7);
|
|
|
|
act.sa_flags = SA_SIGINFO;
|
|
act.sa_sigaction = &handler_usr;
|
|
|
|
/* Add SEGV to blocked mask */
|
|
if (sigemptyset(&act.sa_mask) || sigaddset(&act.sa_mask, SIGSEGV)
|
|
|| (sigismember(&act.sa_mask, SIGSEGV) != 1))
|
|
ksft_exit_fail_msg("Cannot add SEGV to blocked mask\n");
|
|
|
|
if (sigaction(SIGUSR1, &act, NULL))
|
|
ksft_exit_fail_perror("Cannot install handler");
|
|
|
|
act2.sa_flags = SA_SIGINFO;
|
|
act2.sa_sigaction = &handler_segv;
|
|
|
|
if (sigaction(SIGSEGV, &act2, NULL))
|
|
ksft_exit_fail_perror("Cannot install handler");
|
|
|
|
/* Invoke handler */
|
|
if (raise(SIGUSR1))
|
|
ksft_exit_fail_perror("raise");
|
|
|
|
/* USR1 must not be queued */
|
|
ksft_test_result(cnt == 2, "handler invoked only twice\n");
|
|
|
|
/* Mangled ucontext implies USR2 is blocked for current thread */
|
|
if (raise(SIGUSR2))
|
|
ksft_exit_fail_perror("raise");
|
|
|
|
ksft_print_msg("USR2 bypassed successfully\n");
|
|
|
|
act.sa_sigaction = &handler_verify_ucontext;
|
|
if (sigaction(SIGUSR1, &act, NULL))
|
|
ksft_exit_fail_perror("Cannot install handler");
|
|
|
|
if (raise(SIGUSR1))
|
|
ksft_exit_fail_perror("raise");
|
|
|
|
/*
|
|
* Raising USR2 in handler_verify_ucontext is redundant since it
|
|
* is blocked
|
|
*/
|
|
ksft_print_msg("USR2 still blocked on return from handler\n");
|
|
|
|
/* Confirm USR2 blockage by sigprocmask() too */
|
|
if (sigemptyset(&set))
|
|
ksft_exit_fail_perror("sigemptyset");
|
|
|
|
if (sigprocmask(SIG_BLOCK, &set, &oldset))
|
|
ksft_exit_fail_perror("sigprocmask");
|
|
|
|
ksft_test_result(sigismember(&oldset, SIGUSR2) == 1,
|
|
"USR2 present in ¤t->blocked\n");
|
|
|
|
ksft_finished();
|
|
}
|