1 /*
2 * Check decoding of linux/fs.h 'X' ioctl commands.
3 *
4 * Copyright (c) 2020-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 <linux/fs.h>
12
13 #include <errno.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <sys/ioctl.h>
17
18 static const char *errstr;
19
20 static int
21 do_ioctl(kernel_ulong_t cmd, kernel_ulong_t arg)
22 {
23 int rc = ioctl(-1, cmd, arg);
24 errstr = sprintrc(rc);
25
26 #ifdef INJECT_RETVAL
27 if (rc != INJECT_RETVAL)
28 error_msg_and_fail("Return value [%d] does not match"
29 " expectations [%d]", rc, INJECT_RETVAL);
30
31 static char inj_errstr[4096];
32
33 snprintf(inj_errstr, sizeof(inj_errstr), "%s (INJECTED)", errstr);
34 errstr = inj_errstr;
35 #endif
36
37 return rc;
38 }
39
40 static int
41 do_ioctl_ptr(kernel_ulong_t cmd, const void *arg)
42 {
43 return do_ioctl(cmd, (uintptr_t) arg);
44 }
45
46 #ifdef INJECT_RETVAL
47 static void
48 skip_ioctls(int argc, const char *argv[])
49 {
50 if (argc < 2)
51 error_msg_and_fail("Usage: %s NUM_SKIP", argv[0]);
52
53 unsigned long num_skip = strtoul(argv[1], NULL, 0);
54
55 for (size_t i = 0; i < num_skip; ++i) {
56 int rc = ioctl(-1, FIFREEZE, 0);
57
58 printf("ioctl(-1, %s) = %s%s\n",
59 XLAT_STR(FIFREEZE), sprintrc(rc),
60 rc == INJECT_RETVAL ? " (INJECTED)" : "");
61
62 if (rc == INJECT_RETVAL)
63 return;
64 }
65
66 error_msg_and_fail("Issued %lu ioctl syscalls but failed"
67 " to detect an injected return code %d",
68 num_skip, INJECT_RETVAL);
69 }
70 #endif /* INJECT_RETVAL */
71
72 int
73 main(int argc, const char *argv[])
74 {
75 #ifdef INJECT_RETVAL
76 skip_ioctls(argc, argv);
77 #endif
78
79 static const struct {
80 uint32_t cmd;
81 const char *str;
82 bool has_arg;
83 } simple_cmds[] = {
84 { ARG_STR(FIFREEZE), false },
85 { ARG_STR(FITHAW), false },
86 { _IO('X', 0xff), "_IOC(_IOC_NONE, 0x58, 0xff, 0)", true },
87 };
88
89 for (size_t i = 0; i < ARRAY_SIZE(simple_cmds); ++i) {
90 do_ioctl(simple_cmds[i].cmd, 0);
91 if (simple_cmds[i].has_arg) {
92 printf("ioctl(-1, " XLAT_FMT ", 0) = %s\n",
93 XLAT_SEL(simple_cmds[i].cmd, simple_cmds[i].str),
94 errstr);
95 } else {
96 printf("ioctl(-1, " XLAT_FMT ") = %s\n",
97 XLAT_SEL(simple_cmds[i].cmd, simple_cmds[i].str),
98 errstr);
99 }
100
101 static const unsigned long arg =
102 (unsigned long) 0xbadc0deddeadc0deULL;
103
104 do_ioctl(simple_cmds[i].cmd, arg);
105 if (simple_cmds[i].has_arg) {
106 printf("ioctl(-1, " XLAT_FMT ", %#lx) = %s\n",
107 XLAT_SEL(simple_cmds[i].cmd, simple_cmds[i].str),
108 arg, errstr);
109 } else {
110 printf("ioctl(-1, " XLAT_FMT ") = %s\n",
111 XLAT_SEL(simple_cmds[i].cmd, simple_cmds[i].str),
112 errstr);
113 }
114 }
115
116 static const struct {
117 uint32_t cmd;
118 const char *str;
119 } null_arg_cmds[] = {
120 { ARG_STR(FITRIM) },
121 { ARG_STR(FS_IOC_FSSETXATTR) },
122 { ARG_STR(FS_IOC_FSGETXATTR) },
123 };
124
125 for (size_t i = 0; i < ARRAY_SIZE(null_arg_cmds); ++i) {
126 do_ioctl(null_arg_cmds[i].cmd, 0);
127 printf("ioctl(-1, " XLAT_FMT ", NULL) = %s\n",
128 XLAT_SEL(null_arg_cmds[i].cmd, null_arg_cmds[i].str),
129 errstr);
130 }
131
132 TAIL_ALLOC_OBJECT_CONST_PTR(struct fstrim_range, p_range);
133
134 do_ioctl_ptr(FITRIM, (char *) p_range + 1);
135 printf("ioctl(-1, %s, %p) = %s\n",
136 XLAT_STR(FITRIM), (char *) p_range + 1, errstr);
137
138 p_range->start = (typeof(p_range->start)) 0xdeadbeefcafef00dULL;
139 p_range->len = (typeof(p_range->len)) 0xfacefeedbabec0deULL;
140 p_range->minlen = (typeof(p_range->minlen)) 0xbadc0deddeadc0deULL;
141
142 do_ioctl_ptr(FITRIM, p_range);
143 printf("ioctl(-1, %s, {start=%#jx, len=%ju, minlen=%ju}) = %s\n",
144 XLAT_STR(FITRIM), (uintmax_t) p_range->start,
145 (uintmax_t) p_range->len, (uintmax_t) p_range->minlen,
146 errstr);
147
148 /* FS_IOC_FSSETXATTR */
149 TAIL_ALLOC_OBJECT_CONST_PTR(struct fsxattr, p_fsxattr);
150
151 do_ioctl_ptr(FS_IOC_FSSETXATTR, (char *) p_fsxattr + 1);
152 printf("ioctl(-1, %s, %p) = %s\n",
153 XLAT_STR(FS_IOC_FSSETXATTR), (char *) p_fsxattr + 1, errstr);
154
155 #define VALID_FSX_XFLAGS 0x8001fffb
156 #define INVALID_FSX_XFLAGS 0x7ffe0004
157
158 p_fsxattr->fsx_xflags = VALID_FSX_XFLAGS;
159 p_fsxattr->fsx_extsize = 0xdeadbeefU;
160 p_fsxattr->fsx_projid = 0xcafef00dU;
161 p_fsxattr->fsx_cowextsize = 0xbabec0deU;
162
163 do_ioctl_ptr(FS_IOC_FSSETXATTR, p_fsxattr);
164 printf("ioctl(-1, %s, {fsx_xflags=%s, fsx_extsize=%u, fsx_projid=%#x"
165 ", fsx_cowextsize=%u}) = %s\n",
166 XLAT_STR(FS_IOC_FSSETXATTR),
167 XLAT_KNOWN(VALID_FSX_XFLAGS,
168 "FS_XFLAG_REALTIME|FS_XFLAG_PREALLOC|"
169 "FS_XFLAG_IMMUTABLE|FS_XFLAG_APPEND|"
170 "FS_XFLAG_SYNC|FS_XFLAG_NOATIME|"
171 "FS_XFLAG_NODUMP|FS_XFLAG_RTINHERIT|"
172 "FS_XFLAG_PROJINHERIT|FS_XFLAG_NOSYMLINKS|"
173 "FS_XFLAG_EXTSIZE|FS_XFLAG_EXTSZINHERIT|"
174 "FS_XFLAG_NODEFRAG|FS_XFLAG_FILESTREAM|"
175 "FS_XFLAG_DAX|FS_XFLAG_COWEXTSIZE|FS_XFLAG_HASATTR"),
176 p_fsxattr->fsx_extsize,
177 p_fsxattr->fsx_projid,
178 p_fsxattr->fsx_cowextsize,
179 errstr);
180
181 p_fsxattr->fsx_xflags = ~p_fsxattr->fsx_xflags;
182
183 do_ioctl_ptr(FS_IOC_FSSETXATTR, p_fsxattr);
184 printf("ioctl(-1, %s, {fsx_xflags=%s, fsx_extsize=%u, fsx_projid=%#x"
185 ", fsx_cowextsize=%u}) = %s\n",
186 XLAT_STR(FS_IOC_FSSETXATTR),
187 XLAT_UNKNOWN(INVALID_FSX_XFLAGS, "FS_XFLAG_???"),
188 p_fsxattr->fsx_extsize,
189 p_fsxattr->fsx_projid,
190 p_fsxattr->fsx_cowextsize,
191 errstr);
192
193 /* FS_IOC_FSGETXATTR */
194 do_ioctl_ptr(FS_IOC_FSGETXATTR, (char *) p_fsxattr + 1);
195 printf("ioctl(-1, %s, %p) = %s\n",
196 XLAT_STR(FS_IOC_FSGETXATTR), (char *) p_fsxattr + 1, errstr);
197
198 p_fsxattr->fsx_xflags = VALID_FSX_XFLAGS;
199 p_fsxattr->fsx_nextents = 0xfacefeedU;
200
201 if (do_ioctl_ptr(FS_IOC_FSGETXATTR, p_fsxattr) < 0) {
202 printf("ioctl(-1, %s, %p) = %s\n",
203 XLAT_STR(FS_IOC_FSGETXATTR), p_fsxattr, errstr);
204 } else {
205 printf("ioctl(-1, %s, {fsx_xflags=%s, fsx_extsize=%u"
206 ", fsx_nextents=%u, fsx_projid=%#x"
207 ", fsx_cowextsize=%u}) = %s\n",
208 XLAT_STR(FS_IOC_FSGETXATTR),
209 XLAT_KNOWN(VALID_FSX_XFLAGS,
210 "FS_XFLAG_REALTIME|FS_XFLAG_PREALLOC|"
211 "FS_XFLAG_IMMUTABLE|FS_XFLAG_APPEND|"
212 "FS_XFLAG_SYNC|FS_XFLAG_NOATIME|"
213 "FS_XFLAG_NODUMP|FS_XFLAG_RTINHERIT|"
214 "FS_XFLAG_PROJINHERIT|FS_XFLAG_NOSYMLINKS|"
215 "FS_XFLAG_EXTSIZE|FS_XFLAG_EXTSZINHERIT|"
216 "FS_XFLAG_NODEFRAG|FS_XFLAG_FILESTREAM|"
217 "FS_XFLAG_DAX|FS_XFLAG_COWEXTSIZE|FS_XFLAG_HASATTR"),
218 p_fsxattr->fsx_extsize,
219 p_fsxattr->fsx_nextents,
220 p_fsxattr->fsx_projid,
221 p_fsxattr->fsx_cowextsize,
222 errstr);
223 }
224
225 p_fsxattr->fsx_xflags = ~p_fsxattr->fsx_xflags;
226
227 if (do_ioctl_ptr(FS_IOC_FSGETXATTR, p_fsxattr) < 0) {
228 printf("ioctl(-1, %s, %p) = %s\n",
229 XLAT_STR(FS_IOC_FSGETXATTR), p_fsxattr, errstr);
230 } else {
231 printf("ioctl(-1, %s, {fsx_xflags=%s, fsx_extsize=%u"
232 ", fsx_nextents=%u, fsx_projid=%#x"
233 ", fsx_cowextsize=%u}) = %s\n",
234 XLAT_STR(FS_IOC_FSGETXATTR),
235 XLAT_UNKNOWN(INVALID_FSX_XFLAGS, "FS_XFLAG_???"),
236 p_fsxattr->fsx_extsize,
237 p_fsxattr->fsx_nextents,
238 p_fsxattr->fsx_projid,
239 p_fsxattr->fsx_cowextsize,
240 errstr);
241 }
242
243 puts("+++ exited with 0 +++");
244 return 0;
245 }