1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved. 4f08c3bdfSopenharmony_ci * Copyright (c) 2019 SUSE LLC 5f08c3bdfSopenharmony_ci * 6f08c3bdfSopenharmony_ci * Author: Saji Kumar.V.R <saji.kumar@wipro.com> 7f08c3bdfSopenharmony_ci * Ported to new library: Jorik Cronenberg <jcronenberg@suse.de> 8f08c3bdfSopenharmony_ci * 9f08c3bdfSopenharmony_ci * Test the functionality of ptrace() for PTRACE_TRACEME in combination with 10f08c3bdfSopenharmony_ci * PTRACE_KILL and PTRACE_CONT requests. 11f08c3bdfSopenharmony_ci * Forked child does ptrace(PTRACE_TRACEME, ...). 12f08c3bdfSopenharmony_ci * Then a signal is delivered to the child and verified that parent 13f08c3bdfSopenharmony_ci * is notified via wait(). 14f08c3bdfSopenharmony_ci * Afterwards parent does ptrace(PTRACE_KILL, ..)/ptrace(PTRACE_CONT, ..) 15f08c3bdfSopenharmony_ci * and then parent does wait() for child to finish. 16f08c3bdfSopenharmony_ci * Test passes if child exits with SIGKILL for PTRACE_KILL. 17f08c3bdfSopenharmony_ci * Test passes if child exits normally for PTRACE_CONT. 18f08c3bdfSopenharmony_ci * 19f08c3bdfSopenharmony_ci * Testing two cases for each: 20f08c3bdfSopenharmony_ci * 1) child ignore SIGUSR2 signal 21f08c3bdfSopenharmony_ci * 2) using a signal handler for child for SIGUSR2 22f08c3bdfSopenharmony_ci * In both cases, child should stop & notify parent on reception of SIGUSR2. 23f08c3bdfSopenharmony_ci */ 24f08c3bdfSopenharmony_ci 25f08c3bdfSopenharmony_ci#include <stdlib.h> 26f08c3bdfSopenharmony_ci#include <errno.h> 27f08c3bdfSopenharmony_ci#include <signal.h> 28f08c3bdfSopenharmony_ci#include <sys/wait.h> 29f08c3bdfSopenharmony_ci#include <config.h> 30f08c3bdfSopenharmony_ci#include "ptrace.h" 31f08c3bdfSopenharmony_ci#include "tst_test.h" 32f08c3bdfSopenharmony_ci 33f08c3bdfSopenharmony_cistatic struct tcase { 34f08c3bdfSopenharmony_ci int handler; 35f08c3bdfSopenharmony_ci int request; 36f08c3bdfSopenharmony_ci int exp_wifexited; 37f08c3bdfSopenharmony_ci int exp_wtermsig; 38f08c3bdfSopenharmony_ci char *message; 39f08c3bdfSopenharmony_ci} tcases[] = { 40f08c3bdfSopenharmony_ci {0, PTRACE_KILL, 0, 9, "Testing PTRACE_KILL without child handler"}, 41f08c3bdfSopenharmony_ci {1, PTRACE_KILL, 0, 9, "Testing PTRACE_KILL with child handler"}, 42f08c3bdfSopenharmony_ci {0, PTRACE_CONT, 1, 0, "Testing PTRACE_CONT without child handler"}, 43f08c3bdfSopenharmony_ci {1, PTRACE_CONT, 1, 0, "Testing PTRACE_CONT with child handler"}, 44f08c3bdfSopenharmony_ci}; 45f08c3bdfSopenharmony_ci 46f08c3bdfSopenharmony_cistatic volatile int got_signal; 47f08c3bdfSopenharmony_ci 48f08c3bdfSopenharmony_cistatic void child_handler(int sig LTP_ATTRIBUTE_UNUSED) 49f08c3bdfSopenharmony_ci{ 50f08c3bdfSopenharmony_ci SAFE_KILL(getppid(), SIGUSR2); 51f08c3bdfSopenharmony_ci} 52f08c3bdfSopenharmony_ci 53f08c3bdfSopenharmony_cistatic void parent_handler(int sig LTP_ATTRIBUTE_UNUSED) 54f08c3bdfSopenharmony_ci{ 55f08c3bdfSopenharmony_ci got_signal = 1; 56f08c3bdfSopenharmony_ci} 57f08c3bdfSopenharmony_ci 58f08c3bdfSopenharmony_cistatic void do_child(unsigned int i) 59f08c3bdfSopenharmony_ci{ 60f08c3bdfSopenharmony_ci struct sigaction child_act; 61f08c3bdfSopenharmony_ci 62f08c3bdfSopenharmony_ci if (i == 0) 63f08c3bdfSopenharmony_ci child_act.sa_handler = SIG_IGN; 64f08c3bdfSopenharmony_ci else 65f08c3bdfSopenharmony_ci child_act.sa_handler = child_handler; 66f08c3bdfSopenharmony_ci 67f08c3bdfSopenharmony_ci child_act.sa_flags = SA_RESTART; 68f08c3bdfSopenharmony_ci sigemptyset(&child_act.sa_mask); 69f08c3bdfSopenharmony_ci 70f08c3bdfSopenharmony_ci SAFE_SIGACTION(SIGUSR2, &child_act, NULL); 71f08c3bdfSopenharmony_ci 72f08c3bdfSopenharmony_ci if ((ptrace(PTRACE_TRACEME, 0, 0, 0)) == -1) { 73f08c3bdfSopenharmony_ci tst_res(TWARN, "ptrace() failed in child"); 74f08c3bdfSopenharmony_ci exit(1); 75f08c3bdfSopenharmony_ci } 76f08c3bdfSopenharmony_ci SAFE_KILL(getpid(), SIGUSR2); 77f08c3bdfSopenharmony_ci exit(1); 78f08c3bdfSopenharmony_ci} 79f08c3bdfSopenharmony_ci 80f08c3bdfSopenharmony_cistatic void run(unsigned int i) 81f08c3bdfSopenharmony_ci{ 82f08c3bdfSopenharmony_ci struct tcase *tc = &tcases[i]; 83f08c3bdfSopenharmony_ci pid_t child_pid; 84f08c3bdfSopenharmony_ci int status; 85f08c3bdfSopenharmony_ci struct sigaction parent_act; 86f08c3bdfSopenharmony_ci 87f08c3bdfSopenharmony_ci got_signal = 0; 88f08c3bdfSopenharmony_ci 89f08c3bdfSopenharmony_ci tst_res(TINFO, "%s", tc->message); 90f08c3bdfSopenharmony_ci 91f08c3bdfSopenharmony_ci if (tc->handler == 1) { 92f08c3bdfSopenharmony_ci parent_act.sa_handler = parent_handler; 93f08c3bdfSopenharmony_ci parent_act.sa_flags = SA_RESTART; 94f08c3bdfSopenharmony_ci sigemptyset(&parent_act.sa_mask); 95f08c3bdfSopenharmony_ci SAFE_SIGACTION(SIGUSR2, &parent_act, NULL); 96f08c3bdfSopenharmony_ci } 97f08c3bdfSopenharmony_ci 98f08c3bdfSopenharmony_ci child_pid = SAFE_FORK(); 99f08c3bdfSopenharmony_ci 100f08c3bdfSopenharmony_ci if (!child_pid) 101f08c3bdfSopenharmony_ci do_child(tc->handler); 102f08c3bdfSopenharmony_ci 103f08c3bdfSopenharmony_ci SAFE_WAITPID(child_pid, &status, 0); 104f08c3bdfSopenharmony_ci 105f08c3bdfSopenharmony_ci if (((WIFEXITED(status)) && (WEXITSTATUS(status))) 106f08c3bdfSopenharmony_ci || (got_signal == 1)) 107f08c3bdfSopenharmony_ci tst_res(TFAIL, "Test Failed"); 108f08c3bdfSopenharmony_ci else if ((ptrace(tc->request, child_pid, 0, 0)) == -1) 109f08c3bdfSopenharmony_ci tst_res(TFAIL | TERRNO, "ptrace(%i, %i, 0, 0) failed", 110f08c3bdfSopenharmony_ci tc->request, child_pid); 111f08c3bdfSopenharmony_ci 112f08c3bdfSopenharmony_ci SAFE_WAITPID(child_pid, &status, 0); 113f08c3bdfSopenharmony_ci 114f08c3bdfSopenharmony_ci if ((tc->request == PTRACE_CONT && 115f08c3bdfSopenharmony_ci WIFEXITED(status) && WEXITSTATUS(status) == tc->exp_wifexited) || 116f08c3bdfSopenharmony_ci (tc->request == PTRACE_KILL && 117f08c3bdfSopenharmony_ci WIFSIGNALED(status) && WTERMSIG(status) == tc->exp_wtermsig)) { 118f08c3bdfSopenharmony_ci tst_res(TPASS, "Child %s as expected", tst_strstatus(status)); 119f08c3bdfSopenharmony_ci } else { 120f08c3bdfSopenharmony_ci tst_res(TFAIL, "Child %s unexpectedly", tst_strstatus(status)); 121f08c3bdfSopenharmony_ci } 122f08c3bdfSopenharmony_ci 123f08c3bdfSopenharmony_ci} 124f08c3bdfSopenharmony_ci 125f08c3bdfSopenharmony_cistatic struct tst_test test = { 126f08c3bdfSopenharmony_ci .test = run, 127f08c3bdfSopenharmony_ci .tcnt = ARRAY_SIZE(tcases), 128f08c3bdfSopenharmony_ci .forks_child = 1, 129f08c3bdfSopenharmony_ci}; 130