• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Check decoding of quotactl xfs subcommands.
3  *
4  * Copyright (c) 2016 Eugene Syromyatnikov <evgsyr@gmail.com>
5  * Copyright (c) 2016 Dmitry V. Levin <ldv@altlinux.org>
6  * Copyright (c) 2016-2018 The strace developers.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. The name of the author may not be used to endorse or promote products
18  *    derived from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include "tests.h"
33 
34 #include <asm/unistd.h>
35 
36 #if defined(__NR_quotactl) && \
37 	(defined(HAVE_LINUX_QUOTA_H) || defined(HAVE_SYS_QUOTA_H)) && \
38 	defined(HAVE_LINUX_DQBLK_XFS_H)
39 
40 # include <stdio.h>
41 # include <string.h>
42 # include <unistd.h>
43 
44 # include <linux/dqblk_xfs.h>
45 
46 # include "quotactl.h"
47 
48 # ifndef Q_GETNEXTQUOTA
49 #  define Q_XGETNEXTQUOTA	XQM_CMD(0x9)
50 # endif /* !Q_GETNEXTQUOTA */
51 
52 # ifndef Q_XGETQSTATV
53 
54 #  define Q_XGETQSTATV		XQM_CMD(8)
55 #  define FS_QSTATV_VERSION1	1
56 
57 struct fs_qfilestatv {
58 	uint64_t	qfs_ino;	/* inode number */
59 	uint64_t	qfs_nblks;	/* number of BBs 512-byte-blks */
60 	uint32_t	qfs_nextents;	/* number of extents */
61 	uint32_t	qfs_pad;	/* pad for 8-byte alignment */
62 };
63 
64 struct fs_quota_statv {
65 	int8_t		qs_version;		/* version for future changes */
66 	uint8_t		qs_pad1;		/* pad for 16bit alignment */
67 	uint16_t	qs_flags;		/* XFS_QUOTA_.* flags */
68 	uint32_t	qs_incoredqs;		/* number of dquots incore */
69 	struct fs_qfilestatv	qs_uquota;	/* user quota information */
70 	struct fs_qfilestatv	qs_gquota;	/* group quota information */
71 	struct fs_qfilestatv	qs_pquota;	/* project quota information */
72 	int32_t		qs_btimelimit;		/* limit for blks timer */
73 	int32_t		qs_itimelimit;		/* limit for inodes timer */
74 	int32_t		qs_rtbtimelimit;	/* limit for rt blks timer */
75 	uint16_t	qs_bwarnlimit;		/* limit for num warnings */
76 	uint16_t	qs_iwarnlimit;		/* limit for num warnings */
77 	uint64_t	qs_pad2[8];		/* for future proofing */
78 };
79 
80 # endif /* !Q_XGETQSTATV */
81 
82 # include "xlat.h"
83 # include "xlat/xfs_dqblk_flags.h"
84 # if VERBOSE
85 #  include "xlat/xfs_quota_flags.h"
86 # endif
87 
88 
89 void
print_xdisk_quota(int rc,void * ptr,void * arg)90 print_xdisk_quota(int rc, void *ptr, void *arg)
91 {
92 	struct fs_disk_quota *dq = ptr;
93 	long out_arg = (long) arg;
94 
95 	if (((rc < 0) && out_arg) || (out_arg > 1)) {
96 		printf("%p", dq);
97 		return;
98 	}
99 
100 	PRINT_FIELD_D("{", *dq, d_version);
101 	printf(", d_flags=");
102 	printflags(xfs_dqblk_flags, (uint8_t) dq->d_flags, "XFS_???_QUOTA");
103 
104 	PRINT_FIELD_X(", ", *dq, d_fieldmask);
105 	PRINT_FIELD_U(", ", *dq, d_id);
106 	PRINT_FIELD_U(", ", *dq, d_blk_hardlimit);
107 	PRINT_FIELD_U(", ", *dq, d_blk_softlimit);
108 	PRINT_FIELD_U(", ", *dq, d_ino_hardlimit);
109 	PRINT_FIELD_U(", ", *dq, d_ino_softlimit);
110 	PRINT_FIELD_U(", ", *dq, d_bcount);
111 	PRINT_FIELD_U(", ", *dq, d_icount);
112 
113 # if VERBOSE
114 	PRINT_FIELD_D(", ", *dq, d_itimer);
115 	PRINT_FIELD_D(", ", *dq, d_btimer);
116 	PRINT_FIELD_U(", ", *dq, d_iwarns);
117 	PRINT_FIELD_U(", ", *dq, d_bwarns);
118 	PRINT_FIELD_U(", ", *dq, d_rtb_hardlimit);
119 	PRINT_FIELD_U(", ", *dq, d_rtb_softlimit);
120 	PRINT_FIELD_U(", ", *dq, d_rtbcount);
121 	PRINT_FIELD_D(", ", *dq, d_rtbtimer);
122 	PRINT_FIELD_U(", ", *dq, d_rtbwarns);
123 # else
124 	printf(", ...");
125 # endif /* !VERBOSE */
126 	printf("}");
127 }
128 
129 void
print_xquota_stat(int rc,void * ptr,void * arg)130 print_xquota_stat(int rc, void *ptr, void *arg)
131 {
132 	struct fs_quota_stat *qs = ptr;
133 	long out_arg = (long) arg;
134 
135 	if (((rc < 0) && out_arg) || (out_arg > 1)) {
136 		printf("%p", qs);
137 		return;
138 	}
139 
140 	PRINT_FIELD_D("{", *qs, qs_version);
141 
142 # if VERBOSE
143 	printf(", qs_flags=");
144 	printflags(xfs_quota_flags, qs->qs_flags, "XFS_QUOTA_???");
145 	PRINT_FIELD_U(", qs_uquota={", qs->qs_uquota, qfs_ino);
146 	PRINT_FIELD_U(", ", qs->qs_uquota, qfs_nblks);
147 	PRINT_FIELD_U(", ", qs->qs_uquota, qfs_nextents);
148 	PRINT_FIELD_U("}, qs_gquota={", qs->qs_gquota, qfs_ino);
149 	PRINT_FIELD_U(", ", qs->qs_gquota, qfs_nblks);
150 	PRINT_FIELD_U(", ", qs->qs_gquota, qfs_nextents);
151 	PRINT_FIELD_U("}, ", *qs, qs_incoredqs);
152 	PRINT_FIELD_D(", ", *qs, qs_btimelimit);
153 	PRINT_FIELD_D(", ", *qs, qs_itimelimit);
154 	PRINT_FIELD_D(", ", *qs, qs_rtbtimelimit);
155 	PRINT_FIELD_U(", ", *qs, qs_bwarnlimit);
156 	PRINT_FIELD_U(", ", *qs, qs_iwarnlimit);
157 # else
158 	printf(", ...");
159 # endif /* !VERBOSE */
160 	printf("}");
161 }
162 
163 void
print_xquota_statv(int rc,void * ptr,void * arg)164 print_xquota_statv(int rc, void *ptr, void *arg)
165 {
166 	struct fs_quota_statv *qs = ptr;
167 	long out_arg = (long) arg;
168 
169 	if (((rc < 0) && out_arg) || (out_arg > 1)) {
170 		printf("%p", qs);
171 		return;
172 	}
173 
174 	PRINT_FIELD_D("{", *qs, qs_version);
175 
176 # if VERBOSE
177 	printf(", qs_flags=");
178 	printflags(xfs_quota_flags, qs->qs_flags, "XFS_QUOTA_???");
179 	PRINT_FIELD_U(", ", *qs, qs_incoredqs);
180 	PRINT_FIELD_U(", qs_uquota={", qs->qs_uquota, qfs_ino);
181 	PRINT_FIELD_U(", ", qs->qs_uquota, qfs_nblks);
182 	PRINT_FIELD_U(", ", qs->qs_uquota, qfs_nextents);
183 	PRINT_FIELD_U("}, qs_gquota={", qs->qs_gquota, qfs_ino);
184 	PRINT_FIELD_U(", ", qs->qs_gquota, qfs_nblks);
185 	PRINT_FIELD_U(", ", qs->qs_gquota, qfs_nextents);
186 	PRINT_FIELD_U("}, qs_pquota={", qs->qs_pquota, qfs_ino);
187 	PRINT_FIELD_U(", ", qs->qs_pquota, qfs_nblks);
188 	PRINT_FIELD_U(", ", qs->qs_pquota, qfs_nextents);
189 	PRINT_FIELD_D("}, ", *qs, qs_btimelimit);
190 	PRINT_FIELD_D(", ", *qs, qs_itimelimit);
191 	PRINT_FIELD_D(", ", *qs, qs_rtbtimelimit);
192 	PRINT_FIELD_U(", ", *qs, qs_bwarnlimit);
193 	PRINT_FIELD_U(", ", *qs, qs_iwarnlimit);
194 # else
195 	printf(", ...");
196 # endif /* !VERBOSE */
197 	printf("}");
198 }
199 
200 int
main(void)201 main(void)
202 {
203 	char *bogus_special = (char *) tail_alloc(1) + 1;
204 	void *bogus_addr = (char *) tail_alloc(1) + 1;
205 
206 	char bogus_special_str[sizeof(void *) * 2 + sizeof("0x")];
207 	char bogus_addr_str[sizeof(void *) * 2 + sizeof("0x")];
208 	char unterminated_str[sizeof(void *) * 2 + sizeof("0x")];
209 
210 	static char invalid_cmd_str[1024];
211 	TAIL_ALLOC_OBJECT_CONST_PTR(struct fs_disk_quota, xdq);
212 	TAIL_ALLOC_OBJECT_CONST_PTR(struct fs_quota_stat, xqstat);
213 	TAIL_ALLOC_OBJECT_CONST_PTR(struct fs_quota_statv, xqstatv);
214 	TAIL_ALLOC_OBJECT_CONST_PTR(uint32_t, flags);
215 	char *unterminated = tail_memdup(unterminated_data,
216 					 sizeof(unterminated_data));
217 
218 	snprintf(bogus_special_str, sizeof(bogus_special_str), "%p",
219 		 bogus_special);
220 	snprintf(bogus_addr_str, sizeof(bogus_addr_str), "%p",
221 		 bogus_addr);
222 	snprintf(unterminated_str, sizeof(unterminated_str), "%p",
223 		 unterminated);
224 
225 
226 	/* Q_XQUOTAON */
227 
228 	*flags = 0xdeadbeef;
229 
230 	check_quota(CQF_ID_SKIP | CQF_ADDR_STR,
231 		    ARG_STR(QCMD(Q_XQUOTAON, USRQUOTA)),
232 		    ARG_STR("/dev/bogus/"), flags,
233 		    "[XFS_QUOTA_UDQ_ACCT|XFS_QUOTA_UDQ_ENFD"
234 		    "|XFS_QUOTA_GDQ_ACCT|XFS_QUOTA_GDQ_ENFD"
235 		    "|XFS_QUOTA_PDQ_ENFD|0xdeadbec0]");
236 
237 	snprintf(invalid_cmd_str, sizeof(invalid_cmd_str),
238 		 "QCMD(Q_XQUOTAON, %#x /* ???QUOTA */)",
239 		 QCMD_TYPE(QCMD(Q_XQUOTAON, 0xfacefeed)));
240 	check_quota(CQF_ID_SKIP,
241 		    QCMD(Q_XQUOTAON, 0xfacefeed), invalid_cmd_str,
242 		    bogus_dev, bogus_dev_str, bogus_addr);
243 
244 
245 	/* Q_XQUOTAOFF */
246 
247 	check_quota(CQF_ID_SKIP | CQF_ADDR_STR,
248 		    ARG_STR(QCMD(Q_XQUOTAOFF, USRQUOTA)),
249 		    bogus_special, bogus_special_str,
250 		    bogus_addr, bogus_addr_str);
251 	check_quota(CQF_ID_SKIP | CQF_ADDR_STR,
252 		    ARG_STR(QCMD(Q_XQUOTAOFF, GRPQUOTA)),
253 		    ARG_STR("/dev/bogus/"),
254 		    ARG_STR(NULL));
255 	check_quota(CQF_ID_SKIP | CQF_ADDR_STR,
256 		    QCMD(Q_XQUOTAOFF, 3),
257 		    "QCMD(Q_XQUOTAOFF, 0x3 /* ???QUOTA */)",
258 		    ARG_STR("/dev/bogus/"), flags,
259 		    "[XFS_QUOTA_UDQ_ACCT|XFS_QUOTA_UDQ_ENFD"
260 		    "|XFS_QUOTA_GDQ_ACCT|XFS_QUOTA_GDQ_ENFD"
261 		    "|XFS_QUOTA_PDQ_ENFD|0xdeadbec0]");
262 
263 
264 	/* Q_XGETQUOTA */
265 
266 	/* Trying our best to get successful result */
267 	check_quota(CQF_ADDR_CB, ARG_STR(QCMD(Q_XGETQUOTA, USRQUOTA)),
268 		    ARG_STR("/dev/sda1"), getuid(), xdq, print_xdisk_quota,
269 		    (intptr_t) 1);
270 
271 	check_quota(CQF_ADDR_CB, ARG_STR(QCMD(Q_XGETQUOTA, GRPQUOTA)),
272 		    ARG_STR(NULL), -1, xdq, print_xdisk_quota, (intptr_t) 1);
273 
274 
275 	/* Q_XGETNEXTQUOTA */
276 
277 	check_quota(CQF_ADDR_CB, ARG_STR(QCMD(Q_XGETNEXTQUOTA, USRQUOTA)),
278 		    ARG_STR("/dev/sda1"), 0, xdq, print_xdisk_quota,
279 		    (intptr_t) 1);
280 
281 
282 	/* Q_XSETQLIM */
283 
284 	check_quota(CQF_NONE, ARG_STR(QCMD(Q_XSETQLIM, PRJQUOTA)),
285 		    bogus_special, bogus_special_str, 0, bogus_addr);
286 
287 	fill_memory_ex(xdq, sizeof(*xdq), 0x8e, 0x80);
288 
289 	check_quota(CQF_ADDR_CB, ARG_STR(QCMD(Q_XSETQLIM, PRJQUOTA)),
290 		    bogus_dev, bogus_dev_str, 3141592653U,
291 		    xdq, print_xdisk_quota, (intptr_t) 0);
292 
293 
294 	/* Q_XGETQSTAT */
295 
296 	check_quota(CQF_ID_SKIP | CQF_ADDR_CB,
297 		    ARG_STR(QCMD(Q_XGETQSTAT, USRQUOTA)),
298 		    ARG_STR("/dev/sda1"), xqstat, print_xquota_stat, (intptr_t) 1);
299 
300 	check_quota(CQF_ID_SKIP | CQF_ADDR_CB,
301 		    ARG_STR(QCMD(Q_XGETQSTAT, USRQUOTA)),
302 		    ARG_STR("NULL"), xqstat, print_xquota_stat, (intptr_t) 1);
303 
304 	check_quota(CQF_ID_SKIP,
305 		    ARG_STR(QCMD(Q_XGETQSTAT, PRJQUOTA)),
306 		    unterminated, unterminated_str,
307 		    xqstat + 1);
308 
309 
310 	/* Q_XGETQSTATV */
311 
312 	check_quota(CQF_ID_SKIP | CQF_ADDR_CB,
313 		    ARG_STR(QCMD(Q_XGETQSTATV, USRQUOTA)),
314 		    ARG_STR("/dev/sda1"), xqstatv, print_xquota_statv, (intptr_t) 1);
315 
316 	check_quota(CQF_ID_SKIP | CQF_ADDR_CB,
317 		    ARG_STR(QCMD(Q_XGETQSTATV, GRPQUOTA)),
318 		    ARG_STR(NULL), xqstatv, print_xquota_statv, (intptr_t) 1);
319 
320 	check_quota(CQF_ID_SKIP,
321 		    ARG_STR(QCMD(Q_XGETQSTATV, PRJQUOTA)),
322 		    unterminated, unterminated_str,
323 		    xqstatv + 1);
324 
325 
326 	/* Q_XQUOTARM */
327 
328 	check_quota(CQF_ID_SKIP | CQF_ADDR_STR,
329 		    ARG_STR(QCMD(Q_XQUOTARM, PRJQUOTA)),
330 		    bogus_special, bogus_special_str, ARG_STR(NULL));
331 	check_quota(CQF_ID_SKIP,
332 		    ARG_STR(QCMD(Q_XQUOTARM, USRQUOTA)),
333 		    unterminated, unterminated_str, flags + 1);
334 
335 	*flags = 0xdeadbeef;
336 	check_quota(CQF_ID_SKIP | CQF_ADDR_STR,
337 		    ARG_STR(QCMD(Q_XQUOTARM, GRPQUOTA)),
338 		    ARG_STR(NULL), flags,
339 		    "[XFS_USER_QUOTA|XFS_PROJ_QUOTA"
340 		    "|XFS_GROUP_QUOTA|0xdeadbee8]");
341 
342 
343 	/* Q_XQUOTASYNC */
344 
345 	check_quota(CQF_ID_SKIP | CQF_ADDR_SKIP,
346 		    ARG_STR(QCMD(Q_XQUOTASYNC, USRQUOTA)),
347 		    bogus_special, bogus_special_str);
348 	check_quota(CQF_ID_SKIP | CQF_ADDR_SKIP,
349 		    QCMD(Q_XQUOTASYNC, 0xfff),
350 		    "QCMD(Q_XQUOTASYNC, 0xff /* ???QUOTA */)",
351 		    ARG_STR(NULL));
352 
353 	puts("+++ exited with 0 +++");
354 
355 	return 0;
356 }
357 
358 #else
359 
360 SKIP_MAIN_UNDEFINED("__NR_quotactl && "
361 	"(HAVE_LINUX_QUOTA_H || HAVE_SYS_QUOTA_H) && "
362 	"HAVE_LINUX_DQBLK_XFS_H");
363 
364 #endif
365