1 /*
2 * Check decoding of faccessat syscall.
3 *
4 * Copyright (c) 2016-2021 The strace developers.
5 * All rights reserved.
6 *
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
9
10 #include "tests.h"
11 #include "scno.h"
12
13 #ifdef __NR_faccessat
14
15 # include <fcntl.h>
16 # include <stdio.h>
17 # include <unistd.h>
18
19 # include "secontext.h"
20 # include "xmalloc.h"
21
22 # ifdef FD_PATH
23 # define YFLAG
24 # else
25 # define FD_PATH ""
26 # endif
27 # ifndef SKIP_IF_PROC_IS_UNAVAILABLE
28 # define SKIP_IF_PROC_IS_UNAVAILABLE
29 # endif
30
31 # ifdef YFLAG
32 # define AT_FDCWD_FMT "<%s>"
33 # define AT_FDCWD_ARG(arg) arg,
34 # else
35 # define AT_FDCWD_FMT
36 # define AT_FDCWD_ARG(arg)
37 # endif
38
39 static const char *errstr;
40
41 static long
42 k_faccessat(const unsigned int dirfd,
43 const void *const pathname,
44 const unsigned int mode)
45 {
46 const kernel_ulong_t fill = (kernel_ulong_t) 0xdefaced00000000ULL;
47 const kernel_ulong_t bad = (kernel_ulong_t) 0xbadc0dedbadc0dedULL;
48
49 const kernel_ulong_t arg1 = fill | dirfd;
50 const kernel_ulong_t arg2 = (uintptr_t) pathname;
51 const kernel_ulong_t arg3 = fill | mode;
52 const long rc = syscall(__NR_faccessat,
53 arg1, arg2, arg3, bad, bad, bad);
54 errstr = sprintrc(rc);
55 return rc;
56 }
57
58 # ifndef PATH_TRACING
59 static void
60 tests_with_existing_file(void)
61 {
62 /*
63 * Make sure the current workdir of the tracee
64 * is different from the current workdir of the tracer.
65 */
66 create_and_enter_subdir("faccessat_subdir");
67
68 int cwd_fd = get_dir_fd(".");
69 char *cwd = get_fd_path(cwd_fd);
70
71 char *my_secontext = SECONTEXT_PID_MY();
72
73 k_faccessat(-1, NULL, F_OK);
74 printf("%s%s(-1, NULL, F_OK) = %s\n",
75 my_secontext, "faccessat", errstr);
76
77 static const char sample[] = "faccessat_sample";
78 (void) unlink(sample);
79 int fd = open(sample, O_CREAT|O_RDONLY, 0400);
80 if (fd == -1)
81 perror_msg_and_fail("open");
82 close(fd);
83 char *sample_secontext = SECONTEXT_FILE(sample);
84
85 /*
86 * Tests with AT_FDCWD.
87 */
88
89 k_faccessat(-100, sample, F_OK);
90 printf("%s%s(AT_FDCWD" AT_FDCWD_FMT ", \"%s\"%s, F_OK) = %s\n",
91 my_secontext, "faccessat",
92 AT_FDCWD_ARG(cwd)
93 sample, sample_secontext,
94 errstr);
95
96 if (unlink(sample))
97 perror_msg_and_fail("unlink");
98
99 k_faccessat(-100, sample, F_OK);
100 printf("%s%s(AT_FDCWD" AT_FDCWD_FMT ", \"%s\", F_OK) = %s\n",
101 my_secontext, "faccessat",
102 AT_FDCWD_ARG(cwd)
103 sample,
104 errstr);
105
106 /*
107 * Tests with dirfd.
108 */
109
110 char *cwd_secontext = SECONTEXT_FILE(".");
111 char *sample_realpath = xasprintf("%s/%s", cwd, sample);
112
113 /* no file */
114 k_faccessat(cwd_fd, sample, F_OK);
115 # ifdef YFLAG
116 printf("%s%s(%d<%s>%s, \"%s\", F_OK) = %s\n",
117 # else
118 printf("%s%s(%d%s, \"%s\", F_OK) = %s\n",
119 # endif
120 my_secontext, "faccessat",
121 cwd_fd,
122 # ifdef YFLAG
123 cwd,
124 # endif
125 cwd_secontext,
126 sample,
127 errstr);
128
129 fd = open(sample, O_CREAT|O_RDONLY, 0400);
130 if (fd == -1)
131 perror_msg_and_fail("open");
132 close(fd);
133
134 k_faccessat(cwd_fd, sample, F_OK);
135 # ifdef YFLAG
136 printf("%s%s(%d<%s>%s, \"%s\"%s, F_OK) = %s\n",
137 # else
138 printf("%s%s(%d%s, \"%s\"%s, F_OK) = %s\n",
139 # endif
140 my_secontext, "faccessat",
141 cwd_fd,
142 # ifdef YFLAG
143 cwd,
144 # endif
145 cwd_secontext,
146 sample, sample_secontext,
147 errstr);
148
149 /* cwd_fd ignored when path is absolute */
150 if (chdir("../.."))
151 perror_msg_and_fail("chdir");
152
153 k_faccessat(cwd_fd, sample_realpath, F_OK);
154 # ifdef YFLAG
155 printf("%s%s(%d<%s>%s, \"%s\"%s, F_OK) = %s\n",
156 # else
157 printf("%s%s(%d%s, \"%s\"%s, F_OK) = %s\n",
158 # endif
159 my_secontext, "faccessat",
160 cwd_fd,
161 # ifdef YFLAG
162 cwd,
163 # endif
164 cwd_secontext,
165 sample_realpath, sample_secontext,
166 errstr);
167
168 if (fchdir(cwd_fd))
169 perror_msg_and_fail("fchdir");
170
171 if (unlink(sample))
172 perror_msg_and_fail("unlink");
173
174 leave_and_remove_subdir();
175 }
176 # endif
177
178 int
179 main(void)
180 {
181 SKIP_IF_PROC_IS_UNAVAILABLE;
182
183 # ifndef TEST_SECONTEXT
184
185 TAIL_ALLOC_OBJECT_CONST_PTR(const char, unterminated);
186 char *unterminated_str = xasprintf("%p", unterminated);
187 const void *const efault = unterminated + 1;
188 char *efault_str = xasprintf("%p", efault);
189
190 typedef struct {
191 char sym;
192 char null;
193 } sym_null;
194
195 TAIL_ALLOC_OBJECT_CONST_PTR(sym_null, dot);
196 dot->sym = '.';
197 dot->null = '\0';
198 const char *const null = &dot->null;
199
200 TAIL_ALLOC_OBJECT_CONST_PTR(sym_null, slash);
201 slash->sym = '/';
202 slash->null = '\0';
203
204 static const char path[] = "/dev/full";
205 const char *const fd_path = tail_memdup(path, sizeof(path));
206 int fd = open(path, O_WRONLY);
207 if (fd < 0)
208 perror_msg_and_fail("open: %s", path);
209 char *fd_str = xasprintf("%d%s", fd, FD_PATH);
210 const char *at_fdcwd_str =
211 # ifdef YFLAG
212 xasprintf("AT_FDCWD<%s>", get_fd_path(get_dir_fd(".")));
213 # else
214 "AT_FDCWD";
215 # endif
216 char *path_quoted = xasprintf("\"%s\"", path);
217
218 struct {
219 int val;
220 const char *str;
221 } dirfds[] = {
222 { ARG_STR(-1) },
223 { -100, at_fdcwd_str },
224 { fd, fd_str },
225 }, modes[] = {
226 { ARG_STR(F_OK) },
227 { ARG_STR(R_OK) },
228 { ARG_STR(W_OK) },
229 { ARG_STR(X_OK) },
230 { ARG_STR(R_OK|W_OK) },
231 { ARG_STR(R_OK|X_OK) },
232 { ARG_STR(W_OK|X_OK) },
233 { ARG_STR(R_OK|W_OK|X_OK) },
234 { 8, "0x8 /* ?_OK */" },
235 { -1, "R_OK|W_OK|X_OK|0xfffffff8" },
236 };
237
238 struct {
239 const void *val;
240 const char *str;
241 } paths[] = {
242 { 0, "NULL" },
243 { efault, efault_str },
244 { unterminated, unterminated_str },
245 { null, "\"\"" },
246 { &dot->sym, "\".\"" },
247 { &slash->sym, "\"/\"" },
248 { fd_path, path_quoted },
249 };
250
251 for (unsigned int dirfd_i = 0;
252 dirfd_i < ARRAY_SIZE(dirfds);
253 ++dirfd_i) {
254 for (unsigned int path_i = 0;
255 path_i < ARRAY_SIZE(paths);
256 ++path_i) {
257 for (unsigned int mode_i = 0;
258 mode_i < ARRAY_SIZE(modes);
259 ++mode_i) {
260 k_faccessat(dirfds[dirfd_i].val,
261 paths[path_i].val,
262 modes[mode_i].val);
263 # ifdef PATH_TRACING
264 if (dirfds[dirfd_i].val == fd ||
265 paths[path_i].val == fd_path)
266 # endif
267 printf("faccessat(%s, %s, %s) = %s\n",
268 dirfds[dirfd_i].str,
269 paths[path_i].str,
270 modes[mode_i].str,
271 errstr);
272 }
273 }
274 }
275
276 # endif /* !TEST_SECONTEXT */
277
278 # ifndef PATH_TRACING
279 tests_with_existing_file();
280 # endif
281
282 puts("+++ exited with 0 +++");
283 return 0;
284 }
285
286 #else
287
288 SKIP_MAIN_UNDEFINED("__NR_faccessat")
289
290 #endif