1 /*
2 * Check decoding of quotactl syscall.
3 *
4 * Copyright (c) 2016 Eugene Syromyatnikov <evgsyr@gmail.com>
5 * Copyright (c) 2016 Dmitry V. Levin <ldv@strace.io>
6 * Copyright (c) 2016-2021 The strace developers.
7 * All rights reserved.
8 *
9 * SPDX-License-Identifier: GPL-2.0-or-later
10 */
11
12 #include "tests.h"
13 #include "scno.h"
14
15 #include <inttypes.h>
16 #include <stdint.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <unistd.h>
20
21 #include "quotactl.h"
22
23 #include "xlat.h"
24 #include "xlat/quota_formats.h"
25 #include "xlat/if_dqblk_valid.h"
26 #include "xlat/if_dqinfo_flags.h"
27 #include "xlat/if_dqinfo_valid.h"
28
29 #define QUOTA_STR(_arg) (_arg), gen_quotacmd(#_arg, _arg)
30 #define QUOTA_ID_STR(_arg) (_arg), gen_quotaid(#_arg, _arg)
31 #define QUOTA_STR_INVALID(_arg, str) (_arg), gen_quotacmd(str, _arg)
32
33 static void
34 print_dqblk(long rc, void *ptr, void *arg)
35 {
36 struct if_dqblk *db = ptr;
37 long out_arg = (long) arg;
38
39 if (((rc < 0) && out_arg) || (out_arg > 1)) {
40 printf("%p", db);
41 return;
42 }
43
44 printf("{");
45 PRINT_FIELD_U(*db, dqb_bhardlimit);
46 printf(", ");
47 PRINT_FIELD_U(*db, dqb_bsoftlimit);
48 printf(", ");
49 PRINT_FIELD_U(*db, dqb_curspace);
50 printf(", ");
51 PRINT_FIELD_U(*db, dqb_ihardlimit);
52 printf(", ");
53 PRINT_FIELD_U(*db, dqb_isoftlimit);
54 printf(", ");
55 PRINT_FIELD_U(*db, dqb_curinodes);
56
57 #if VERBOSE
58 printf(", ");
59 PRINT_FIELD_U(*db, dqb_btime);
60 printf(", ");
61 PRINT_FIELD_U(*db, dqb_itime);
62
63 printf(", dqb_valid=");
64 printflags(if_dqblk_valid, db->dqb_valid, "QIF_???");
65 #else
66 printf(", ...");
67 #endif /* !VERBOSE */
68 printf("}");
69 }
70
71 static void
72 print_nextdqblk(long rc, void *ptr, void *arg)
73 {
74 struct if_nextdqblk *db = ptr;
75 long out_arg = (long) arg;
76
77 if (((rc < 0) && out_arg) || (out_arg > 1)) {
78 printf("%p", db);
79 return;
80 }
81
82 printf("{");
83 PRINT_FIELD_U(*db, dqb_bhardlimit);
84 printf(", ");
85 PRINT_FIELD_U(*db, dqb_bsoftlimit);
86 printf(", ");
87 PRINT_FIELD_U(*db, dqb_curspace);
88 printf(", ");
89 PRINT_FIELD_U(*db, dqb_ihardlimit);
90 printf(", ");
91 PRINT_FIELD_U(*db, dqb_isoftlimit);
92 printf(", ");
93 PRINT_FIELD_U(*db, dqb_curinodes);
94
95 #if VERBOSE
96 printf(", ");
97 PRINT_FIELD_U(*db, dqb_btime);
98 printf(", ");
99 PRINT_FIELD_U(*db, dqb_itime);
100
101 printf(", dqb_valid=");
102 printflags(if_dqblk_valid, db->dqb_valid, "QIF_???");
103
104 printf(", ");
105 PRINT_FIELD_U(*db, dqb_id);
106 #else
107 printf(", ");
108 PRINT_FIELD_U(*db, dqb_id);
109 printf(", ...");
110 #endif /* !VERBOSE */
111 printf("}");
112 }
113
114 static void
115 print_dqinfo(long rc, void *ptr, void *arg)
116 {
117 struct if_dqinfo *di = ptr;
118 long out_arg = (long) arg;
119
120 if (((rc < 0) && out_arg) || (out_arg > 1)) {
121 printf("%p", di);
122 return;
123 }
124
125 printf("{");
126 PRINT_FIELD_U(*di, dqi_bgrace);
127 printf(", ");
128 PRINT_FIELD_U(*di, dqi_igrace);
129
130 printf(", dqi_flags=");
131 #if XLAT_RAW
132 printf("%#x", di->dqi_flags);
133 #elif XLAT_VERBOSE
134 printf("%#x /* ", di->dqi_flags);
135 printflags(if_dqinfo_flags, di->dqi_flags, "DQF_???");
136 printf(" */");
137 #else /* XLAT_ABBREV */
138 printflags(if_dqinfo_flags, di->dqi_flags, "DQF_???");
139 #endif
140 printf(", dqi_valid=");
141 #if XLAT_RAW
142 printf("%#x", di->dqi_valid);
143 #elif XLAT_VERBOSE
144 printf("%#x /* ", di->dqi_valid);
145 printflags(if_dqinfo_valid, di->dqi_valid, "IIF_???");
146 printf(" */");
147 #else /* XLAT_ABBREV */
148 printflags(if_dqinfo_valid, di->dqi_valid, "IIF_???");
149 #endif
150 printf("}");
151 }
152
153 static void
154 print_dqfmt(long rc, void *ptr, void *arg)
155 {
156 uint32_t *fmtval = ptr;
157 long out_arg = (long) arg;
158 const char *fmtstr;
159
160 if (((rc < 0) && out_arg) || (out_arg > 1)) {
161 printf("%p", fmtval);
162 return;
163 }
164 printf("[");
165 #if XLAT_RAW
166 printf("%#x]", *fmtval);
167 return;
168 #else
169 switch (*fmtval) {
170 case 1:
171 fmtstr = "QFMT_VFS_OLD";
172 break;
173 case 2:
174 fmtstr = "QFMT_VFS_V0";
175 break;
176 case 3:
177 fmtstr = "QFMT_OCFS2";
178 break;
179 case 4:
180 fmtstr = "QFMT_VFS_V1";
181 break;
182 default:
183 printf("%#x /* QFMT_VFS_??? */]", *fmtval);
184 return;
185 }
186 #endif
187 #if XLAT_VERBOSE
188 printf("%#x /* %s */]", *fmtval, fmtstr);
189 #else
190 printf("%s]", fmtstr);
191 #endif
192 }
193
194 static const char *
195 gen_quotacmd(const char *abbrev_str, const uint32_t cmd)
196 {
197 static char quotacmd_str[2048];
198
199 #if XLAT_RAW
200 snprintf(quotacmd_str, sizeof(quotacmd_str), "%u", cmd);
201 #elif XLAT_VERBOSE
202 snprintf(quotacmd_str, sizeof(quotacmd_str), "%u /* %s */", cmd, abbrev_str);
203 #else
204 return abbrev_str;
205 #endif
206 return quotacmd_str;
207 }
208
209 static const char *
210 gen_quotaid(const char *abbrev_str, const uint32_t id)
211 {
212 static char quotaid_str[1024];
213
214 #if XLAT_RAW
215 snprintf(quotaid_str, sizeof(quotaid_str), "%#x", id);
216 #elif XLAT_VERBOSE
217 snprintf(quotaid_str, sizeof(quotaid_str), "%#x /* %s */", id, abbrev_str);
218 #else
219 return abbrev_str;
220 #endif
221 return quotaid_str;
222 }
223
224 int
225 main(void)
226 {
227 char *bogus_special = (char *) tail_alloc(1) + 1;
228 void *bogus_addr = (char *) tail_alloc(1) + 1;
229
230 char bogus_special_str[sizeof(void *) * 2 + sizeof("0x")];
231 char unterminated_str[sizeof(void *) * 2 + sizeof("0x")];
232
233 static char invalid_cmd_str[1024];
234 static char invalid_id_str[1024];
235 char *unterminated = tail_memdup(unterminated_data,
236 sizeof(unterminated_data));
237 TAIL_ALLOC_OBJECT_CONST_PTR(struct if_dqblk, dqblk);
238 TAIL_ALLOC_OBJECT_CONST_PTR(struct if_dqinfo, dqinfo);
239 TAIL_ALLOC_OBJECT_CONST_PTR(uint32_t, fmt);
240 TAIL_ALLOC_OBJECT_CONST_PTR(struct if_nextdqblk, nextdqblk);
241
242 snprintf(bogus_special_str, sizeof(bogus_special_str), "%p",
243 bogus_special);
244 snprintf(unterminated_str, sizeof(unterminated_str), "%p",
245 unterminated);
246
247
248 /* Invalid commands */
249 snprintf(invalid_cmd_str, sizeof(invalid_cmd_str),
250 "QCMD(%#x /* Q_??? */, %#x /* ???QUOTA */)",
251 QCMD_CMD(bogus_cmd), QCMD_TYPE(bogus_cmd));
252 check_quota(CQF_NONE, bogus_cmd, gen_quotacmd(invalid_cmd_str, bogus_cmd),
253 bogus_special, bogus_special_str, bogus_id, bogus_addr);
254
255 snprintf(invalid_cmd_str, sizeof(invalid_cmd_str),
256 "QCMD(0 /* Q_??? */, USRQUOTA)");
257 check_quota(CQF_ADDR_STR, 0, gen_quotacmd(invalid_cmd_str, 0),
258 ARG_STR(NULL), -1, ARG_STR(NULL));
259
260
261 /* Q_QUOTAON */
262
263 check_quota(CQF_ID_STR | CQF_ADDR_STR,
264 QUOTA_STR(QCMD(Q_QUOTAON, USRQUOTA)),
265 ARG_STR("/dev/bogus/"), QUOTA_ID_STR(QFMT_VFS_OLD),
266 ARG_STR("/tmp/bogus/"));
267
268 snprintf(invalid_cmd_str, sizeof(invalid_cmd_str),
269 "QCMD(Q_QUOTAON, %#x /* ???QUOTA */)",
270 QCMD_TYPE(QCMD(Q_QUOTAON, 0xfacefeed)));
271 #if XLAT_RAW
272 snprintf(invalid_id_str, sizeof(invalid_id_str),
273 "%#x", bogus_id);
274 #else
275 snprintf(invalid_id_str, sizeof(invalid_id_str),
276 "%#x /* QFMT_VFS_??? */", bogus_id);
277 #endif
278 check_quota(CQF_ID_STR, QCMD(Q_QUOTAON, 0xfacefeed),
279 gen_quotacmd(invalid_cmd_str, QCMD(Q_QUOTAON, 0xfacefeed)),
280 bogus_dev, bogus_dev_str,
281 bogus_id, invalid_id_str, bogus_addr);
282
283
284 /* Q_QUOTAOFF */
285
286 check_quota(CQF_ID_SKIP | CQF_ADDR_SKIP,
287 QUOTA_STR(QCMD(Q_QUOTAOFF, USRQUOTA)),
288 bogus_special, bogus_special_str);
289 check_quota(CQF_ID_SKIP | CQF_ADDR_SKIP,
290 QUOTA_STR(QCMD(Q_QUOTAOFF, GRPQUOTA)),
291 ARG_STR("/dev/bogus/"));
292 check_quota(CQF_ID_SKIP | CQF_ADDR_SKIP,
293 QUOTA_STR(QCMD(Q_QUOTAOFF, PRJQUOTA)), ARG_STR(NULL));
294 const char *cmd_str = "QCMD(Q_QUOTAOFF, 0x3 /* ???QUOTA */)";
295 check_quota(CQF_ID_SKIP | CQF_ADDR_SKIP,
296 QUOTA_STR_INVALID(QCMD(Q_QUOTAOFF, 3), cmd_str),
297 ARG_STR(NULL));
298
299
300 /* Q_GETQUOTA */
301
302 /* Trying our best to get successful result */
303 check_quota(CQF_ADDR_CB, QUOTA_STR(QCMD(Q_GETQUOTA, USRQUOTA)),
304 ARG_STR("/dev/sda1"), getuid(), dqblk, print_dqblk,
305 (intptr_t) 1);
306
307 check_quota(CQF_ADDR_CB, QUOTA_STR(QCMD(Q_GETQUOTA, GRPQUOTA)),
308 ARG_STR(NULL), -1, dqblk, print_dqblk, (intptr_t) 1);
309
310
311 /* Q_GETNEXTQUOTA */
312
313 check_quota(CQF_ADDR_CB, QUOTA_STR(QCMD(Q_GETNEXTQUOTA, USRQUOTA)),
314 ARG_STR("/dev/sda1"), 0, nextdqblk, print_nextdqblk,
315 (intptr_t) 1);
316
317
318 /* Q_SETQUOTA */
319
320 fill_memory(dqblk, sizeof(*dqblk));
321
322 check_quota(CQF_NONE, QUOTA_STR(QCMD(Q_SETQUOTA, PRJQUOTA)),
323 bogus_special, bogus_special_str, 0, bogus_addr);
324
325 check_quota(CQF_ADDR_CB, QUOTA_STR(QCMD(Q_SETQUOTA, PRJQUOTA)),
326 ARG_STR("/dev/bogus/"), 3141592653U, dqblk, print_dqblk,
327 (intptr_t) 0);
328
329
330 /* Q_GETINFO */
331
332 check_quota(CQF_ID_SKIP | CQF_ADDR_CB,
333 QUOTA_STR(QCMD(Q_GETINFO, GRPQUOTA)),
334 ARG_STR("/dev/sda1"), dqinfo, print_dqinfo, (intptr_t) 1);
335
336 check_quota(CQF_ID_SKIP | CQF_ADDR_CB,
337 QUOTA_STR(QCMD(Q_GETINFO, GRPQUOTA)),
338 bogus_special, bogus_special_str, dqinfo,
339 print_dqinfo, (intptr_t) 1);
340
341 /* Q_SETINFO */
342
343 fill_memory(dqinfo, sizeof(*dqinfo));
344 /* In order to check flag printing correctness */
345 dqinfo->dqi_flags = 0xdeadabcd;
346
347 check_quota(CQF_ID_SKIP | CQF_ADDR_STR,
348 QUOTA_STR(QCMD(Q_SETINFO, PRJQUOTA)),
349 bogus_special, bogus_special_str, ARG_STR(NULL));
350
351 check_quota(CQF_ID_SKIP | CQF_ADDR_CB,
352 QUOTA_STR(QCMD(Q_SETINFO, USRQUOTA)),
353 ARG_STR("/dev/bogus/"), dqinfo, print_dqinfo, (intptr_t) 0);
354
355
356 /* Q_GETFMT */
357
358 check_quota(CQF_ID_SKIP | CQF_ADDR_STR,
359 QUOTA_STR(QCMD(Q_GETFMT, PRJQUOTA)),
360 bogus_special, bogus_special_str, ARG_STR(NULL));
361 check_quota(CQF_ID_SKIP,
362 QUOTA_STR(QCMD(Q_GETFMT, USRQUOTA)),
363 unterminated, unterminated_str, fmt + 1);
364 check_quota(CQF_ID_SKIP | CQF_ADDR_CB,
365 QUOTA_STR(QCMD(Q_GETFMT, GRPQUOTA)),
366 ARG_STR("/dev/sda1"), fmt, print_dqfmt, (uintptr_t) 1);
367 /* Try to check valid quota format */
368 *fmt = QFMT_VFS_OLD;
369 check_quota(CQF_ID_SKIP | CQF_ADDR_CB,
370 QUOTA_STR(QCMD(Q_GETFMT, GRPQUOTA)),
371 ARG_STR("/dev/sda1"), fmt, print_dqfmt, (uintptr_t) 1);
372
373
374 /* Q_SYNC */
375
376 check_quota(CQF_ID_SKIP | CQF_ADDR_SKIP,
377 QUOTA_STR(QCMD(Q_SYNC, USRQUOTA)),
378 bogus_special, bogus_special_str);
379 cmd_str = "QCMD(Q_SYNC, 0xff /* ???QUOTA */)";
380 check_quota(CQF_ID_SKIP | CQF_ADDR_SKIP,
381 QUOTA_STR_INVALID(QCMD(Q_SYNC, 0xfff), cmd_str),
382 ARG_STR(NULL));
383
384 puts("+++ exited with 0 +++");
385
386 return 0;
387 }