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@altlinux.org> 6 * Copyright (c) 2016-2017 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 39# include <inttypes.h> 40# include <stdint.h> 41# include <stdio.h> 42# include <string.h> 43# include <unistd.h> 44 45# include "quotactl.h" 46 47# ifndef HAVE_LINUX_QUOTA_H 48/* Some dirty hacks in order to make sys/quota.h usable as a backup */ 49 50# define if_dqblk dqblk 51# define if_nextdqblk nextdqblk 52# define if_dqinfo dqinfo 53 54# endif /* !HAVE_LINUX_QUOTA_H */ 55 56# ifndef Q_GETNEXTQUOTA 57 58# define Q_GETNEXTQUOTA 0x800009 59 60struct if_nextdqblk { 61 uint64_t dqb_bhardlimit; 62 uint64_t dqb_bsoftlimit; 63 uint64_t dqb_curspace; 64 uint64_t dqb_ihardlimit; 65 uint64_t dqb_isoftlimit; 66 uint64_t dqb_curinodes; 67 uint64_t dqb_btime; 68 uint64_t dqb_itime; 69 uint32_t dqb_valid; 70 uint32_t dqb_id; 71}; 72# endif /* !Q_GETNEXTQUOTA */ 73 74# include "xlat.h" 75# include "xlat/quota_formats.h" 76# include "xlat/if_dqblk_valid.h" 77# include "xlat/if_dqinfo_flags.h" 78# include "xlat/if_dqinfo_valid.h" 79 80void 81print_dqblk(long rc, void *ptr, void *arg) 82{ 83 struct if_dqblk *db = ptr; 84 long out_arg = (long) arg; 85 86 if (((rc != 0) && out_arg) || (out_arg > 1)) { 87 printf("%p", db); 88 return; 89 } 90 91 PRINT_FIELD_U("{", *db, dqb_bhardlimit); 92 PRINT_FIELD_U(", ", *db, dqb_bsoftlimit); 93 PRINT_FIELD_U(", ", *db, dqb_curspace); 94 PRINT_FIELD_U(", ", *db, dqb_ihardlimit); 95 PRINT_FIELD_U(", ", *db, dqb_isoftlimit); 96 PRINT_FIELD_U(", ", *db, dqb_curinodes); 97 98# if VERBOSE 99 PRINT_FIELD_U(", ", *db, dqb_btime); 100 PRINT_FIELD_U(", ", *db, dqb_itime); 101 102 printf(", dqb_valid="); 103 printflags(if_dqblk_valid, db->dqb_valid, "QIF_???"); 104# else 105 printf(", ..."); 106# endif /* !VERBOSE */ 107 printf("}"); 108} 109 110void 111print_nextdqblk(long rc, void *ptr, void *arg) 112{ 113 struct if_nextdqblk *db = ptr; 114 long out_arg = (long) arg; 115 116 if (((rc != 0) && out_arg) || (out_arg > 1)) { 117 printf("%p", db); 118 return; 119 } 120 121 PRINT_FIELD_U("{", *db, dqb_bhardlimit); 122 PRINT_FIELD_U(", ", *db, dqb_bsoftlimit); 123 PRINT_FIELD_U(", ", *db, dqb_curspace); 124 PRINT_FIELD_U(", ", *db, dqb_ihardlimit); 125 PRINT_FIELD_U(", ", *db, dqb_isoftlimit); 126 PRINT_FIELD_U(", ", *db, dqb_curinodes); 127 128# if VERBOSE 129 PRINT_FIELD_U(", ", *db, dqb_btime); 130 PRINT_FIELD_U(", ", *db, dqb_itime); 131 132 printf(", dqb_valid="); 133 printflags(if_dqblk_valid, db->dqb_valid, "QIF_???"); 134 135 PRINT_FIELD_U(", ", *db, dqb_id); 136# else 137 PRINT_FIELD_U(", ", *db, dqb_id); 138 printf(", ..."); 139# endif /* !VERBOSE */ 140 printf("}"); 141} 142 143void 144print_dqinfo(long rc, void *ptr, void *arg) 145{ 146 struct if_dqinfo *di = ptr; 147 long out_arg = (long) arg; 148 149 if (((rc != 0) && out_arg) || (out_arg > 1)) { 150 printf("%p", di); 151 return; 152 } 153 154 PRINT_FIELD_U("{", *di, dqi_bgrace); 155 PRINT_FIELD_U(", ", *di, dqi_igrace); 156 157 printf(", dqi_flags="); 158 printflags(if_dqinfo_flags, di->dqi_flags, "DQF_???"); 159 printf(", dqi_valid="); 160 printflags(if_dqinfo_valid, di->dqi_valid, "IIF_???"); 161 printf("}"); 162} 163 164 165int 166main(void) 167{ 168 char *bogus_special = (char *) tail_alloc(1) + 1; 169 void *bogus_addr = (char *) tail_alloc(1) + 1; 170 171 char bogus_special_str[sizeof(void *) * 2 + sizeof("0x")]; 172 char unterminated_str[sizeof(void *) * 2 + sizeof("0x")]; 173 174 long rc; 175 char *unterminated = tail_memdup(unterminated_data, 176 sizeof(unterminated_data)); 177 TAIL_ALLOC_OBJECT_CONST_PTR(struct if_dqblk, dqblk); 178 TAIL_ALLOC_OBJECT_CONST_PTR(struct if_dqinfo, dqinfo); 179 TAIL_ALLOC_OBJECT_CONST_PTR(uint32_t, fmt); 180 TAIL_ALLOC_OBJECT_CONST_PTR(struct if_nextdqblk, nextdqblk); 181 182 183 snprintf(bogus_special_str, sizeof(bogus_special_str), "%p", 184 bogus_special); 185 snprintf(unterminated_str, sizeof(unterminated_str), "%p", 186 unterminated); 187 188 189 /* Invalid commands */ 190 191 rc = syscall(__NR_quotactl, bogus_cmd, bogus_special, bogus_id, 192 bogus_addr); 193 printf("quotactl(QCMD(%#x /* Q_??? */, %#x /* ???QUOTA */)" 194 ", %p, %u, %p) = %s\n", 195 QCMD_CMD(bogus_cmd), QCMD_TYPE(bogus_cmd), 196 bogus_special, bogus_id, bogus_addr, sprintrc(rc)); 197 198 rc = syscall(__NR_quotactl, 0, NULL, -1, NULL); 199 printf("quotactl(QCMD(0 /* Q_??? */, USRQUOTA), NULL, -1, NULL) = %s\n", 200 sprintrc(rc)); 201 202 203 /* Q_QUOTAON */ 204 205 check_quota(CQF_ID_STR | CQF_ADDR_STR, 206 ARG_STR(QCMD(Q_QUOTAON, USRQUOTA)), 207 ARG_STR("/dev/bogus/"), ARG_STR(QFMT_VFS_OLD), 208 ARG_STR("/tmp/bogus/")); 209 210 rc = syscall(__NR_quotactl, QCMD(Q_QUOTAON, 0xfacefeed), bogus_dev, 211 bogus_id, bogus_addr); 212 printf("quotactl(QCMD(Q_QUOTAON, %#x /* ???QUOTA */)" 213 ", %s, %#x /* QFMT_VFS_??? */, %p) = %s\n", 214 QCMD_TYPE(QCMD(Q_QUOTAON, 0xfacefeed)), 215 bogus_dev_str, bogus_id, bogus_addr, sprintrc(rc)); 216 217 218 /* Q_QUOTAOFF */ 219 220 check_quota(CQF_ID_SKIP | CQF_ADDR_SKIP, 221 ARG_STR(QCMD(Q_QUOTAOFF, USRQUOTA)), 222 bogus_special, bogus_special_str); 223 check_quota(CQF_ID_SKIP | CQF_ADDR_SKIP, 224 ARG_STR(QCMD(Q_QUOTAOFF, GRPQUOTA)), 225 ARG_STR("/dev/bogus/")); 226 check_quota(CQF_ID_SKIP | CQF_ADDR_SKIP, 227 ARG_STR(QCMD(Q_QUOTAOFF, PRJQUOTA)), ARG_STR(NULL)); 228 check_quota(CQF_ID_SKIP | CQF_ADDR_SKIP, 229 QCMD(Q_QUOTAOFF, 3), "QCMD(Q_QUOTAOFF, 0x3 /* ???QUOTA */)", 230 ARG_STR(NULL)); 231 232 233 /* Q_GETQUOTA */ 234 235 /* Trying our best to get successful result */ 236 check_quota(CQF_ADDR_CB, ARG_STR(QCMD(Q_GETQUOTA, USRQUOTA)), 237 ARG_STR("/dev/sda1"), getuid(), dqblk, print_dqblk, 238 (intptr_t) 1); 239 240 check_quota(CQF_ADDR_CB, ARG_STR(QCMD(Q_GETQUOTA, GRPQUOTA)), 241 ARG_STR(NULL), -1, dqblk, print_dqblk, (intptr_t) 2); 242 243 244 /* Q_GETNEXTQUOTA */ 245 246 check_quota(CQF_ADDR_CB, ARG_STR(QCMD(Q_GETNEXTQUOTA, USRQUOTA)), 247 ARG_STR("/dev/sda1"), 0, nextdqblk, print_nextdqblk, 248 (intptr_t) 1); 249 250 251 /* Q_SETQUOTA */ 252 253 fill_memory(dqblk, sizeof(*dqblk)); 254 255 check_quota(CQF_NONE, ARG_STR(QCMD(Q_SETQUOTA, PRJQUOTA)), 256 bogus_special, bogus_special_str, 0, bogus_addr); 257 258 check_quota(CQF_ADDR_CB, ARG_STR(QCMD(Q_SETQUOTA, PRJQUOTA)), 259 ARG_STR("/dev/bogus/"), 3141592653U, dqblk, print_dqblk, 260 (intptr_t) 0); 261 262 263 /* Q_GETINFO */ 264 265 check_quota(CQF_ID_SKIP | CQF_ADDR_CB, 266 ARG_STR(QCMD(Q_GETINFO, GRPQUOTA)), 267 ARG_STR("/dev/sda1"), dqinfo, print_dqinfo, (intptr_t) 1); 268 269 check_quota(CQF_ID_SKIP | CQF_ADDR_CB, 270 ARG_STR(QCMD(Q_GETINFO, GRPQUOTA)), 271 bogus_special, bogus_special_str, dqinfo, 272 print_dqinfo, (intptr_t) 2); 273 274 /* Q_SETINFO */ 275 276 fill_memory(dqinfo, sizeof(*dqinfo)); 277 /* In order to check flag printing correctness */ 278 dqinfo->dqi_flags = 0xdeadabcd; 279 280 check_quota(CQF_ID_SKIP | CQF_ADDR_STR, 281 ARG_STR(QCMD(Q_SETINFO, PRJQUOTA)), 282 bogus_special, bogus_special_str, ARG_STR(NULL)); 283 284 check_quota(CQF_ID_SKIP | CQF_ADDR_CB, 285 ARG_STR(QCMD(Q_SETINFO, USRQUOTA)), 286 ARG_STR("/dev/bogus/"), dqinfo, print_dqinfo, (intptr_t) 0); 287 288 289 /* Q_GETFMT */ 290 291 check_quota(CQF_ID_SKIP | CQF_ADDR_STR, 292 ARG_STR(QCMD(Q_GETFMT, PRJQUOTA)), 293 bogus_special, bogus_special_str, ARG_STR(NULL)); 294 check_quota(CQF_ID_SKIP, 295 ARG_STR(QCMD(Q_GETFMT, USRQUOTA)), 296 unterminated, unterminated_str, fmt + 1); 297 check_quota(CQF_ID_SKIP, 298 ARG_STR(QCMD(Q_GETFMT, GRPQUOTA)), 299 ARG_STR("/dev/sda1"), fmt); 300 301 302 /* Q_SYNC */ 303 304 check_quota(CQF_ID_SKIP | CQF_ADDR_SKIP, 305 ARG_STR(QCMD(Q_SYNC, USRQUOTA)), 306 bogus_special, bogus_special_str); 307 check_quota(CQF_ID_SKIP | CQF_ADDR_SKIP, 308 QCMD(Q_SYNC, 0xfff), "QCMD(Q_SYNC, 0xff /* ???QUOTA */)", 309 ARG_STR(NULL)); 310 311 puts("+++ exited with 0 +++"); 312 313 return 0; 314} 315 316#else 317 318SKIP_MAIN_UNDEFINED("__NR_quotactl && " 319 "(HAVE_LINUX_QUOTA_H || HAVE_SYS_QUOTA_H)"); 320 321#endif 322