brintos

brintos / linux-shallow public Read only

0
0
Text · 6.4 KiB · 5bcd1c7 Raw
272 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Copyright (c) 2018 Dmitry V. Levin <ldv@altlinux.org>4 * All rights reserved.5 *6 * Check whether PTRACE_GET_SYSCALL_INFO semantics implemented in the kernel7 * matches userspace expectations.8 */9 10#include "../kselftest_harness.h"11#include <err.h>12#include <signal.h>13#include <asm/unistd.h>14#include "linux/ptrace.h"15 16static int17kill_tracee(pid_t pid)18{19	if (!pid)20		return 0;21 22	int saved_errno = errno;23 24	int rc = kill(pid, SIGKILL);25 26	errno = saved_errno;27	return rc;28}29 30static long31sys_ptrace(int request, pid_t pid, unsigned long addr, unsigned long data)32{33	return syscall(__NR_ptrace, request, pid, addr, data);34}35 36#define LOG_KILL_TRACEE(fmt, ...)				\37	do {							\38		kill_tracee(pid);				\39		TH_LOG("wait #%d: " fmt,			\40		       ptrace_stop, ##__VA_ARGS__);		\41	} while (0)42 43TEST(get_syscall_info)44{45	static const unsigned long args[][7] = {46		/* a sequence of architecture-agnostic syscalls */47		{48			__NR_chdir,49			(unsigned long) "",50			0xbad1fed1,51			0xbad2fed2,52			0xbad3fed3,53			0xbad4fed4,54			0xbad5fed555		},56		{57			__NR_gettid,58			0xcaf0bea0,59			0xcaf1bea1,60			0xcaf2bea2,61			0xcaf3bea3,62			0xcaf4bea4,63			0xcaf5bea564		},65		{66			__NR_exit_group,67			0,68			0xfac1c0d1,69			0xfac2c0d2,70			0xfac3c0d3,71			0xfac4c0d4,72			0xfac5c0d573		}74	};75	const unsigned long *exp_args;76 77	pid_t pid = fork();78 79	ASSERT_LE(0, pid) {80		TH_LOG("fork: %m");81	}82 83	if (pid == 0) {84		/* get the pid before PTRACE_TRACEME */85		pid = getpid();86		ASSERT_EQ(0, sys_ptrace(PTRACE_TRACEME, 0, 0, 0)) {87			TH_LOG("PTRACE_TRACEME: %m");88		}89		ASSERT_EQ(0, kill(pid, SIGSTOP)) {90			/* cannot happen */91			TH_LOG("kill SIGSTOP: %m");92		}93		for (unsigned int i = 0; i < ARRAY_SIZE(args); ++i) {94			syscall(args[i][0],95				args[i][1], args[i][2], args[i][3],96				args[i][4], args[i][5], args[i][6]);97		}98		/* unreachable */99		_exit(1);100	}101 102	const struct {103		unsigned int is_error;104		int rval;105	} *exp_param, exit_param[] = {106		{ 1, -ENOENT },	/* chdir */107		{ 0, pid }	/* gettid */108	};109 110	unsigned int ptrace_stop;111 112	for (ptrace_stop = 0; ; ++ptrace_stop) {113		struct ptrace_syscall_info info = {114			.op = 0xff	/* invalid PTRACE_SYSCALL_INFO_* op */115		};116		const size_t size = sizeof(info);117		const int expected_none_size =118			(void *) &info.entry - (void *) &info;119		const int expected_entry_size =120			(void *) &info.entry.args[6] - (void *) &info;121		const int expected_exit_size =122			(void *) (&info.exit.is_error + 1) -123			(void *) &info;124		int status;125		long rc;126 127		ASSERT_EQ(pid, wait(&status)) {128			/* cannot happen */129			LOG_KILL_TRACEE("wait: %m");130		}131		if (WIFEXITED(status)) {132			pid = 0;	/* the tracee is no more */133			ASSERT_EQ(0, WEXITSTATUS(status));134			break;135		}136		ASSERT_FALSE(WIFSIGNALED(status)) {137			pid = 0;	/* the tracee is no more */138			LOG_KILL_TRACEE("unexpected signal %u",139					WTERMSIG(status));140		}141		ASSERT_TRUE(WIFSTOPPED(status)) {142			/* cannot happen */143			LOG_KILL_TRACEE("unexpected wait status %#x", status);144		}145 146		switch (WSTOPSIG(status)) {147		case SIGSTOP:148			ASSERT_EQ(0, ptrace_stop) {149				LOG_KILL_TRACEE("unexpected signal stop");150			}151			ASSERT_EQ(0, sys_ptrace(PTRACE_SETOPTIONS, pid, 0,152						PTRACE_O_TRACESYSGOOD)) {153				LOG_KILL_TRACEE("PTRACE_SETOPTIONS: %m");154			}155			ASSERT_LT(0, (rc = sys_ptrace(PTRACE_GET_SYSCALL_INFO,156						      pid, size,157						      (unsigned long) &info))) {158				LOG_KILL_TRACEE("PTRACE_GET_SYSCALL_INFO: %m");159			}160			ASSERT_EQ(expected_none_size, rc) {161				LOG_KILL_TRACEE("signal stop mismatch");162			}163			ASSERT_EQ(PTRACE_SYSCALL_INFO_NONE, info.op) {164				LOG_KILL_TRACEE("signal stop mismatch");165			}166			ASSERT_TRUE(info.arch) {167				LOG_KILL_TRACEE("signal stop mismatch");168			}169			ASSERT_TRUE(info.instruction_pointer) {170				LOG_KILL_TRACEE("signal stop mismatch");171			}172			ASSERT_TRUE(info.stack_pointer) {173				LOG_KILL_TRACEE("signal stop mismatch");174			}175			break;176 177		case SIGTRAP | 0x80:178			ASSERT_LT(0, (rc = sys_ptrace(PTRACE_GET_SYSCALL_INFO,179						      pid, size,180						      (unsigned long) &info))) {181				LOG_KILL_TRACEE("PTRACE_GET_SYSCALL_INFO: %m");182			}183			switch (ptrace_stop) {184			case 1: /* entering chdir */185			case 3: /* entering gettid */186			case 5: /* entering exit_group */187				exp_args = args[ptrace_stop / 2];188				ASSERT_EQ(expected_entry_size, rc) {189					LOG_KILL_TRACEE("entry stop mismatch");190				}191				ASSERT_EQ(PTRACE_SYSCALL_INFO_ENTRY, info.op) {192					LOG_KILL_TRACEE("entry stop mismatch");193				}194				ASSERT_TRUE(info.arch) {195					LOG_KILL_TRACEE("entry stop mismatch");196				}197				ASSERT_TRUE(info.instruction_pointer) {198					LOG_KILL_TRACEE("entry stop mismatch");199				}200				ASSERT_TRUE(info.stack_pointer) {201					LOG_KILL_TRACEE("entry stop mismatch");202				}203				ASSERT_EQ(exp_args[0], info.entry.nr) {204					LOG_KILL_TRACEE("entry stop mismatch");205				}206				ASSERT_EQ(exp_args[1], info.entry.args[0]) {207					LOG_KILL_TRACEE("entry stop mismatch");208				}209				ASSERT_EQ(exp_args[2], info.entry.args[1]) {210					LOG_KILL_TRACEE("entry stop mismatch");211				}212				ASSERT_EQ(exp_args[3], info.entry.args[2]) {213					LOG_KILL_TRACEE("entry stop mismatch");214				}215				ASSERT_EQ(exp_args[4], info.entry.args[3]) {216					LOG_KILL_TRACEE("entry stop mismatch");217				}218				ASSERT_EQ(exp_args[5], info.entry.args[4]) {219					LOG_KILL_TRACEE("entry stop mismatch");220				}221				ASSERT_EQ(exp_args[6], info.entry.args[5]) {222					LOG_KILL_TRACEE("entry stop mismatch");223				}224				break;225			case 2: /* exiting chdir */226			case 4: /* exiting gettid */227				exp_param = &exit_param[ptrace_stop / 2 - 1];228				ASSERT_EQ(expected_exit_size, rc) {229					LOG_KILL_TRACEE("exit stop mismatch");230				}231				ASSERT_EQ(PTRACE_SYSCALL_INFO_EXIT, info.op) {232					LOG_KILL_TRACEE("exit stop mismatch");233				}234				ASSERT_TRUE(info.arch) {235					LOG_KILL_TRACEE("exit stop mismatch");236				}237				ASSERT_TRUE(info.instruction_pointer) {238					LOG_KILL_TRACEE("exit stop mismatch");239				}240				ASSERT_TRUE(info.stack_pointer) {241					LOG_KILL_TRACEE("exit stop mismatch");242				}243				ASSERT_EQ(exp_param->is_error,244					  info.exit.is_error) {245					LOG_KILL_TRACEE("exit stop mismatch");246				}247				ASSERT_EQ(exp_param->rval, info.exit.rval) {248					LOG_KILL_TRACEE("exit stop mismatch");249				}250				break;251			default:252				LOG_KILL_TRACEE("unexpected syscall stop");253				abort();254			}255			break;256 257		default:258			LOG_KILL_TRACEE("unexpected stop signal %#x",259					WSTOPSIG(status));260			abort();261		}262 263		ASSERT_EQ(0, sys_ptrace(PTRACE_SYSCALL, pid, 0, 0)) {264			LOG_KILL_TRACEE("PTRACE_SYSCALL: %m");265		}266	}267 268	ASSERT_EQ(ARRAY_SIZE(args) * 2, ptrace_stop);269}270 271TEST_HARNESS_MAIN272