tools/testing/selftests/signal/mangle_uc_sigmask.c

Source file repositories/reference/linux-study-clean/tools/testing/selftests/signal/mangle_uc_sigmask.c

File Facts

System
Linux kernel
Corpus path
tools/testing/selftests/signal/mangle_uc_sigmask.c
Extension
.c
Size
5506 bytes
Lines
185
Domain
Support Tooling And Documentation
Bucket
tools
Inferred role
Support Tooling And Documentation: implementation source
Status
source implementation candidate

Why This File Exists

Repository support layer: documentation, build tooling, samples, user-space helper tools, generated initramfs support, licenses, and validation utilities.

Dependency Surface

Detected Declarations

Annotated Snippet

// 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");

Annotation

Implementation Notes