1 /*
2 * This file is part of execveat strace test.
3 *
4 * Copyright (c) 2015-2016 Dmitry V. Levin <ldv@strace.io>
5 * Copyright (c) 2015-2021 The strace developers.
6 * All rights reserved.
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11 #include "tests.h"
12 #include "scno.h"
13
14 #ifdef __NR_execveat
15
16 # include <fcntl.h>
17 # include <stdio.h>
18 # include <unistd.h>
19
20 # include "secontext.h"
21
22 static void
23 tests_with_existing_file(void)
24 {
25 /*
26 * Make sure the current workdir of the tracee
27 * is different from the current workdir of the tracer.
28 */
29 create_and_enter_subdir("execveat_subdir");
30
31 char *my_secontext = SECONTEXT_PID_MY();
32
33 static const char sample[] = "execveat_sample";
34 (void) unlink(sample);
35 if (open(sample, O_RDONLY | O_CREAT, 0400) < 0)
36 perror_msg_and_fail("open");
37
38 char *sample_secontext = SECONTEXT_FILE(sample);
39 static const char *argv[] = { sample, NULL };
40
41 /*
42 * Tests with AT_FDCWD.
43 */
44
45 long rc = syscall(__NR_execveat, -100, sample, argv, NULL, 0);
46 printf("%s%s(AT_FDCWD, \"%s\"%s, [\"%s\"], NULL, 0) = %s\n",
47 my_secontext, "execveat",
48 sample, sample_secontext,
49 argv[0],
50 sprintrc(rc));
51
52 if (unlink(sample))
53 perror_msg_and_fail("unlink");
54
55 rc = syscall(__NR_execveat, -100, sample, argv, NULL, 0);
56 printf("%s%s(AT_FDCWD, \"%s\", [\"%s\"], NULL, 0) = %s\n",
57 my_secontext, "execveat",
58 sample,
59 argv[0],
60 sprintrc(rc));
61
62 /*
63 * Tests with dirfd.
64 */
65
66 int cwd_fd = get_dir_fd(".");
67 char *cwd = get_fd_path(cwd_fd);
68 char *cwd_secontext = SECONTEXT_FILE(".");
69 char *sample_realpath = xasprintf("%s/%s", cwd, sample);
70
71 /* no file */
72 rc = syscall(__NR_execveat, cwd_fd, sample, argv, NULL, 0);
73 printf("%s%s(%d%s, \"%s\", [\"%s\"], NULL, 0) = %s\n",
74 my_secontext, "execveat",
75 cwd_fd, cwd_secontext,
76 sample,
77 argv[0],
78 sprintrc(rc));
79
80 if (open(sample, O_RDONLY | O_CREAT, 0400) < 0)
81 perror_msg_and_fail("open");
82
83 rc = syscall(__NR_execveat, cwd_fd, sample, argv, NULL, 0);
84 printf("%s%s(%d%s, \"%s\"%s, [\"%s\"], NULL, 0) = %s\n",
85 my_secontext, "execveat",
86 cwd_fd, cwd_secontext,
87 sample, sample_secontext,
88 argv[0],
89 sprintrc(rc));
90
91 /* cwd_fd ignored when path is absolute */
92 if (chdir("../.."))
93 perror_msg_and_fail("chdir");
94
95 rc = syscall(__NR_execveat, cwd_fd, sample_realpath, argv, NULL, 0);
96 printf("%s%s(%d%s, \"%s\"%s, [\"%s\"], NULL, 0) = %s\n",
97 my_secontext, "execveat",
98 cwd_fd, cwd_secontext,
99 sample_realpath, sample_secontext,
100 argv[0],
101 sprintrc(rc));
102
103 if (fchdir(cwd_fd))
104 perror_msg_and_fail("fchdir");
105
106 if (unlink(sample))
107 perror_msg_and_fail("unlink");
108
109 leave_and_remove_subdir();
110 }
111
112 # define FILENAME "test.execveat\nfilename"
113 # define Q_FILENAME "test.execveat\\nfilename"
114
115 static const char * const argv[] = {
116 FILENAME, "first", "second", (const char *) -1L,
117 (const char *) -2L, (const char *) -3L
118 };
119 static const char * const q_argv[] = {
120 Q_FILENAME, "first", "second"
121 };
122
123 static const char * const envp[] = {
124 "foobar=1", "foo\nbar=2", (const char *) -1L,
125 (const char *) -2L, (const char *) -3L
126 };
127 static const char * const q_envp[] = {
128 "foobar=1", "foo\\nbar=2"
129 };
130
131 int
132 main(void)
133 {
134 const char ** const tail_argv = tail_memdup(argv, sizeof(argv));
135 const char ** const tail_envp = tail_memdup(envp, sizeof(envp));
136 char *my_secontext = SECONTEXT_PID_MY();
137
138 syscall(__NR_execveat, -100, FILENAME, tail_argv, tail_envp, 0x1100);
139 printf("%s%s(AT_FDCWD, \"%s\""
140 ", [\"%s\", \"%s\", \"%s\", %p, %p, %p, ... /* %p */]"
141 # if VERBOSE
142 ", [\"%s\", \"%s\", %p, %p, %p, ... /* %p */]"
143 # else
144 ", %p /* 5 vars, unterminated */"
145 # endif
146 ", AT_SYMLINK_NOFOLLOW|AT_EMPTY_PATH) = -1 %s (%m)\n",
147 my_secontext, "execveat",
148 Q_FILENAME, q_argv[0], q_argv[1], q_argv[2],
149 argv[3], argv[4], argv[5], (char *) tail_argv + sizeof(argv),
150 # if VERBOSE
151 q_envp[0], q_envp[1], envp[2], envp[3], envp[4],
152 (char *) tail_envp + sizeof(envp),
153 # else
154 tail_envp,
155 # endif
156 errno2name());
157
158 tail_argv[ARRAY_SIZE(q_argv)] = NULL;
159 tail_envp[ARRAY_SIZE(q_envp)] = NULL;
160 (void) q_envp; /* workaround for clang bug #33068 */
161
162 syscall(__NR_execveat, -100, FILENAME, tail_argv, tail_envp, 0x1100);
163 printf("%s%s(AT_FDCWD, \"%s\", [\"%s\", \"%s\", \"%s\"]"
164 # if VERBOSE
165 ", [\"%s\", \"%s\"]"
166 # else
167 ", %p /* 2 vars */"
168 # endif
169 ", AT_SYMLINK_NOFOLLOW|AT_EMPTY_PATH) = -1 %s (%m)\n",
170 my_secontext, "execveat",
171 Q_FILENAME, q_argv[0], q_argv[1], q_argv[2],
172 # if VERBOSE
173 q_envp[0], q_envp[1],
174 # else
175 tail_envp,
176 # endif
177 errno2name());
178
179 syscall(__NR_execveat, -100, FILENAME, tail_argv + 2, tail_envp + 1, 0x1100);
180 printf("%s%s(AT_FDCWD, \"%s\", [\"%s\"]"
181 # if VERBOSE
182 ", [\"%s\"]"
183 # else
184 ", %p /* 1 var */"
185 # endif
186 ", AT_SYMLINK_NOFOLLOW|AT_EMPTY_PATH) = -1 %s (%m)\n",
187 my_secontext, "execveat",
188 Q_FILENAME, q_argv[2],
189 # if VERBOSE
190 q_envp[1],
191 # else
192 tail_envp + 1,
193 # endif
194 errno2name());
195
196 TAIL_ALLOC_OBJECT_CONST_PTR(char *, empty);
197 char **const efault = empty + 1;
198 *empty = NULL;
199
200 syscall(__NR_execveat, -100, FILENAME, empty, empty, 0x1100);
201 printf("%s%s(AT_FDCWD, \"%s\", []"
202 # if VERBOSE
203 ", []"
204 # else
205 ", %p /* 0 vars */"
206 # endif
207 ", AT_SYMLINK_NOFOLLOW|AT_EMPTY_PATH) = -1 %s (%m)\n",
208 my_secontext, "execveat",
209 Q_FILENAME,
210 # if !VERBOSE
211 empty,
212 # endif
213 errno2name());
214
215 char *const str_a = tail_alloc(DEFAULT_STRLEN + 2);
216 fill_memory_ex(str_a, DEFAULT_STRLEN + 1, '0', 10);
217 str_a[DEFAULT_STRLEN + 1] = '\0';
218
219 char *const str_b = tail_alloc(DEFAULT_STRLEN + 2);
220 fill_memory_ex(str_b, DEFAULT_STRLEN + 1, '_', 32);
221 str_b[DEFAULT_STRLEN + 1] = '\0';
222
223 char **const a = tail_alloc(sizeof(*a) * (DEFAULT_STRLEN + 2));
224 char **const b = tail_alloc(sizeof(*b) * (DEFAULT_STRLEN + 2));
225 unsigned int i;
226 for (i = 0; i <= DEFAULT_STRLEN; ++i) {
227 a[i] = &str_a[i];
228 b[i] = &str_b[i];
229 }
230 a[i] = b[i] = NULL;
231
232 syscall(__NR_execveat, -100, FILENAME, a, b, 0x1100);
233 printf("%s%s(AT_FDCWD, \"%s\", [\"%.*s\"...",
234 my_secontext, "execveat",
235 Q_FILENAME, DEFAULT_STRLEN, a[0]);
236 for (i = 1; i < DEFAULT_STRLEN; ++i)
237 printf(", \"%s\"", a[i]);
238 # if VERBOSE
239 printf(", \"%s\"", a[i]);
240 # else
241 printf(", ...");
242 # endif
243 # if VERBOSE
244 printf("], [\"%.*s\"...", DEFAULT_STRLEN, b[0]);
245 for (i = 1; i <= DEFAULT_STRLEN; ++i)
246 printf(", \"%s\"", b[i]);
247 printf("]");
248 # else
249 printf("], %p /* %u vars */", b, DEFAULT_STRLEN + 1);
250 # endif
251 printf(", AT_SYMLINK_NOFOLLOW|AT_EMPTY_PATH) = -1 %s (%m)\n",
252 errno2name());
253
254 syscall(__NR_execveat, -100, FILENAME, a + 1, b + 1, 0x1100);
255 printf("%s%s(AT_FDCWD, \"%s\", [\"%s\"",
256 my_secontext, "execveat",
257 Q_FILENAME, a[1]);
258 for (i = 2; i <= DEFAULT_STRLEN; ++i)
259 printf(", \"%s\"", a[i]);
260 # if VERBOSE
261 printf("], [\"%s\"", b[1]);
262 for (i = 2; i <= DEFAULT_STRLEN; ++i)
263 printf(", \"%s\"", b[i]);
264 printf("]");
265 # else
266 printf("], %p /* %d vars */", b + 1, DEFAULT_STRLEN);
267 # endif
268 printf(", AT_SYMLINK_NOFOLLOW|AT_EMPTY_PATH) = -1 %s (%m)\n",
269 errno2name());
270
271 syscall(__NR_execveat, -100, FILENAME, NULL, efault, 0x1100);
272 printf("%s%s(AT_FDCWD, \"%s\", NULL, %p"
273 ", AT_SYMLINK_NOFOLLOW|AT_EMPTY_PATH) = -1 %s (%m)\n",
274 my_secontext, "execveat",
275 Q_FILENAME, efault, errno2name());
276
277 syscall(__NR_execveat, -100, FILENAME, efault, NULL, 0x1100);
278 printf("%s%s(AT_FDCWD, \"%s\", %p, NULL"
279 ", AT_SYMLINK_NOFOLLOW|AT_EMPTY_PATH) = -1 %s (%m)\n",
280 my_secontext, "execveat",
281 Q_FILENAME, efault, errno2name());
282
283 tests_with_existing_file();
284
285 puts("+++ exited with 0 +++");
286 return 0;
287 }
288
289 #else
290
291 SKIP_MAIN_UNDEFINED("__NR_execveat")
292
293 #endif