brintos

brintos / linux-shallow public Read only

0
0
Text · 4.7 KiB · 0924ccd Raw
215 lines · c
1// SPDX-License-Identifier: GPL-2.02#include <linux/compiler.h>3#include <sys/types.h>4#include <sys/wait.h>5#include <sys/user.h>6#include <syscall.h>7#include <unistd.h>8#include <stdio.h>9#include <stdlib.h>10#include <string.h>11#include <sys/ptrace.h>12#include <asm/ptrace.h>13#include <errno.h>14#include "debug.h"15#include "tests/tests.h"16#include "arch-tests.h"17 18static noinline int bp_1(void)19{20	pr_debug("in %s\n", __func__);21	return 0;22}23 24static noinline int bp_2(void)25{26	pr_debug("in %s\n", __func__);27	return 0;28}29 30static int spawn_child(void)31{32	int child = fork();33 34	if (child == 0) {35		/*36		 * The child sets itself for as tracee and37		 * waits in signal for parent to trace it,38		 * then it calls bp_1 and quits.39		 */40		int err = ptrace(PTRACE_TRACEME, 0, NULL, NULL);41 42		if (err) {43			pr_debug("failed to PTRACE_TRACEME\n");44			exit(1);45		}46 47		raise(SIGCONT);48		bp_1();49		exit(0);50	}51 52	return child;53}54 55/*56 * This tests creates HW breakpoint, tries to57 * change it and checks it was properly changed.58 */59static int bp_modify1(void)60{61	pid_t child;62	int status;63	unsigned long rip = 0, dr7 = 1;64 65	child = spawn_child();66 67	waitpid(child, &status, 0);68	if (WIFEXITED(status)) {69		pr_debug("tracee exited prematurely 1\n");70		return TEST_FAIL;71	}72 73	/*74	 * The parent does following steps:75	 *  - creates a new breakpoint (id 0) for bp_2 function76	 *  - changes that breakpoint to bp_1 function77	 *  - waits for the breakpoint to hit and checks78	 *    it has proper rip of bp_1 function79	 *  - detaches the child80	 */81	if (ptrace(PTRACE_POKEUSER, child,82		   offsetof(struct user, u_debugreg[0]), bp_2)) {83		pr_debug("failed to set breakpoint, 1st time: %s\n",84			 strerror(errno));85		goto out;86	}87 88	if (ptrace(PTRACE_POKEUSER, child,89		   offsetof(struct user, u_debugreg[0]), bp_1)) {90		pr_debug("failed to set breakpoint, 2nd time: %s\n",91			 strerror(errno));92		goto out;93	}94 95	if (ptrace(PTRACE_POKEUSER, child,96		   offsetof(struct user, u_debugreg[7]), dr7)) {97		pr_debug("failed to set dr7: %s\n", strerror(errno));98		goto out;99	}100 101	if (ptrace(PTRACE_CONT, child, NULL, NULL)) {102		pr_debug("failed to PTRACE_CONT: %s\n", strerror(errno));103		goto out;104	}105 106	waitpid(child, &status, 0);107	if (WIFEXITED(status)) {108		pr_debug("tracee exited prematurely 2\n");109		return TEST_FAIL;110	}111 112	rip = ptrace(PTRACE_PEEKUSER, child,113		     offsetof(struct user_regs_struct, rip), NULL);114	if (rip == (unsigned long) -1) {115		pr_debug("failed to PTRACE_PEEKUSER: %s\n",116			 strerror(errno));117		goto out;118	}119 120	pr_debug("rip %lx, bp_1 %p\n", rip, bp_1);121 122out:123	if (ptrace(PTRACE_DETACH, child, NULL, NULL)) {124		pr_debug("failed to PTRACE_DETACH: %s", strerror(errno));125		return TEST_FAIL;126	}127 128	return rip == (unsigned long) bp_1 ? TEST_OK : TEST_FAIL;129}130 131/*132 * This tests creates HW breakpoint, tries to133 * change it to bogus value and checks the original134 * breakpoint is hit.135 */136static int bp_modify2(void)137{138	pid_t child;139	int status;140	unsigned long rip = 0, dr7 = 1;141 142	child = spawn_child();143 144	waitpid(child, &status, 0);145	if (WIFEXITED(status)) {146		pr_debug("tracee exited prematurely 1\n");147		return TEST_FAIL;148	}149 150	/*151	 * The parent does following steps:152	 *  - creates a new breakpoint (id 0) for bp_1 function153	 *  - tries to change that breakpoint to (-1) address154	 *  - waits for the breakpoint to hit and checks155	 *    it has proper rip of bp_1 function156	 *  - detaches the child157	 */158	if (ptrace(PTRACE_POKEUSER, child,159		   offsetof(struct user, u_debugreg[0]), bp_1)) {160		pr_debug("failed to set breakpoint: %s\n",161			 strerror(errno));162		goto out;163	}164 165	if (ptrace(PTRACE_POKEUSER, child,166		   offsetof(struct user, u_debugreg[7]), dr7)) {167		pr_debug("failed to set dr7: %s\n", strerror(errno));168		goto out;169	}170 171	if (!ptrace(PTRACE_POKEUSER, child,172		   offsetof(struct user, u_debugreg[0]), (unsigned long) (-1))) {173		pr_debug("failed, breakpoint set to bogus address\n");174		goto out;175	}176 177	if (ptrace(PTRACE_CONT, child, NULL, NULL)) {178		pr_debug("failed to PTRACE_CONT: %s\n", strerror(errno));179		goto out;180	}181 182	waitpid(child, &status, 0);183	if (WIFEXITED(status)) {184		pr_debug("tracee exited prematurely 2\n");185		return TEST_FAIL;186	}187 188	rip = ptrace(PTRACE_PEEKUSER, child,189		     offsetof(struct user_regs_struct, rip), NULL);190	if (rip == (unsigned long) -1) {191		pr_debug("failed to PTRACE_PEEKUSER: %s\n",192			 strerror(errno));193		goto out;194	}195 196	pr_debug("rip %lx, bp_1 %p\n", rip, bp_1);197 198out:199	if (ptrace(PTRACE_DETACH, child, NULL, NULL)) {200		pr_debug("failed to PTRACE_DETACH: %s", strerror(errno));201		return TEST_FAIL;202	}203 204	return rip == (unsigned long) bp_1 ? TEST_OK : TEST_FAIL;205}206 207int test__bp_modify(struct test_suite *test __maybe_unused,208		    int subtest __maybe_unused)209{210	TEST_ASSERT_VAL("modify test 1 failed\n", !bp_modify1());211	TEST_ASSERT_VAL("modify test 2 failed\n", !bp_modify2());212 213	return 0;214}215