โฌข DragonFlyBSD Kernel Audit
DF-0847 / quota_unreachable.c
โ† back to finding โ†“ download raw
/*
 * DF-0847 โ€” default-kernel reachability probe.
 *
 * The finding cites an unlocked manipulation of the global UFS dquot hash
 * list and free list in ufs_dqget()/ufs_dqrele()/ufs_dqflush() (ufs_quota.c).
 * This probe demonstrates that on the stock X86_64_GENERIC kernel the entire
 * quota code path is DEAD:
 *
 *   1. ufs_quotactl() returns EOPNOTSUPP unless the kernel was built with
 *      `options QUOTA` (sys/vfs/ufs/ufs_vfsops.c:77-78).  X86_64_GENERIC
 *      does NOT enable `options QUOTA` (0 occurrences in sys/config/).
 *   2. Every in-kernel caller of ufs_getinoquota()/ufs_chkdq()/ufs_chkiq()/
 *      ufs_dqrele() โ€” the only paths that reach ufs_dqget() โ€” is wrapped in
 *      `#ifdef QUOTA` (ffs_alloc.c, ffs_inode.c, ufs_vnops.c, ufs_inode.c,
 *      ffs_balloc.c).  Compiled out on a non-QUOTA kernel.
 *
 * Consequence: ufs_dqget() exists in the binary (ufs_quota.c is
 * `optional ffs`, not `optional quota` โ€” confirmed via sys/conf/files:1994)
 * but has ZERO callers and is unreachable.  The unlocked list manipulation
 * (lines 769-866 of ufs_quota.c) can never execute on the default kernel.
 *
 * This program calls quotactl(Q_QUOTAON) against a UFS mount and prints the
 * errno.  On the default kernel it is EOPNOTSUPP (path dead).  On a kernel
 * built with `options QUOTA` it succeeds (path live).
 *
 * Build:  cc -o quota_unreachable quota_unreachable.c
 * Run:    ./quota_unreachable /mnt/q   (path of a UFS mount point)
 */
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/syscall.h>

/* ufs quota commands โ€” from vfs/ufs/quota.h */
#define Q_QUOTAON  0x0100
#define Q_QUOTAOFF 0x0200
#define USRQUOTA   0
#define SUBCMDMASK 0x00ff
#define SUBCMDSHIFT 8

int
main(int argc, char **argv)
{
    const char *path = (argc > 1) ? argv[1] : "/mnt/q";
    const char *qfile = (argc > 2) ? argv[2] : "/mnt/q/quota.user";
    /* cmd is packed as (subcmd << 8) | type per ufs_quotactl() */
    int cmd_on  = (Q_QUOTAON  << SUBCMDSHIFT) | USRQUOTA;
    int cmd_off = (Q_QUOTAOFF << SUBCMDSHIFT) | USRQUOTA;
    long rc;

    errno = 0;
    /* syscall(SYS_quotactl, path, cmd, uid, arg) โ€” uid=0 (root's quota) */
    rc = syscall(SYS_quotactl, path, cmd_on, 0, (char *)qfile);
    printf("quotactl(Q_QUOTAON, \"%s\", uid=0, \"%s\") -> rc=%ld errno=%d (%s)\n",
           path, qfile, rc, errno, strerror(errno));

    if (rc == 0) {
        printf("PATH LIVE: kernel has `options QUOTA`; the buggy code is reachable.\n");
        printf("           (turning quotas off again to leave the mount clean.)\n");
        syscall(SYS_quotactl, path, cmd_off, 0, NULL);
        return 0;
    }
    if (errno == EOPNOTSUPP) {
        printf("PATH DEAD: EOPNOTSUPP => ufs_quotactl() #ifndef-QUOTA early-return at\n");
        printf("           sys/vfs/ufs/ufs_vfsops.c:77-78. `options QUOTA` is absent from\n");
        printf("           X86_64_GENERIC, so every caller of ufs_dqget() is compiled out.\n");
        printf("           => DF-0847 unreachable on this (default) kernel.\n");
        return 0;
    }
    printf("Unexpected errno=%d (%s) โ€” see VERDICT.md.\n", errno, strerror(errno));
    return 0;
}