cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sig_sc_double_restart.c (3942B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Test that a syscall does not get restarted twice, handled by trap_norestart()
      4 *
      5 * Based on Al's description, and a test for the bug fixed in this commit:
      6 *
      7 * commit 9a81c16b527528ad307843be5571111aa8d35a80
      8 * Author: Al Viro <viro@zeniv.linux.org.uk>
      9 * Date:   Mon Sep 20 21:48:57 2010 +0100
     10 *
     11 *  powerpc: fix double syscall restarts
     12 *
     13 *  Make sigreturn zero regs->trap, make do_signal() do the same on all
     14 *  paths.  As it is, signal interrupting e.g. read() from fd 512 (==
     15 *  ERESTARTSYS) with another signal getting unblocked when the first
     16 *  handler finishes will lead to restart one insn earlier than it ought
     17 *  to.  Same for multiple signals with in-kernel handlers interrupting
     18 *  that sucker at the same time.  Same for multiple signals of any kind
     19 *  interrupting that sucker on 64bit...
     20 */
     21#define _GNU_SOURCE
     22#include <sys/types.h>
     23#include <sys/wait.h>
     24#include <sys/syscall.h>
     25#include <unistd.h>
     26#include <signal.h>
     27#include <errno.h>
     28#include <stdlib.h>
     29#include <stdio.h>
     30#include <string.h>
     31
     32#include "utils.h"
     33
     34static void SIGUSR1_handler(int sig)
     35{
     36	kill(getpid(), SIGUSR2);
     37	/*
     38	 * SIGUSR2 is blocked until the handler exits, at which point it will
     39	 * be raised again and think there is a restart to be done because the
     40	 * pending restarted syscall has 512 (ERESTARTSYS) in r3. The second
     41	 * restart will retreat NIP another 4 bytes to fail case branch.
     42	 */
     43}
     44
     45static void SIGUSR2_handler(int sig)
     46{
     47}
     48
     49static ssize_t raw_read(int fd, void *buf, size_t count)
     50{
     51	register long nr asm("r0") = __NR_read;
     52	register long _fd asm("r3") = fd;
     53	register void *_buf asm("r4") = buf;
     54	register size_t _count asm("r5") = count;
     55
     56	asm volatile(
     57"		b	0f		\n"
     58"		b	1f		\n"
     59"	0:	sc	0		\n"
     60"		bns	2f		\n"
     61"		neg	%0,%0		\n"
     62"		b	2f		\n"
     63"	1:				\n"
     64"		li	%0,%4		\n"
     65"	2:				\n"
     66		: "+r"(_fd), "+r"(nr), "+r"(_buf), "+r"(_count)
     67		: "i"(-ENOANO)
     68		: "memory", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "ctr", "cr0");
     69
     70	if (_fd < 0) {
     71		errno = -_fd;
     72		_fd = -1;
     73	}
     74
     75	return _fd;
     76}
     77
     78#define DATA "test 123"
     79#define DLEN (strlen(DATA)+1)
     80
     81int test_restart(void)
     82{
     83	int pipefd[2];
     84	pid_t pid;
     85	char buf[512];
     86
     87	if (pipe(pipefd) == -1) {
     88		perror("pipe");
     89		exit(EXIT_FAILURE);
     90	}
     91
     92	pid = fork();
     93	if (pid == -1) {
     94		perror("fork");
     95		exit(EXIT_FAILURE);
     96	}
     97
     98	if (pid == 0) { /* Child reads from pipe */
     99		struct sigaction act;
    100		int fd;
    101
    102		memset(&act, 0, sizeof(act));
    103		sigaddset(&act.sa_mask, SIGUSR2);
    104		act.sa_handler = SIGUSR1_handler;
    105		act.sa_flags = SA_RESTART;
    106		if (sigaction(SIGUSR1, &act, NULL) == -1) {
    107			perror("sigaction");
    108			exit(EXIT_FAILURE);
    109		}
    110
    111		memset(&act, 0, sizeof(act));
    112		act.sa_handler = SIGUSR2_handler;
    113		act.sa_flags = SA_RESTART;
    114		if (sigaction(SIGUSR2, &act, NULL) == -1) {
    115			perror("sigaction");
    116			exit(EXIT_FAILURE);
    117		}
    118
    119		/* Let's get ERESTARTSYS into r3 */
    120		while ((fd = dup(pipefd[0])) != 512) {
    121			if (fd == -1) {
    122				perror("dup");
    123				exit(EXIT_FAILURE);
    124			}
    125		}
    126
    127		if (raw_read(fd, buf, 512) == -1) {
    128			if (errno == ENOANO) {
    129				fprintf(stderr, "Double restart moved restart before sc instruction.\n");
    130				_exit(EXIT_FAILURE);
    131			}
    132			perror("read");
    133			exit(EXIT_FAILURE);
    134		}
    135
    136		if (strncmp(buf, DATA, DLEN)) {
    137			fprintf(stderr, "bad test string %s\n", buf);
    138			exit(EXIT_FAILURE);
    139		}
    140
    141		return 0;
    142
    143	} else {
    144		int wstatus;
    145
    146		usleep(100000);		/* Hack to get reader waiting */
    147		kill(pid, SIGUSR1);
    148		usleep(100000);
    149		if (write(pipefd[1], DATA, DLEN) != DLEN) {
    150			perror("write");
    151			exit(EXIT_FAILURE);
    152		}
    153		close(pipefd[0]);
    154		close(pipefd[1]);
    155		if (wait(&wstatus) == -1) {
    156			perror("wait");
    157			exit(EXIT_FAILURE);
    158		}
    159		if (!WIFEXITED(wstatus)) {
    160			fprintf(stderr, "child exited abnormally\n");
    161			exit(EXIT_FAILURE);
    162		}
    163
    164		FAIL_IF(WEXITSTATUS(wstatus) != EXIT_SUCCESS);
    165
    166		return 0;
    167	}
    168}
    169
    170int main(void)
    171{
    172	test_harness_set_timeout(10);
    173	return test_harness(test_restart, "sig sys restart");
    174}