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 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31#include "tests.h" 32 33#include <asm/unistd.h> 34 35#if defined(__NR_quotactl) && \ 36 (defined(HAVE_LINUX_QUOTA_H) || defined(HAVE_SYS_QUOTA_H)) 37 38# include <inttypes.h> 39# include <stdint.h> 40# include <stdio.h> 41# include <string.h> 42# include <unistd.h> 43 44# include "quotactl.h" 45 46# ifndef HAVE_LINUX_QUOTA_H 47/* Some dirty hacks in order to make sys/quota.h usable as a backup */ 48 49# define if_dqblk dqblk 50# define if_nextdqblk nextdqblk 51# define if_dqinfo dqinfo 52 53# endif /* !HAVE_LINUX_QUOTA_H */ 54 55# ifndef Q_GETNEXTQUOTA 56 57# define Q_GETNEXTQUOTA 0x800009 58 59struct if_nextdqblk { 60 uint64_t dqb_bhardlimit; 61 uint64_t dqb_bsoftlimit; 62 uint64_t dqb_curspace; 63 uint64_t dqb_ihardlimit; 64 uint64_t dqb_isoftlimit; 65 uint64_t dqb_curinodes; 66 uint64_t dqb_btime; 67 uint64_t dqb_itime; 68 uint32_t dqb_valid; 69 uint32_t dqb_id; 70}; 71# endif /* !Q_GETNEXTQUOTA */ 72 73# include "xlat.h" 74# include "xlat/quota_formats.h" 75# include "xlat/if_dqblk_valid.h" 76# include "xlat/if_dqinfo_flags.h" 77# include "xlat/if_dqinfo_valid.h" 78 79void 80print_dqblk(long rc, void *ptr, void *arg) 81{ 82 struct if_dqblk *db = ptr; 83 long out_arg = (long) arg; 84 85 if (((rc != 0) && out_arg) || (out_arg > 1)) { 86 printf("%p", db); 87 return; 88 } 89 90 PRINT_FIELD_U("{", db, dqb_bhardlimit); 91 PRINT_FIELD_U(", ", db, dqb_bsoftlimit); 92 PRINT_FIELD_U(", ", db, dqb_curspace); 93 PRINT_FIELD_U(", ", db, dqb_ihardlimit); 94 PRINT_FIELD_U(", ", db, dqb_isoftlimit); 95 PRINT_FIELD_U(", ", db, dqb_curinodes); 96 97# if VERBOSE 98 PRINT_FIELD_U(", ", db, dqb_btime); 99 PRINT_FIELD_U(", ", db, dqb_itime); 100 101 printf(", dqb_valid="); 102 printflags(if_dqblk_valid, db->dqb_valid, "QIF_???"); 103# else 104 printf(", ..."); 105# endif /* !VERBOSE */ 106 printf("}"); 107} 108 109void 110print_nextdqblk(long rc, void *ptr, void *arg) 111{ 112 struct if_nextdqblk *db = ptr; 113 long out_arg = (long) arg; 114 115 if (((rc != 0) && out_arg) || (out_arg > 1)) { 116 printf("%p", db); 117 return; 118 } 119 120 PRINT_FIELD_U("{", db, dqb_bhardlimit); 121 PRINT_FIELD_U(", ", db, dqb_bsoftlimit); 122 PRINT_FIELD_U(", ", db, dqb_curspace); 123 PRINT_FIELD_U(", ", db, dqb_ihardlimit); 124 PRINT_FIELD_U(", ", db, dqb_isoftlimit); 125 PRINT_FIELD_U(", ", db, dqb_curinodes); 126 127# if VERBOSE 128 PRINT_FIELD_U(", ", db, dqb_btime); 129 PRINT_FIELD_U(", ", db, dqb_itime); 130 131 printf(", dqb_valid="); 132 printflags(if_dqblk_valid, db->dqb_valid, "QIF_???"); 133 134 PRINT_FIELD_U(", ", db, dqb_id); 135# else 136 PRINT_FIELD_U(", ", db, dqb_id); 137 printf(", ..."); 138# endif /* !VERBOSE */ 139 printf("}"); 140} 141 142void 143print_dqinfo(long rc, void *ptr, void *arg) 144{ 145 struct if_dqinfo *di = ptr; 146 long out_arg = (long) arg; 147 148 if (((rc != 0) && out_arg) || (out_arg > 1)) { 149 printf("%p", di); 150 return; 151 } 152 153 PRINT_FIELD_U("{", di, dqi_bgrace); 154 PRINT_FIELD_U(", ", di, dqi_igrace); 155 156 printf(", dqi_flags="); 157 printflags(if_dqinfo_flags, di->dqi_flags, "DQF_???"); 158 printf(", dqi_valid="); 159 printflags(if_dqinfo_valid, di->dqi_valid, "IIF_???"); 160 printf("}"); 161} 162 163 164int 165main(void) 166{ 167 char *bogus_special = (char *) tail_alloc(1) + 1; 168 void *bogus_addr = (char *) tail_alloc(1) + 1; 169 170 char bogus_special_str[sizeof(void *) * 2 + sizeof("0x")]; 171 char unterminated_str[sizeof(void *) * 2 + sizeof("0x")]; 172 173 long rc; 174 char *unterminated = tail_memdup(unterminated_data, 175 sizeof(unterminated_data)); 176 struct if_dqblk *dqblk = tail_alloc(sizeof(*dqblk)); 177 struct if_dqinfo *dqinfo = tail_alloc(sizeof(*dqinfo)); 178 uint32_t *fmt = tail_alloc(sizeof(*fmt)); 179 struct if_nextdqblk *nextdqblk = tail_alloc(sizeof(*nextdqblk)); 180 181 182 snprintf(bogus_special_str, sizeof(bogus_special_str), "%p", 183 bogus_special); 184 snprintf(unterminated_str, sizeof(unterminated_str), "%p", 185 unterminated); 186 187 188 /* Invalid commands */ 189 190 rc = syscall(__NR_quotactl, bogus_cmd, bogus_special, bogus_id, 191 bogus_addr); 192 printf("quotactl(QCMD(%#x /* Q_??? */, %#x /* ???QUOTA */)" 193 ", %p, %u, %p) = %s\n", 194 QCMD_CMD(bogus_cmd), QCMD_TYPE(bogus_cmd), 195 bogus_special, bogus_id, bogus_addr, sprintrc(rc)); 196 197 rc = syscall(__NR_quotactl, 0, NULL, -1, NULL); 198 printf("quotactl(QCMD(0 /* Q_??? */, USRQUOTA), NULL, -1, NULL) = %s\n", 199 sprintrc(rc)); 200 201 202 /* Q_QUOTAON */ 203 204 check_quota(CQF_ID_STR | CQF_ADDR_STR, 205 ARG_STR(QCMD(Q_QUOTAON, USRQUOTA)), 206 ARG_STR("/dev/bogus/"), ARG_STR(QFMT_VFS_OLD), 207 ARG_STR("/tmp/bogus/")); 208 209 rc = syscall(__NR_quotactl, QCMD(Q_QUOTAON, 0xfacefeed), bogus_dev, 210 bogus_id, bogus_addr); 211 printf("quotactl(QCMD(Q_QUOTAON, %#x /* ???QUOTA */)" 212 ", %s, %#x /* QFMT_VFS_??? */, %p) = %s\n", 213 QCMD_TYPE(QCMD(Q_QUOTAON, 0xfacefeed)), 214 bogus_dev_str, bogus_id, bogus_addr, sprintrc(rc)); 215 216 217 /* Q_QUOTAOFF */ 218 219 check_quota(CQF_ID_SKIP | CQF_ADDR_SKIP, 220 ARG_STR(QCMD(Q_QUOTAOFF, USRQUOTA)), 221 bogus_special, bogus_special_str); 222 check_quota(CQF_ID_SKIP | CQF_ADDR_SKIP, 223 ARG_STR(QCMD(Q_QUOTAOFF, GRPQUOTA)), 224 ARG_STR("/dev/bogus/")); 225 check_quota(CQF_ID_SKIP | CQF_ADDR_SKIP, 226 ARG_STR(QCMD(Q_QUOTAOFF, PRJQUOTA)), ARG_STR(NULL)); 227 check_quota(CQF_ID_SKIP | CQF_ADDR_SKIP, 228 QCMD(Q_QUOTAOFF, 3), "QCMD(Q_QUOTAOFF, 0x3 /* ???QUOTA */)", 229 ARG_STR(NULL)); 230 231 232 /* Q_GETQUOTA */ 233 234 /* Trying our best to get successful result */ 235 check_quota(CQF_ADDR_CB, ARG_STR(QCMD(Q_GETQUOTA, USRQUOTA)), 236 ARG_STR("/dev/sda1"), getuid(), dqblk, print_dqblk, 237 (intptr_t) 1); 238 239 check_quota(CQF_ADDR_CB, ARG_STR(QCMD(Q_GETQUOTA, GRPQUOTA)), 240 ARG_STR(NULL), -1, dqblk, print_dqblk, (intptr_t) 2); 241 242 243 /* Q_GETNEXTQUOTA */ 244 245 check_quota(CQF_ADDR_CB, ARG_STR(QCMD(Q_GETNEXTQUOTA, USRQUOTA)), 246 ARG_STR("/dev/sda1"), 0, nextdqblk, print_nextdqblk, 247 (intptr_t) 1); 248 249 250 /* Q_SETQUOTA */ 251 252 fill_memory(dqblk, sizeof(*dqblk)); 253 254 check_quota(CQF_NONE, ARG_STR(QCMD(Q_SETQUOTA, PRJQUOTA)), 255 bogus_special, bogus_special_str, 0, bogus_addr); 256 257 check_quota(CQF_ADDR_CB, ARG_STR(QCMD(Q_SETQUOTA, PRJQUOTA)), 258 ARG_STR("/dev/bogus/"), 3141592653U, dqblk, print_dqblk, 259 (intptr_t) 0); 260 261 262 /* Q_GETINFO */ 263 264 check_quota(CQF_ID_SKIP | CQF_ADDR_CB, 265 ARG_STR(QCMD(Q_GETINFO, GRPQUOTA)), 266 ARG_STR("/dev/sda1"), dqinfo, print_dqinfo, (intptr_t) 1); 267 268 check_quota(CQF_ID_SKIP | CQF_ADDR_CB, 269 ARG_STR(QCMD(Q_GETINFO, GRPQUOTA)), 270 bogus_special, bogus_special_str, dqinfo, 271 print_dqinfo, (intptr_t) 2); 272 273 /* Q_SETINFO */ 274 275 fill_memory(dqinfo, sizeof(*dqinfo)); 276 /* In order to check flag printing correctness */ 277 dqinfo->dqi_flags = 0xdeadabcd; 278 279 check_quota(CQF_ID_SKIP | CQF_ADDR_STR, 280 ARG_STR(QCMD(Q_SETINFO, PRJQUOTA)), 281 bogus_special, bogus_special_str, ARG_STR(NULL)); 282 283 check_quota(CQF_ID_SKIP | CQF_ADDR_CB, 284 ARG_STR(QCMD(Q_SETINFO, USRQUOTA)), 285 ARG_STR("/dev/bogus/"), dqinfo, print_dqinfo, (intptr_t) 0); 286 287 288 /* Q_GETFMT */ 289 290 check_quota(CQF_ID_SKIP | CQF_ADDR_STR, 291 ARG_STR(QCMD(Q_GETFMT, PRJQUOTA)), 292 bogus_special, bogus_special_str, ARG_STR(NULL)); 293 check_quota(CQF_ID_SKIP, 294 ARG_STR(QCMD(Q_GETFMT, USRQUOTA)), 295 unterminated, unterminated_str, fmt + 1); 296 check_quota(CQF_ID_SKIP, 297 ARG_STR(QCMD(Q_GETFMT, GRPQUOTA)), 298 ARG_STR("/dev/sda1"), fmt); 299 300 301 /* Q_SYNC */ 302 303 check_quota(CQF_ID_SKIP | CQF_ADDR_SKIP, 304 ARG_STR(QCMD(Q_SYNC, USRQUOTA)), 305 bogus_special, bogus_special_str); 306 check_quota(CQF_ID_SKIP | CQF_ADDR_SKIP, 307 QCMD(Q_SYNC, 0xfff), "QCMD(Q_SYNC, 0xff /* ???QUOTA */)", 308 ARG_STR(NULL)); 309 310 puts("+++ exited with 0 +++"); 311 312 return 0; 313} 314 315#else 316 317SKIP_MAIN_UNDEFINED("__NR_quotactl && " 318 "(HAVE_LINUX_QUOTA_H || HAVE_SYS_QUOTA_H)"); 319 320#endif 321