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 * 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 defined(HAVE_LINUX_DQBLK_XFS_H) 38 39# include <stdio.h> 40# include <string.h> 41# include <unistd.h> 42 43# include <linux/dqblk_xfs.h> 44 45# include "quotactl.h" 46 47# ifndef Q_GETNEXTQUOTA 48# define Q_XGETNEXTQUOTA XQM_CMD(0x9) 49# endif /* !Q_GETNEXTQUOTA */ 50 51# ifndef Q_XGETQSTATV 52 53# define Q_XGETQSTATV XQM_CMD(8) 54# define FS_QSTATV_VERSION1 1 55 56struct fs_qfilestatv { 57 uint64_t qfs_ino; /* inode number */ 58 uint64_t qfs_nblks; /* number of BBs 512-byte-blks */ 59 uint32_t qfs_nextents; /* number of extents */ 60 uint32_t qfs_pad; /* pad for 8-byte alignment */ 61}; 62 63struct fs_quota_statv { 64 int8_t qs_version; /* version for future changes */ 65 uint8_t qs_pad1; /* pad for 16bit alignment */ 66 uint16_t qs_flags; /* XFS_QUOTA_.* flags */ 67 uint32_t qs_incoredqs; /* number of dquots incore */ 68 struct fs_qfilestatv qs_uquota; /* user quota information */ 69 struct fs_qfilestatv qs_gquota; /* group quota information */ 70 struct fs_qfilestatv qs_pquota; /* project quota information */ 71 int32_t qs_btimelimit; /* limit for blks timer */ 72 int32_t qs_itimelimit; /* limit for inodes timer */ 73 int32_t qs_rtbtimelimit; /* limit for rt blks timer */ 74 uint16_t qs_bwarnlimit; /* limit for num warnings */ 75 uint16_t qs_iwarnlimit; /* limit for num warnings */ 76 uint64_t qs_pad2[8]; /* for future proofing */ 77}; 78 79# endif /* !Q_XGETQSTATV */ 80 81# include "xlat.h" 82# include "xlat/xfs_dqblk_flags.h" 83# if VERBOSE 84# include "xlat/xfs_quota_flags.h" 85# endif 86 87 88void 89print_xdisk_quota(int rc, void *ptr, void *arg) 90{ 91 struct fs_disk_quota *dq = ptr; 92 long out_arg = (long) arg; 93 94 if (((rc != 0) && out_arg) || (out_arg > 1)) { 95 printf("%p", dq); 96 return; 97 } 98 99 PRINT_FIELD_D("{", dq, d_version); 100 printf(", d_flags="); 101 printflags(xfs_dqblk_flags, (uint8_t) dq->d_flags, "XFS_???_QUOTA"); 102 103 PRINT_FIELD_X(", ", dq, d_fieldmask); 104 PRINT_FIELD_U(", ", dq, d_id); 105 PRINT_FIELD_U(", ", dq, d_blk_hardlimit); 106 PRINT_FIELD_U(", ", dq, d_blk_softlimit); 107 PRINT_FIELD_U(", ", dq, d_ino_hardlimit); 108 PRINT_FIELD_U(", ", dq, d_ino_softlimit); 109 PRINT_FIELD_U(", ", dq, d_bcount); 110 PRINT_FIELD_U(", ", dq, d_icount); 111 112# if VERBOSE 113 PRINT_FIELD_D(", ", dq, d_itimer); 114 PRINT_FIELD_D(", ", dq, d_btimer); 115 PRINT_FIELD_U(", ", dq, d_iwarns); 116 PRINT_FIELD_U(", ", dq, d_bwarns); 117 PRINT_FIELD_U(", ", dq, d_rtb_hardlimit); 118 PRINT_FIELD_U(", ", dq, d_rtb_softlimit); 119 PRINT_FIELD_U(", ", dq, d_rtbcount); 120 PRINT_FIELD_D(", ", dq, d_rtbtimer); 121 PRINT_FIELD_U(", ", dq, d_rtbwarns); 122# else 123 printf(", ..."); 124# endif /* !VERBOSE */ 125 printf("}"); 126} 127 128void 129print_xquota_stat(int rc, void *ptr, void *arg) 130{ 131 struct fs_quota_stat *qs = ptr; 132 long out_arg = (long) arg; 133 134 if (((rc != 0) && out_arg) || (out_arg > 1)) { 135 printf("%p", qs); 136 return; 137 } 138 139 PRINT_FIELD_D("{", qs, qs_version); 140 141# if VERBOSE 142 printf(", qs_flags="); 143 printflags(xfs_quota_flags, qs->qs_flags, "XFS_QUOTA_???"); 144 PRINT_FIELD_U(", qs_uquota={", &qs->qs_uquota, qfs_ino); 145 PRINT_FIELD_U(", ", &qs->qs_uquota, qfs_nblks); 146 PRINT_FIELD_U(", ", &qs->qs_uquota, qfs_nextents); 147 PRINT_FIELD_U("}, qs_gquota={", &qs->qs_gquota, qfs_ino); 148 PRINT_FIELD_U(", ", &qs->qs_gquota, qfs_nblks); 149 PRINT_FIELD_U(", ", &qs->qs_gquota, qfs_nextents); 150 PRINT_FIELD_U("}, ", qs, qs_incoredqs); 151 PRINT_FIELD_D(", ", qs, qs_btimelimit); 152 PRINT_FIELD_D(", ", qs, qs_itimelimit); 153 PRINT_FIELD_D(", ", qs, qs_rtbtimelimit); 154 PRINT_FIELD_U(", ", qs, qs_bwarnlimit); 155 PRINT_FIELD_U(", ", qs, qs_iwarnlimit); 156# else 157 printf(", ..."); 158# endif /* !VERBOSE */ 159 printf("}"); 160} 161 162void 163print_xquota_statv(int rc, void *ptr, void *arg) 164{ 165 struct fs_quota_statv *qs = ptr; 166 long out_arg = (long) arg; 167 168 if (((rc != 0) && out_arg) || (out_arg > 1)) { 169 printf("%p", qs); 170 return; 171 } 172 173 PRINT_FIELD_D("{", qs, qs_version); 174 175# if VERBOSE 176 printf(", qs_flags="); 177 printflags(xfs_quota_flags, qs->qs_flags, "XFS_QUOTA_???"); 178 PRINT_FIELD_U(", ", qs, qs_incoredqs); 179 PRINT_FIELD_U(", qs_uquota={", &qs->qs_uquota, qfs_ino); 180 PRINT_FIELD_U(", ", &qs->qs_uquota, qfs_nblks); 181 PRINT_FIELD_U(", ", &qs->qs_uquota, qfs_nextents); 182 PRINT_FIELD_U("}, qs_gquota={", &qs->qs_gquota, qfs_ino); 183 PRINT_FIELD_U(", ", &qs->qs_gquota, qfs_nblks); 184 PRINT_FIELD_U(", ", &qs->qs_gquota, qfs_nextents); 185 PRINT_FIELD_U("}, qs_pquota={", &qs->qs_pquota, qfs_ino); 186 PRINT_FIELD_U(", ", &qs->qs_pquota, qfs_nblks); 187 PRINT_FIELD_U(", ", &qs->qs_pquota, qfs_nextents); 188 PRINT_FIELD_D("}, ", qs, qs_btimelimit); 189 PRINT_FIELD_D(", ", qs, qs_itimelimit); 190 PRINT_FIELD_D(", ", qs, qs_rtbtimelimit); 191 PRINT_FIELD_U(", ", qs, qs_bwarnlimit); 192 PRINT_FIELD_U(", ", qs, qs_iwarnlimit); 193# else 194 printf(", ..."); 195# endif /* !VERBOSE */ 196 printf("}"); 197} 198 199int 200main(void) 201{ 202 char *bogus_special = (char *) tail_alloc(1) + 1; 203 void *bogus_addr = (char *) tail_alloc(1) + 1; 204 205 char bogus_special_str[sizeof(void *) * 2 + sizeof("0x")]; 206 char bogus_addr_str[sizeof(void *) * 2 + sizeof("0x")]; 207 char unterminated_str[sizeof(void *) * 2 + sizeof("0x")]; 208 209 long rc; 210 struct fs_disk_quota *xdq = tail_alloc(sizeof(*xdq)); 211 struct fs_quota_stat *xqstat = tail_alloc(sizeof(*xqstat)); 212 struct fs_quota_statv *xqstatv = tail_alloc(sizeof(*xqstatv)); 213 uint32_t *flags = tail_alloc(sizeof(*flags)); 214 char *unterminated = tail_memdup(unterminated_data, 215 sizeof(unterminated_data)); 216 217 snprintf(bogus_special_str, sizeof(bogus_special_str), "%p", 218 bogus_special); 219 snprintf(bogus_addr_str, sizeof(bogus_addr_str), "%p", 220 bogus_addr); 221 snprintf(unterminated_str, sizeof(unterminated_str), "%p", 222 unterminated); 223 224 225 /* Q_XQUOTAON */ 226 227 *flags = 0xdeadbeef; 228 229 check_quota(CQF_ID_SKIP | CQF_ADDR_STR, 230 ARG_STR(QCMD(Q_XQUOTAON, USRQUOTA)), 231 ARG_STR("/dev/bogus/"), flags, 232 "[XFS_QUOTA_UDQ_ACCT|XFS_QUOTA_UDQ_ENFD" 233 "|XFS_QUOTA_GDQ_ACCT|XFS_QUOTA_GDQ_ENFD" 234 "|XFS_QUOTA_PDQ_ENFD|0xdeadbec0]"); 235 236 rc = syscall(__NR_quotactl, QCMD(Q_XQUOTAON, 0xfacefeed), bogus_dev, 237 bogus_id, bogus_addr); 238 printf("quotactl(QCMD(Q_XQUOTAON, %#x /* ???QUOTA */)" 239 ", %s, %p) = %s\n", 240 QCMD_TYPE(QCMD(Q_XQUOTAON, 0xfacefeed)), 241 bogus_dev_str, bogus_addr, sprintrc(rc)); 242 243 244 /* Q_XQUOTAOFF */ 245 246 check_quota(CQF_ID_SKIP | CQF_ADDR_STR, 247 ARG_STR(QCMD(Q_XQUOTAOFF, USRQUOTA)), 248 bogus_special, bogus_special_str, 249 bogus_addr, bogus_addr_str); 250 check_quota(CQF_ID_SKIP | CQF_ADDR_STR, 251 ARG_STR(QCMD(Q_XQUOTAOFF, GRPQUOTA)), 252 ARG_STR("/dev/bogus/"), 253 ARG_STR(NULL)); 254 check_quota(CQF_ID_SKIP | CQF_ADDR_STR, 255 QCMD(Q_XQUOTAOFF, 3), 256 "QCMD(Q_XQUOTAOFF, 0x3 /* ???QUOTA */)", 257 ARG_STR("/dev/bogus/"), flags, 258 "[XFS_QUOTA_UDQ_ACCT|XFS_QUOTA_UDQ_ENFD" 259 "|XFS_QUOTA_GDQ_ACCT|XFS_QUOTA_GDQ_ENFD" 260 "|XFS_QUOTA_PDQ_ENFD|0xdeadbec0]"); 261 262 263 /* Q_XGETQUOTA */ 264 265 /* Trying our best to get successful result */ 266 check_quota(CQF_ADDR_CB, ARG_STR(QCMD(Q_GETQUOTA, USRQUOTA)), 267 ARG_STR("/dev/sda1"), getuid(), xdq, print_xdisk_quota, 268 (intptr_t) 1); 269 270 check_quota(CQF_ADDR_CB, ARG_STR(QCMD(Q_GETQUOTA, GRPQUOTA)), 271 ARG_STR(NULL), -1, xdq, print_xdisk_quota, (intptr_t) 2); 272 273 274 /* Q_XGETNEXTQUOTA */ 275 276 check_quota(CQF_ADDR_CB, ARG_STR(QCMD(Q_XGETNEXTQUOTA, USRQUOTA)), 277 ARG_STR("/dev/sda1"), 0, xdq, print_xdisk_quota, 278 (intptr_t) 1); 279 280 281 /* Q_XSETQLIM */ 282 283 check_quota(CQF_NONE, ARG_STR(QCMD(Q_XSETQLIM, PRJQUOTA)), 284 bogus_special, bogus_special_str, 0, bogus_addr); 285 286 fill_memory_ex(xdq, sizeof(*xdq), 0x8e, 0x80); 287 288 check_quota(CQF_ADDR_CB, ARG_STR(QCMD(Q_XSETQLIM, PRJQUOTA)), 289 bogus_dev, bogus_dev_str, 3141592653U, 290 xdq, print_xdisk_quota, (intptr_t) 0); 291 292 293 /* Q_XGETQSTAT */ 294 295 check_quota(CQF_ID_SKIP | CQF_ADDR_CB, 296 ARG_STR(QCMD(Q_XGETQSTAT, USRQUOTA)), 297 ARG_STR("/dev/sda1"), xqstat, print_xquota_stat, (intptr_t) 1); 298 299 check_quota(CQF_ID_SKIP | CQF_ADDR_CB, 300 ARG_STR(QCMD(Q_XGETQSTATV, PRJQUOTA)), 301 unterminated, unterminated_str, 302 xqstat + 1, print_xquota_stat, (intptr_t) 2); 303 304 305 /* Q_XGETQSTATV */ 306 307 check_quota(CQF_ID_SKIP | CQF_ADDR_CB, 308 ARG_STR(QCMD(Q_XGETQSTAT, USRQUOTA)), 309 ARG_STR("/dev/sda1"), xqstatv, print_xquota_statv, 1); 310 311 check_quota(CQF_ID_SKIP | CQF_ADDR_CB, 312 ARG_STR(QCMD(Q_XGETQSTATV, GRPQUOTA)), 313 ARG_STR(NULL), xqstatv, print_xquota_statv, (intptr_t) 2); 314 315 316 /* Q_XQUOTARM */ 317 318 check_quota(CQF_ID_SKIP | CQF_ADDR_STR, 319 ARG_STR(QCMD(Q_XQUOTARM, PRJQUOTA)), 320 bogus_special, bogus_special_str, ARG_STR(NULL)); 321 check_quota(CQF_ID_SKIP, 322 ARG_STR(QCMD(Q_XQUOTARM, USRQUOTA)), 323 unterminated, unterminated_str, flags + 1); 324 325 *flags = 0xdeadbeef; 326 check_quota(CQF_ID_SKIP | CQF_ADDR_STR, 327 ARG_STR(QCMD(Q_XQUOTARM, GRPQUOTA)), 328 ARG_STR(NULL), flags, 329 "[XFS_USER_QUOTA|XFS_PROJ_QUOTA" 330 "|XFS_GROUP_QUOTA|0xdeadbee8]"); 331 332 333 /* Q_XQUOTASYNC */ 334 335 check_quota(CQF_ID_SKIP | CQF_ADDR_SKIP, 336 ARG_STR(QCMD(Q_XQUOTASYNC, USRQUOTA)), 337 bogus_special, bogus_special_str); 338 check_quota(CQF_ID_SKIP | CQF_ADDR_SKIP, 339 QCMD(Q_XQUOTASYNC, 0xfff), 340 "QCMD(Q_XQUOTASYNC, 0xff /* ???QUOTA */)", 341 ARG_STR(NULL)); 342 343 puts("+++ exited with 0 +++"); 344 345 return 0; 346} 347 348#else 349 350SKIP_MAIN_UNDEFINED("__NR_quotactl && " 351 "(HAVE_LINUX_QUOTA_H || HAVE_SYS_QUOTA_H) && " 352 "HAVE_LINUX_DQBLK_XFS_H"); 353 354#endif 355