1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2013 Damian Bogel.  All rights reserved.
  14  */
  15 
  16 /*
  17  * Filesystem disturber pseudo-device driver.
  18  */
  19 
  20 #include <sys/conf.h>
  21 #include <sys/ddi.h>
  22 #include <sys/file.h>
  23 #include <sys/fsd.h>
  24 #include <sys/fsh.h>
  25 #include <sys/kmem.h>
  26 #include <sys/ksynch.h>
  27 #include <sys/list.h>
  28 #include <sys/mkdev.h>
  29 #include <sys/stat.h>
  30 #include <sys/sunddi.h>
  31 #include <sys/sysmacros.h>
  32 #include <sys/types.h>
  33 
  34 /*
  35  * fsd - filesystem disturber
  36  *
  37  * 1. Abstract
  38  * Filesystem disturber is a pseudo-device driver used to inject pathological
  39  * behaviour into vfs calls. It is NOT a fuzzer. That kind of behaviour
  40  * should be expected and correctly handled by software. A simple example of
  41  * such behaviour is read() reading less bytes than it was requested. It's
  42  * well documented and every read() caller should check the return value of
  43  * this function before proceeding.
  44  *
  45  * 2. Features
  46  * * per-vfs injections
  47  * * injection installing on every newly mounted vfs
  48  *
  49  * 3. Usage
  50  * A library (libfsd) is provided to drive fsd.
  51  *
  52  * 4. Internals
  53  * fsd_enable() does the necessary fsh callbacks installing.
  54  * These callbacks are used for both installing injections on newly mounted
  55  * vfs' and cleaning up when a vfs is destroyed.
  56  *
  57  * The list of currently installed hooks is kept in fsd_slist.
  58  *
  59  * 5. Locking
  60  * The locking is fairly simple. Every modification of fsd_enable, fsd_hooks,
  61  * fsd_new_stat and fsd_slist is protected by fsd_lock. Hooks use only the
  62  * elements of fsd_slist, nothing else. Before an element of fsd_slist
  63  * is destroyed, a hook which uses it is removed.
  64  *
  65  * Every fsd_slist element is protected by it's own lock.
  66  */
  67 
  68 static dev_info_t       *fsd_devi;
  69 
  70 /* procets: fsd_enabled, fsd_hooks, fsd_new_stat, fsd_slist */
  71 static kmutex_t         fsd_lock;
  72 
  73 /* fsd_stat for new filesystems. Don't do anything if NULL. */
  74 static fsd_stat_t       *fsd_new_stat;
  75 static int              fsd_enabled;
  76 static fsh_t            fsd_hooks;
  77 
  78 /*
  79  * The fsd_slist exist for two purposes.
  80  * 1. It's an argument for hooks.
  81  * 2. For every vfs on which fsd installed a set of hooks there exist exactly
  82  * one entry in fsd_slist.
  83  */
  84 static list_t   fsd_slist;
  85 
  86 /* No need for lock here. It's unchanged between fsd_attach()/fsd_detach(). */
  87 static fsh_callback_t   fsd_callbacks;
  88 
  89 /*
  90  * Although it's safe to use this kind of pseudo-random number generator,
  91  * it behaves very regular when it comes to parity. Every fsd_rand() call
  92  * changes the parity of the seed. That's why when a range of width 2 is set
  93  * as a parameter, it's highly possible that the random value will always be
  94  * the same, because fsd_rand() could be called the same number of times in a
  95  * hook.
  96  */
  97 static long     fsd_rand_seed;
  98 
  99 static int
 100 fsd_rand()
 101 {
 102         fsd_rand_seed = fsd_rand_seed * 1103515245L + 12345;
 103         return (fsd_rand_seed & 0x7ffffffff);
 104 }
 105 
 106 /* vnode hooks */
 107 /*
 108  * A pointer to a given fsd_stat_int_t is valid always inside fsh_hook_xxx()
 109  * call, because it's valid until the hooks associated with it are removed.
 110  * If a hook is removed, it cannot be executing.
 111  */
 112 static int
 113 fsd_hook_read(fsh_int_t *fshi, void *arg, vnode_t *vp, uio_t *uiop,
 114         int ioflag, cred_t *cr, caller_context_t *ct)
 115 {
 116         fsd_stat_int_t  *si;
 117         uint64_t        cnt;
 118         uint64_t        less;
 119         uint64_t        less_chance;
 120 
 121         /*
 122          * It is used to keep an odd number of fsd_rand() calls in every
 123          * fsd_hook_read() call. That is desired because when a range of width
 124          * 2 is set as a parameter, we don't want to make it a constant.
 125          * The pseudo-random number generator returns a number with different
 126          * parity with every call. If this function is called in every
 127          * fsd_hook_read() execution even number of times, it would always be
 128          * the same % 2.
 129          */
 130         (void) fsd_rand();
 131 
 132         si = (fsd_stat_int_t *)arg;
 133         ASSERT(vp->v_vfsp == si->fsdsi_vfsp);
 134 
 135         rw_enter(&si->fsdsi_lock, RW_READER);
 136         less_chance = si->fsdsi_stat.fsds_read_less_chance;
 137         less = (uint64_t)fsd_rand() %
 138             (si->fsdsi_stat.fsds_read_less_r[1] + 1 -
 139             si->fsdsi_stat.fsds_read_less_r[0]) +
 140             si->fsdsi_stat.fsds_read_less_r[0];
 141 
 142         rw_exit(&si->fsdsi_lock);
 143 
 144         cnt = uiop->uio_iov->iov_len;
 145         if ((uint64_t)fsd_rand() % 100 < less_chance) {
 146                 extern size_t copyout_max_cached;
 147                 int ret;
 148 
 149                 if (cnt > less)
 150                         cnt -= less;
 151                 else
 152                         less = 0;
 153 
 154                 uiop->uio_iov->iov_len = cnt;
 155                 uiop->uio_resid = cnt;
 156                 if (cnt <= copyout_max_cached)
 157                         uiop->uio_extflg = UIO_COPY_CACHED;
 158                 else
 159                         uiop->uio_extflg = UIO_COPY_DEFAULT;
 160 
 161                 ret = fsh_next_read(fshi, vp, uiop, ioflag, cr, ct);
 162                 uiop->uio_resid += less;
 163                 return (ret);
 164         }
 165 
 166         return (fsh_next_read(fshi, vp, uiop, ioflag, cr, ct));
 167 }
 168 
 169 /*
 170  * Finds and (optionally) locks a fsd_stat_int_t structure of a given vfs.
 171  */
 172 static int
 173 fsd_get_stati(vfs_t *vfsp, fsd_stat_int_t **si, int lock, int rwmode)
 174 {
 175         fsd_stat_int_t *stati;
 176 
 177         ASSERT(MUTEX_HELD(&fsd_lock));
 178 
 179         for (stati = list_head(&fsd_slist); stati;
 180             stati = list_next(&fsd_slist, stati))
 181                 if (stati->fsdsi_vfsp == vfsp) {
 182                         if (lock)
 183                                 rw_enter(&stati->fsdsi_lock, rwmode);
 184                         *si = stati;
 185                         return (0);
 186                 }
 187         return (FSD_ENTRY_NOT_FOUND);
 188 
 189 }
 190 
 191 static void
 192 fsd_install_disturber(vfs_t *vfsp, fsd_stat_t *stat)
 193 {
 194         fsd_stat_int_t *si;
 195 
 196         ASSERT(MUTEX_HELD(&fsd_lock));
 197 
 198         if (fsd_get_stati(vfsp, &si, 1, RW_WRITER) == FSD_ENTRY_NOT_FOUND) {
 199                 si = kmem_alloc(sizeof (*si), KM_SLEEP);
 200                 si->fsdsi_vfsp = vfsp;
 201                 (void) memcpy(&si->fsdsi_stat, stat, sizeof (si->fsdsi_stat));
 202                 rw_init(&si->fsdsi_lock, NULL, RW_DRIVER, NULL);
 203                 list_insert_head(&fsd_slist, si);
 204 
 205                 fsd_hooks.arg = si;
 206                 fsh_hook_install(vfsp, &fsd_hooks);
 207         } else {
 208                 (void) memcpy(&si->fsdsi_stat, stat, sizeof (si->fsdsi_stat));
 209                 rw_exit(&si->fsdsi_lock);
 210         }
 211 }
 212 
 213 static int
 214 fsd_remove_disturber(vfs_t *vfsp)
 215 {
 216         fsd_stat_int_t *si;
 217         int error;
 218 
 219         ASSERT(MUTEX_HELD(&fsd_lock));
 220 
 221         error = fsd_get_stati(vfsp, &si, 0, 0);
 222         if (error == FSD_ENTRY_NOT_FOUND)
 223                 return (error);
 224 
 225         list_remove(&fsd_slist, si);
 226         fsd_hooks.arg = si;
 227         fsh_hook_remove(vfsp, &fsd_hooks);
 228 
 229         rw_destroy(&si->fsdsi_lock);
 230         kmem_free(si, sizeof (*si));
 231 
 232         return (0);
 233 }
 234 
 235 static void
 236 fsd_callback_mount(vfs_t *vfsp, void *arg)
 237 {
 238         _NOTE(ARGUNUSED(arg));
 239 
 240         mutex_enter(&fsd_lock);
 241         if (fsd_new_stat != NULL)
 242                 fsd_install_disturber(vfsp, fsd_new_stat);
 243         mutex_exit(&fsd_lock);
 244 }
 245 
 246 static void
 247 fsd_callback_free(vfs_t *vfsp, void *arg)
 248 {
 249         _NOTE(ARGUNUSED(arg));
 250 
 251         mutex_enter(&fsd_lock);
 252         (void) fsd_remove_disturber(vfsp);
 253         mutex_exit(&fsd_lock);
 254 }
 255 
 256 static void
 257 fsd_enable()
 258 {
 259         mutex_enter(&fsd_lock);
 260         if (!fsd_enabled)
 261                 fsh_callback_install(&fsd_callbacks);
 262         fsd_enabled = 1;
 263         mutex_exit(&fsd_lock);
 264 }
 265 
 266 static void
 267 fsd_disable()
 268 {
 269         fsd_stat_int_t *si;
 270 
 271         mutex_enter(&fsd_lock);
 272         if (fsd_enabled) {
 273                 fsd_enabled = 0;
 274 
 275                 fsh_callback_remove(&fsd_callbacks);
 276 
 277                 /* Removing all hooks and fsd_stat_int_t entries. */
 278                 while (!list_is_empty(&fsd_slist)) {
 279                         si = list_remove_head(&fsd_slist);
 280 
 281                         /*
 282                          * After a fsh_hook_remove, we don't have to worry
 283                          * about the fsd_stat_int_t. If we hold the fsd_lock,
 284                          * nobody would try to use it. It's safe to destroy it.
 285                          */
 286                         fsd_hooks.arg = si;
 287                         fsh_hook_remove(si->fsdsi_vfsp, &fsd_hooks);
 288 
 289                         rw_destroy(&si->fsdsi_lock);
 290                         kmem_free(si, sizeof (*si));
 291                 }
 292 
 293                 if (fsd_new_stat != NULL) {
 294                         kmem_free(fsd_new_stat, sizeof (*fsd_new_stat));
 295                         fsd_new_stat = NULL;
 296                 }
 297         }
 298         mutex_exit(&fsd_lock);
 299 }
 300 
 301 static int
 302 fsd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 303 {
 304         minor_t instance;
 305 
 306         if (cmd != DDI_ATTACH)
 307                 return (DDI_FAILURE);
 308 
 309         if (fsd_devi != NULL)
 310                 return (DDI_FAILURE);
 311 
 312         instance = ddi_get_instance(dip);
 313         if (ddi_create_minor_node(dip, "fsd", S_IFCHR, instance,
 314             DDI_PSEUDO, 0) == DDI_FAILURE)
 315                 return (DDI_FAILURE);
 316         fsd_devi = dip;
 317         ddi_report_dev(fsd_devi);
 318 
 319         /* Setting hooks */
 320         fsd_hooks.hook_read = fsd_hook_read;
 321 
 322         list_create(&fsd_slist, sizeof (fsd_stat_int_t),
 323             offsetof(fsd_stat_int_t, fsdsi_next));
 324 
 325         fsd_rand_seed = gethrtime();
 326 
 327         /* Setting callbacks */
 328         fsd_callbacks.fshc_mount = fsd_callback_mount;
 329         fsd_callbacks.fshc_free = fsd_callback_free;
 330 
 331         mutex_init(&fsd_lock, NULL, MUTEX_DRIVER, NULL);
 332 
 333         return (DDI_SUCCESS);
 334 }
 335 
 336 /*
 337  * If fsd_enable() was called and there was no subsequent fsd_disable() call,
 338  * detach will fail.
 339  */
 340 static int
 341 fsd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 342 {
 343         if (cmd != DDI_DETACH)
 344                 return (DDI_FAILURE);
 345 
 346         ASSERT(dip == fsd_devi);
 347 
 348         /* No need to hold fsd_lock here */
 349         if (fsd_enabled)
 350                 return (DDI_FAILURE);
 351 
 352         ddi_remove_minor_node(dip, NULL);
 353         fsd_devi = NULL;
 354 
 355         list_destroy(&fsd_slist);
 356         mutex_destroy(&fsd_lock);
 357 
 358         return (DDI_SUCCESS);
 359 }
 360 
 361 static int
 362 fsd_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **resultp)
 363 {
 364         _NOTE(ARGUNUSED(dip));
 365 
 366         switch (infocmd) {
 367         case DDI_INFO_DEVT2DEVINFO:
 368                 *resultp = fsd_devi;
 369                 return (DDI_SUCCESS);
 370         case DDI_INFO_DEVT2INSTANCE:
 371                 *resultp = (void *)(uintptr_t)getminor((dev_t)arg);
 372                 return (DDI_SUCCESS);
 373         default:
 374                 return (DDI_FAILURE);
 375         }
 376 }
 377 
 378 /* TODO: what policy should be checked here? */
 379 static int
 380 fsd_open(dev_t *devp, int oflag, int sflag, cred_t *cred_p)
 381 {
 382         _NOTE(ARGUNUSED(devp));
 383         _NOTE(ARGUNUSED(oflag));
 384         _NOTE(ARGUNUSED(sflag));
 385         _NOTE(ARGUNUSED(cred_p));
 386 
 387         return (0);
 388 }
 389 
 390 static int
 391 fsd_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
 392 {
 393         _NOTE(ARGUNUSED(dev));
 394         _NOTE(ARGUNUSED(flag));
 395         _NOTE(ARGUNUSED(otyp));
 396         _NOTE(ARGUNUSED(cred_p));
 397 
 398         return (0);
 399 }
 400 
 401 static int
 402 fsd_check_stat(fsd_stat_t *stat)
 403 {
 404         if (stat->fsds_read_less_chance > 100 ||
 405             stat->fsds_read_less_r[0] > stat->fsds_read_less_r[1])
 406                 return (FSD_BAD_STAT);
 407         return (0);
 408 }
 409 
 410 static int
 411 fsd_ioctl_disturb(void *arg, int mode, int *rvalp)
 412 {
 413         file_t *file;
 414         fsd_ioc_stat_t iocs;
 415         int rv;
 416 
 417         if (ddi_copyin(arg, &iocs, sizeof (iocs), mode))
 418                 return (EFAULT);
 419 
 420         if ((rv = fsd_check_stat(&iocs.fsdis_stat))) {
 421                 *rvalp = rv;
 422                 return (0);
 423         }
 424 
 425         if ((file = getf((int)iocs.fsdis_mnt)) == NULL) {
 426                 *rvalp = FSD_BAD_FD;
 427                 return (0);
 428         }
 429 
 430         mutex_enter(&fsd_lock);
 431         fsd_install_disturber(file->f_vnode->v_vfsp, &iocs.fsdis_stat);
 432         mutex_exit(&fsd_lock);
 433 
 434         releasef((int)iocs.fsdis_mnt);
 435 
 436         *rvalp = 0;
 437         return (0);
 438 }
 439 
 440 static int
 441 fsd_ioctl_get_status(void *arg, int mode, int *rvalp)
 442 {
 443         file_t *file;
 444         fsd_stat_int_t *si;
 445         int error;
 446         int64_t fd;
 447 
 448         if (ddi_copyin(arg, &fd, sizeof (fd), mode))
 449                 return (EFAULT);
 450 
 451         if ((file = getf((int)fd)) == NULL) {
 452                 *rvalp = FSD_BAD_FD;
 453                 return (0);
 454         }
 455 
 456         mutex_enter(&fsd_lock);
 457         error = fsd_get_stati(file->f_vnode->v_vfsp, &si, 1, RW_READER);
 458         mutex_exit(&fsd_lock);
 459 
 460         releasef((int)fd);
 461 
 462         if (error == FSD_ENTRY_NOT_FOUND) {
 463                 *rvalp = FSD_ENTRY_NOT_FOUND;
 464                 return (0);
 465         }
 466 
 467         error = ddi_copyout(&si->fsdsi_stat, (void *)arg,
 468             sizeof (si->fsdsi_stat), mode);
 469         rw_exit(&si->fsdsi_lock);
 470         if (error)
 471                 return (EFAULT);
 472 
 473         *rvalp = 0;
 474         return (0);
 475 }
 476 
 477 static int
 478 fsd_ioctl_nodisturb(void *arg, int mode, int *rvalp)
 479 {
 480         file_t *file;
 481         int64_t fd;
 482 
 483         if (ddi_copyin((void *)arg, &fd, sizeof (fd), mode))
 484                 return (EFAULT);
 485 
 486         if ((file = getf((int)fd)) == NULL) {
 487                 *rvalp = FSD_BAD_FD;
 488                 return (0);
 489         }
 490 
 491         mutex_enter(&fsd_lock);
 492         *rvalp = fsd_remove_disturber(file->f_vnode->v_vfsp);
 493         releasef((int)fd);
 494         mutex_exit(&fsd_lock);
 495 
 496         return (0);
 497 }
 498 
 499 static int
 500 fsd_ioctl_disturb_new(void *arg, int mode, int *rvalp)
 501 {
 502         fsd_stat_t stat;
 503         int rv;
 504 
 505         if (ddi_copyin(arg, &stat, sizeof (stat), mode))
 506                 return (EFAULT);
 507 
 508         if ((rv = fsd_check_stat(&stat))) {
 509                 *rvalp = rv;
 510                 return (0);
 511         }
 512 
 513         mutex_enter(&fsd_lock);
 514         if (fsd_new_stat == NULL)
 515                 fsd_new_stat = (fsd_stat_t *)kmem_alloc(sizeof (*fsd_new_stat),
 516                     KM_SLEEP);
 517         (void) memcpy(fsd_new_stat, &stat, sizeof (*fsd_new_stat));
 518         mutex_exit(&fsd_lock);
 519 
 520         *rvalp = 0;
 521         return (0);
 522 }
 523 
 524 
 525 static int
 526 fsd_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
 527         int *rvalp)
 528 {
 529         _NOTE(ARGUNUSED(dev));
 530         _NOTE(ARGUNUSED(credp));
 531 
 532         if (!fsd_enabled && cmd != FSD_ENABLE) {
 533                 *rvalp = FSD_NOT_ENABLED;
 534                 return (0);
 535         }
 536 
 537         switch (cmd) {
 538         case FSD_ENABLE:
 539                 fsd_enable();
 540                 *rvalp = 0;
 541                 return (0);
 542 
 543         case FSD_DISABLE:
 544                 fsd_disable();
 545                 *rvalp = 0;
 546                 return (0);
 547 
 548         case FSD_GET_STATUS:
 549                 return (fsd_ioctl_get_status((void *)arg, mode, rvalp));
 550 
 551         case FSD_DISTURB:
 552                 return (fsd_ioctl_disturb((void *)arg, mode, rvalp));
 553 
 554         case FSD_NODISTURB:
 555                 return (fsd_ioctl_nodisturb((void *)arg, mode, rvalp));
 556 
 557         case FSD_DISTURB_NEW:
 558                 return (fsd_ioctl_disturb_new((void *)arg, mode, rvalp));
 559 
 560         case FSD_NODISTURB_NEW:
 561                 mutex_enter(&fsd_lock);
 562                 if (fsd_new_stat != NULL)
 563                         kmem_free(fsd_new_stat, sizeof (*fsd_new_stat));
 564                 mutex_exit(&fsd_lock);
 565 
 566                 *rvalp = 0;
 567                 return (0);
 568 
 569         default:
 570                 return (EINVAL);
 571         }
 572 }
 573 
 574 static struct cb_ops cb_ops = {
 575         fsd_open,       /* open(9E) */
 576         fsd_close,      /* close(9E) */
 577         nodev,          /* strategy(9E) */
 578         nodev,          /* print(9E) */
 579         nodev,          /* dump(9E) */
 580         nodev,          /* read(9E) */
 581         nodev,          /* write(9E) */
 582         fsd_ioctl,      /* ioctl(9E) */
 583         nodev,          /* devmap(9E) */
 584         nodev,          /* mmap(9E) */
 585         nodev,          /* segmap(9E) */
 586         nochpoll,       /* chpoll(9E) */
 587         ddi_prop_op,    /* prop_op(9E) */
 588         NULL,           /* streamtab(9E) */
 589         D_MP | D_64BIT, /* cb_flag(9E) */
 590         CB_REV,         /* cb_rev(9E) */
 591         nodev,          /* aread(9E) */
 592         nodev,          /* awrite(9E) */
 593 };
 594 
 595 static struct dev_ops dev_ops = {
 596         DEVO_REV,               /* driver build version */
 597         0,                      /* reference count */
 598         fsd_getinfo,            /* getinfo */
 599         nulldev,
 600         nulldev,                /* probe */
 601         fsd_attach,             /* attach */
 602         fsd_detach,             /* detach */
 603         nodev,
 604         &cb_ops,            /* cb_ops */
 605         NULL,                   /* bus_ops */
 606         NULL,                   /* power */
 607         ddi_quiesce_not_needed, /* quiesce */
 608 };
 609 
 610 static struct modldrv modldrv = {
 611         &mod_driverops,     "Filesystem disturber", &dev_ops
 612 };
 613 
 614 static struct modlinkage modlinkage = {
 615         MODREV_1, &modldrv, NULL
 616 };
 617 
 618 int
 619 _init(void)
 620 {
 621         return (mod_install(&modlinkage));
 622 }
 623 
 624 int
 625 _info(struct modinfo *modinfop)
 626 {
 627         return (mod_info(&modlinkage, modinfop));
 628 }
 629 
 630 int
 631 _fini(void)
 632 {
 633         return (mod_remove(&modlinkage));
 634 }