linux/tools/testing/selftests/powerpc/signal/sig_sc_double_restart.c
<<
>>
Prefs
   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}
 175