1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2008 Analog Devices Inc.
4 * Copyright (c) Linux Test Project, 2008-2023
5 * Copyright (c) 2025 Wei Gao <wegao@suse.com>
6 */
7
8 /*\
9 * [Description]
10 *
11 * Check out-of-bound/unaligned addresses given to
12 *
13 * - {PEEK,POKE}{DATA,TEXT,USER}
14 * - {GET,SET}{,FG}REGS
15 * - {GET,SET}SIGINFO
16 */
17
18 #include <stdlib.h>
19 #include <sys/ptrace.h>
20 #include "tst_test.h"
21
22 /* this should be sizeof(struct user), but that info is only found
23 * in the kernel asm/user.h which is not exported to userspace.
24 */
25
26 #if defined(__i386__)
27 # define SIZEOF_USER 284
28 #elif defined(__x86_64__)
29 # define SIZEOF_USER 928
30 #else
31 # define SIZEOF_USER 0x1000 /* just pick a big number */
32 #endif
33
34 static struct test_case_t {
35 int request;
36 long addr;
37 long data;
38 } test_cases[] = {
39 {PTRACE_PEEKDATA, .addr = 0},
40 {PTRACE_PEEKDATA, .addr = 1},
41 {PTRACE_PEEKDATA, .addr = 2},
42 {PTRACE_PEEKDATA, .addr = 3},
43 {PTRACE_PEEKDATA, .addr = -1},
44 {PTRACE_PEEKDATA, .addr = -2},
45 {PTRACE_PEEKDATA, .addr = -3},
46 {PTRACE_PEEKDATA, .addr = -4},
47 {PTRACE_PEEKTEXT, .addr = 0},
48 {PTRACE_PEEKTEXT, .addr = 1},
49 {PTRACE_PEEKTEXT, .addr = 2},
50 {PTRACE_PEEKTEXT, .addr = 3},
51 {PTRACE_PEEKTEXT, .addr = -1},
52 {PTRACE_PEEKTEXT, .addr = -2},
53 {PTRACE_PEEKTEXT, .addr = -3},
54 {PTRACE_PEEKTEXT, .addr = -4},
55 {PTRACE_PEEKUSER, .addr = SIZEOF_USER + 1},
56 {PTRACE_PEEKUSER, .addr = SIZEOF_USER + 2},
57 {PTRACE_PEEKUSER, .addr = SIZEOF_USER + 3},
58 {PTRACE_PEEKUSER, .addr = SIZEOF_USER + 4},
59 {PTRACE_PEEKUSER, .addr = -1},
60 {PTRACE_PEEKUSER, .addr = -2},
61 {PTRACE_PEEKUSER, .addr = -3},
62 {PTRACE_PEEKUSER, .addr = -4},
63 {PTRACE_POKEDATA, .addr = 0},
64 {PTRACE_POKEDATA, .addr = 1},
65 {PTRACE_POKEDATA, .addr = 2},
66 {PTRACE_POKEDATA, .addr = 3},
67 {PTRACE_POKEDATA, .addr = -1},
68 {PTRACE_POKEDATA, .addr = -2},
69 {PTRACE_POKEDATA, .addr = -3},
70 {PTRACE_POKEDATA, .addr = -4},
71 {PTRACE_POKETEXT, .addr = 0},
72 {PTRACE_POKETEXT, .addr = 1},
73 {PTRACE_POKETEXT, .addr = 2},
74 {PTRACE_POKETEXT, .addr = 3},
75 {PTRACE_POKETEXT, .addr = -1},
76 {PTRACE_POKETEXT, .addr = -2},
77 {PTRACE_POKETEXT, .addr = -3},
78 {PTRACE_POKETEXT, .addr = -4},
79 {PTRACE_POKEUSER, .addr = SIZEOF_USER + 1},
80 {PTRACE_POKEUSER, .addr = SIZEOF_USER + 2},
81 {PTRACE_POKEUSER, .addr = SIZEOF_USER + 3},
82 {PTRACE_POKEUSER, .addr = SIZEOF_USER + 4},
83 {PTRACE_POKEUSER, .addr = -1},
84 {PTRACE_POKEUSER, .addr = -2},
85 {PTRACE_POKEUSER, .addr = -3},
86 {PTRACE_POKEUSER, .addr = -4},
87 #ifdef PTRACE_GETREGS
88 {PTRACE_GETREGS, .data = 0},
89 {PTRACE_GETREGS, .data = 1},
90 {PTRACE_GETREGS, .data = 2},
91 {PTRACE_GETREGS, .data = 3},
92 {PTRACE_GETREGS, .data = -1},
93 {PTRACE_GETREGS, .data = -2},
94 {PTRACE_GETREGS, .data = -3},
95 {PTRACE_GETREGS, .data = -4},
96 #endif
97 #ifdef PTRACE_GETFGREGS
98 {PTRACE_GETFGREGS, .data = 0},
99 {PTRACE_GETFGREGS, .data = 1},
100 {PTRACE_GETFGREGS, .data = 2},
101 {PTRACE_GETFGREGS, .data = 3},
102 {PTRACE_GETFGREGS, .data = -1},
103 {PTRACE_GETFGREGS, .data = -2},
104 {PTRACE_GETFGREGS, .data = -3},
105 {PTRACE_GETFGREGS, .data = -4},
106 #endif
107 #ifdef PTRACE_SETREGS
108 {PTRACE_SETREGS, .data = 0},
109 {PTRACE_SETREGS, .data = 1},
110 {PTRACE_SETREGS, .data = 2},
111 {PTRACE_SETREGS, .data = 3},
112 {PTRACE_SETREGS, .data = -1},
113 {PTRACE_SETREGS, .data = -2},
114 {PTRACE_SETREGS, .data = -3},
115 {PTRACE_SETREGS, .data = -4},
116 #endif
117 #ifdef PTRACE_SETFGREGS
118 {PTRACE_SETFGREGS, .data = 0},
119 {PTRACE_SETFGREGS, .data = 1},
120 {PTRACE_SETFGREGS, .data = 2},
121 {PTRACE_SETFGREGS, .data = 3},
122 {PTRACE_SETFGREGS, .data = -1},
123 {PTRACE_SETFGREGS, .data = -2},
124 {PTRACE_SETFGREGS, .data = -3},
125 {PTRACE_SETFGREGS, .data = -4},
126 #endif
127 #if HAVE_DECL_PTRACE_GETSIGINFO
128 {PTRACE_GETSIGINFO, .data = 0},
129 {PTRACE_GETSIGINFO, .data = 1},
130 {PTRACE_GETSIGINFO, .data = 2},
131 {PTRACE_GETSIGINFO, .data = 3},
132 {PTRACE_GETSIGINFO, .data = -1},
133 {PTRACE_GETSIGINFO, .data = -2},
134 {PTRACE_GETSIGINFO, .data = -3},
135 {PTRACE_GETSIGINFO, .data = -4},
136 #endif
137 #if HAVE_DECL_PTRACE_SETSIGINFO
138 {PTRACE_SETSIGINFO, .data = 0},
139 {PTRACE_SETSIGINFO, .data = 1},
140 {PTRACE_SETSIGINFO, .data = 2},
141 {PTRACE_SETSIGINFO, .data = 3},
142 {PTRACE_SETSIGINFO, .data = -1},
143 {PTRACE_SETSIGINFO, .data = -2},
144 {PTRACE_SETSIGINFO, .data = -3},
145 {PTRACE_SETSIGINFO, .data = -4},
146 #endif
147 };
148
149 #define SPT(x)[PTRACE_##x] = #x,
150 static char *strings[] = {
151 SPT(TRACEME)
152 SPT(PEEKTEXT)
153 SPT(PEEKDATA)
154 SPT(PEEKUSER)
155 SPT(POKETEXT)
156 SPT(POKEDATA)
157 SPT(POKEUSER)
158 #ifdef PTRACE_GETREGS
159 SPT(GETREGS)
160 #endif
161 #ifdef PTRACE_SETREGS
162 SPT(SETREGS)
163 #endif
164 #ifdef PTRACE_GETSIGINFO
165 SPT(GETSIGINFO)
166 #endif
167 #ifdef PTRACE_SETSIGINFO
168 SPT(SETSIGINFO)
169 #endif
170 #ifdef PTRACE_GETFGREGS
171 SPT(GETFGREGS)
172 #endif
173 #ifdef PTRACE_SETFGREGS
174 SPT(SETFGREGS)
175 #endif
176 SPT(KILL)
177 SPT(SINGLESTEP)
178 };
179
child(void)180 static void child(void)
181 {
182 SAFE_PTRACE(PTRACE_TRACEME, 0, NULL, NULL);
183 raise(SIGSTOP);
184 exit(0);
185 }
186
run(void)187 static void run(void)
188 {
189 size_t i;
190 int pid;
191 int status;
192 int exp_errnos[] = {EIO, EFAULT};
193
194 pid = SAFE_FORK();
195
196 if (!pid)
197 child();
198
199 SAFE_WAIT(&status);
200
201 if (!WIFSTOPPED(status))
202 tst_brk(TBROK, "child %d was not stopped", pid);
203
204 for (i = 0; i < ARRAY_SIZE(test_cases); ++i) {
205 struct test_case_t *tc = &test_cases[i];
206
207 TST_EXP_FAIL_ARR(ptrace(tc->request, pid, (void *)tc->addr,
208 (void *)tc->data), exp_errnos, ARRAY_SIZE(exp_errnos),
209 "ptrace(%s, ..., %li, %li) failed as expected",
210 strings[tc->request], tc->addr, tc->data);
211 }
212
213 SAFE_PTRACE(PTRACE_CONT, pid, NULL, NULL);
214
215 }
216
217 static struct tst_test test = {
218 .test_all = run,
219 .forks_child = 1,
220 };
221