1 /*
2 * Check decoding of faccessat2 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 #include "xmalloc.h"
14 #include <fcntl.h>
15 #include <stdio.h>
16 #include <unistd.h>
17
18 #define XLAT_MACROS_ONLY
19 # include "xlat/faccessat_flags.h"
20 #undef XLAT_MACROS_ONLY
21
22 #ifndef FD_PATH
23 # define FD_PATH ""
24 #else
25 # define YFLAG
26 #endif
27 #ifndef SKIP_IF_PROC_IS_UNAVAILABLE
28 # define SKIP_IF_PROC_IS_UNAVAILABLE
29 #endif
30
31 static const char *errstr;
32
33 static long
34 k_faccessat2(const unsigned int dirfd,
35 const void *const pathname,
36 const unsigned int mode,
37 const unsigned int flags)
38 {
39 const kernel_ulong_t fill = (kernel_ulong_t) 0xdefaced00000000ULL;
40 const kernel_ulong_t bad = (kernel_ulong_t) 0xbadc0dedbadc0dedULL;
41
42 const kernel_ulong_t arg1 = fill | dirfd;
43 const kernel_ulong_t arg2 = (uintptr_t) pathname;
44 const kernel_ulong_t arg3 = fill | mode;
45 const kernel_ulong_t arg4 = fill | flags;
46 const long rc = syscall(__NR_faccessat2,
47 arg1, arg2, arg3, arg4, bad, bad);
48 errstr = sprintrc(rc);
49 return rc;
50 }
51
52 int
53 main(void)
54 {
55 SKIP_IF_PROC_IS_UNAVAILABLE;
56
57 TAIL_ALLOC_OBJECT_CONST_PTR(const char, unterminated);
58 char *unterminated_str = xasprintf("%p", unterminated);
59 const void *const efault = unterminated + 1;
60 char *efault_str = xasprintf("%p", efault);
61
62 typedef struct {
63 char sym;
64 char null;
65 } sym_null;
66
67 TAIL_ALLOC_OBJECT_CONST_PTR(sym_null, dot);
68 dot->sym = '.';
69 dot->null = '\0';
70 const char *const null = &dot->null;
71
72 TAIL_ALLOC_OBJECT_CONST_PTR(sym_null, slash);
73 slash->sym = '/';
74 slash->null = '\0';
75
76 static const char path[] = "/dev/full";
77 const char *const fd_path = tail_memdup(path, sizeof(path));
78 int fd = open(path, O_WRONLY);
79 if (fd < 0)
80 perror_msg_and_fail("open: %s", path);
81 char *fd_str = xasprintf("%d%s", fd, FD_PATH);
82 const char *at_fdcwd_str =
83 #ifdef YFLAG
84 xasprintf("AT_FDCWD<%s>", get_fd_path(get_dir_fd(".")));
85 #else
86 "AT_FDCWD";
87 #endif
88
89 char *path_quoted = xasprintf("\"%s\"", path);
90
91 struct {
92 int val;
93 const char *str;
94 } dirfds[] = {
95 { ARG_STR(-1) },
96 { -100, at_fdcwd_str },
97 { fd, fd_str },
98 }, modes[] = {
99 { ARG_STR(F_OK) },
100 { ARG_STR(R_OK) },
101 { ARG_STR(W_OK) },
102 { ARG_STR(X_OK) },
103 { ARG_STR(R_OK|W_OK) },
104 { ARG_STR(R_OK|X_OK) },
105 { ARG_STR(W_OK|X_OK) },
106 { ARG_STR(R_OK|W_OK|X_OK) },
107 { 8, "0x8 /* ?_OK */" },
108 { -1, "R_OK|W_OK|X_OK|0xfffffff8" },
109 }, flags[] = {
110 { ARG_STR(0) },
111 { ARG_STR(AT_SYMLINK_NOFOLLOW) },
112 { ARG_STR(AT_EACCESS) },
113 { ARG_STR(AT_EMPTY_PATH) },
114 { ARG_STR(AT_SYMLINK_NOFOLLOW|AT_EACCESS) },
115 { ARG_STR(AT_SYMLINK_NOFOLLOW|AT_EMPTY_PATH) },
116 { ARG_STR(AT_EACCESS|AT_EMPTY_PATH) },
117 { ARG_STR(AT_SYMLINK_NOFOLLOW|AT_EACCESS|AT_EMPTY_PATH) },
118 { 1, "0x1 /* AT_??? */" },
119 { -1, "AT_SYMLINK_NOFOLLOW|AT_EACCESS|AT_EMPTY_PATH|0xffffecff" },
120 };
121
122 struct {
123 const void *val;
124 const char *str;
125 } paths[] = {
126 { 0, "NULL" },
127 { efault, efault_str },
128 { unterminated, unterminated_str },
129 { null, "\"\"" },
130 { &dot->sym, "\".\"" },
131 { &slash->sym, "\"/\"" },
132 { fd_path, path_quoted },
133 };
134
135 for (unsigned int dirfd_i = 0;
136 dirfd_i < ARRAY_SIZE(dirfds);
137 ++dirfd_i) {
138 for (unsigned int path_i = 0;
139 path_i < ARRAY_SIZE(paths);
140 ++path_i) {
141 for (unsigned int mode_i = 0;
142 mode_i < ARRAY_SIZE(modes);
143 ++mode_i) {
144 for (unsigned int flag_i = 0;
145 flag_i < ARRAY_SIZE(flags);
146 ++flag_i) {
147 k_faccessat2(dirfds[dirfd_i].val,
148 paths[path_i].val,
149 modes[mode_i].val,
150 flags[flag_i].val);
151 #ifdef PATH_TRACING
152 if (dirfds[dirfd_i].val == fd ||
153 paths[path_i].val == fd_path)
154 #endif
155 printf("faccessat2(%s, %s, %s, %s) = %s\n",
156 dirfds[dirfd_i].str,
157 paths[path_i].str,
158 modes[mode_i].str,
159 flags[flag_i].str,
160 errstr);
161 }
162 }
163 }
164 }
165
166 puts("+++ exited with 0 +++");
167 return 0;
168 }