DF-3035 / cgxtool.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | /* * cgxtool.c — DF-3035 on-disk cylinder-group header patcher (root, guest). * * Demonstrates that the FFS allocator (sys/vfs/ufs/ffs_alloc.c) uses * cylinder-group header fields straight off disk with no validation: * the cg block is bread()ed, only cg_chkmagic() (a magic comparison) * is applied, and then fields such as cg_cgx / cg_freeoff / cg_iusedoff / * cg_frotor / cg_nclusterblks are used as array indices and pointer * offsets into kernel memory. * * usage: * cgxtool <image> info * cgxtool <image> <field> <hex-value> field ∈ {cgx, freeoff, iusedoff, * frotor, nclusterblks} * * Locates the superblock (8192 / 65536, both magics), computes cg0's byte * offset from fs_cblkno*fs_fsize (cgstart(fs,0)==0), verifies CG_MAGIC, * and patches the requested 32-bit field of the on-disk struct cg. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> #include <fcntl.h> #include <unistd.h> #include <err.h> #include <stddef.h> #include <sys/types.h> typedef int32_t ufs_time_t; typedef int32_t ufs_daddr_t; #define _KERNEL_STRUCTURES #define MAXFRAG 8 #include "fs.h" static const struct { off_t off; uint32_t magic; } sbs[] = { { 8192, FS_MAGIC }, /* UFS1 sblkno=16, fsize=512 */ { 65536, FS_MAGIC }, { 8192, 0x19540119 }, /* UFS2 magic */ { 65536, 0x19540119 }, }; static void loadsb(int fd, struct fs *fsb, off_t *sbpos) { unsigned i; for (i = 0; i < sizeof(sbs)/sizeof(sbs[0]); i++) { if (pread(fd, fsb, sizeof(*fsb), sbs[i].off) != sizeof(*fsb)) continue; if (fsb->fs_magic == sbs[i].magic) { *sbpos = sbs[i].off; return; } } errx(1, "no superblock found"); } int main(int argc, char **argv) { struct fs fsb; struct cg cg; off_t sbpos, cgoff; int fd; uint32_t val; unsigned fieldoff = 0; char *img, *field; if (argc != 2 && !(argc == 3 && !strcmp(argv[2], "info")) && argc != 4) { fprintf(stderr, "usage: %s img [field hexval]\n", argv[0]); return (2); } img = argv[1]; fd = open(img, O_RDWR); if (fd < 0) err(1, "open %s", img); loadsb(fd, &fsb, &sbpos); cgoff = (off_t)fsb.fs_cblkno * fsb.fs_fsize; /* cgtod(fs,0) */ if (pread(fd, &cg, sizeof(cg), cgoff) != sizeof(cg)) err(1, "read cg0"); if (cg.cg_magic != CG_MAGIC) errx(1, "cg0 at byte %lld: bad magic %08x", (long long)cgoff, cg.cg_magic); printf("[sb] pos=%lld magic=%08x ncg=%d fpg=%d ipg=%d cblkno=%d\n", (long long)sbpos, fsb.fs_magic, fsb.fs_ncg, fsb.fs_fpg, fsb.fs_ipg, fsb.fs_cblkno); printf("[sb] bsize=%ld fsize=%ld frag=%d cgsize=%ld " "contigsumsize=%d ncyl=%d spc=%d cpc=%d nrpos=%d\n", (long)fsb.fs_bsize, (long)fsb.fs_fsize, fsb.fs_frag, (long)fsb.fs_cgsize, fsb.fs_contigsumsize, fsb.fs_cpg, fsb.fs_spc, fsb.fs_cpc, fsb.fs_nrpos); printf("[cg0] at byte %lld: cgx=%d rotor=%d frotor=%d irotor=%d " "nclusterblks=%d\n", (long long)cgoff, cg.cg_cgx, cg.cg_rotor, cg.cg_frotor, cg.cg_irotor, cg.cg_nclusterblks); printf("[cg0] btotoff=%d boff=%d iusedoff=%d freeoff=%d " "clustersumoff=%d clusteroff=%d\n", cg.cg_btotoff, cg.cg_boff, cg.cg_iusedoff, cg.cg_freeoff, cg.cg_clustersumoff, cg.cg_clusteroff); if (argc < 4) return (0); field = argv[2]; val = (uint32_t)strtoul(argv[3], NULL, 0); if (!strcmp(field, "cgx")) fieldoff = offsetof(struct cg, cg_cgx); else if (!strcmp(field, "freeoff")) fieldoff = offsetof(struct cg, cg_freeoff); else if (!strcmp(field, "iusedoff")) fieldoff = offsetof(struct cg, cg_iusedoff); else if (!strcmp(field, "frotor")) fieldoff = offsetof(struct cg, cg_frotor); else if (!strcmp(field, "nclusterblks")) fieldoff = offsetof(struct cg, cg_nclusterblks); else errx(1, "unknown field %s", field); if (pwrite(fd, &val, 4, cgoff + fieldoff) != 4) err(1, "pwrite"); printf("[patch] cg0.%s = 0x%08x written at byte %lld\n", field, val, (long long)(cgoff + fieldoff)); return (0); } |