view pirollback/rollback.c @ 106:a39a38bbec4d

analysis of what osmocon's voodoo payloads disassemble to in ARM/Thumb
author Michael Spacefalcon <msokolov@ivan.Harhan.ORG>
date Mon, 31 Mar 2014 06:33:14 +0000
parents e516128db432
children
line wrap: on
line source

#include <sys/types.h>
#include <sys/file.h>
#include <endian.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <unistd.h>
#include "types.h"
#include "struct.h"
#include "pathname.h"

extern char *imgfile;
extern u8 image[0x480000];
extern struct inode_info inode[];
extern int last_inode;
extern int journal_start_ino;

static void
report_inode(ino)
{
	struct inode_info *inf = inode + ino;
	char pathname[PATHNAME_BUF_SIZE];
	int typechar;

	switch (inf->type) {
	case 0xF1:
		typechar = 'f';
		break;
	case 0xF2:
		typechar = 'd';
		break;
	case 0xF4:
		typechar = '.';
		break;
	default:
		fprintf(stderr, "inode #%x: unexpected type %02X\n",
			ino, inf->type);
		exit(1);
	}
	if (pathname_of_inode(ino, pathname) < 0)
		strcpy(pathname, "-nopath-");
	printf("reverting #%04X %c %s\n", ino, typechar, pathname);
}

static void
unlink_inode(oldino, newino, is_sibling)
{
	struct inode_info *inf = inode + oldino;
	struct inode_flash *fl = inf->flash;
	u16 *flashp;

	if (is_sibling)
		flashp = &fl->sibling;
	else
		flashp = &fl->descend;
	if (le16toh(*flashp) != newino) {
		fprintf(stderr,
	"fail: %s pointer of inode #%x does not point to #%x as expected\n",
			is_sibling ? "sibling" : "descend", oldino, newino);
		exit(1);
	}
	/* unprogram it! */
	*flashp = 0xFFFF;
}

static void
resurrect_descend_chain(headino, ino)
{
	struct inode_info *inf;
	u8 *typebyte;

	for (; ino; ino = inf->descend) {
		inf = inode + ino;
		if (inf->type != 0xF4) {
			fprintf(stderr,
			"error: #%x, descendant of #%x, is not of type F4\n",
				ino, headino);
			exit(1);
		}
		typebyte = &inf->flash->type;
		if (*typebyte) {
			fprintf(stderr,
			"inode #%x to be resurrected: not in deleted state\n",
				ino);
			exit(1);
		}
		/* undo the zeroing */
		*typebyte = 0xF4;
	}
}

static void
resurrect_old_ver(oldino, newino)
{
	struct inode_info *old = inode + oldino;
	struct inode_info *new = inode + newino;
	u8 *typebyte;

	if (old->type != new->type || old->parent != new->parent ||
	    strcmp(old->dataptr, new->dataptr)) {
		fprintf(stderr, "inode #%x replacing #%x: mismatch error\n",
			newino, oldino);
		exit(1);
	}
	/* the item of interest is the old in-flash type byte */
	typebyte = &old->flash->type;
	if (*typebyte) {
		fprintf(stderr,
			"inode #%x to be resurrected: not in deleted state\n",
			oldino);
		exit(1);
	}
	/* undo the zeroing */
	*typebyte = old->type;
	/*
	 * Is there a descendant chain (file continuation chunks)
	 * to resurrect as well?
	 */
	if (!old->descend)
		return;
	if (old->type != 0xF1) {
		fprintf(stderr,
	"resurrecting inode #%x: unexpected descendant with type != F1\n",
			oldino);
		exit(1);
	}
	resurrect_descend_chain(oldino, old->descend);
}

roll_back_inode(ino)
{
	struct inode_info *inf = inode + ino;

	report_inode(ino);
	if (!inf->flash->type)
		printf("NOTE: object is already in deleted state\n");
	/* first order of business: unlink it */
	if (inf->j_unlink_ptr < 0)
		unlink_inode(-inf->j_unlink_ptr, ino, 0);
	else
		unlink_inode(inf->j_unlink_ptr, ino, 1);
	/* resurrect the previous version */
	if (inf->type != 0xF4) {
		if (inf->j_oldver)
			resurrect_old_ver(inf->j_oldver, ino);
		else
			printf("NOTE: no previous version to resurrect\n");
	} else if (inf->j_oldver) {
		fprintf(stderr,
			"error: unexpected oldver on inode #%x of type F4\n",
			ino);
		exit(1);
	}
	/* reblank the 3 flash areas programmed with this inode */
	memset(inf->flash, 0xFF, 16);
	memset(inf->jflash, 0xFF, 16);
	memset(inf->dataptr, 0xFF, inf->len);
}

write_new_img(outfilename)
	char *outfilename;
{
	int fd, cc;

	fd = open(outfilename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
	if (fd < 0) {
		perror(outfilename);
		exit(1);
	}
	cc = write(fd, image, sizeof image);
	close(fd);
	if (cc != sizeof image) {
		fprintf(stderr, "error writing to %s\n", outfilename);
		exit(1);
	}
}

main(argc, argv)
	char **argv;
{
	int ino, keep_ino;
	char *strtoul_endp;

	if (argc != 4) {
usage:		fprintf(stderr,
			"usage: %s ffs-image inode-to-keep new-image\n",
			argv[0]);
		exit(1);
	}
	imgfile = argv[1];
	keep_ino = strtoul(argv[2], &strtoul_endp, 16);
	if (!argv[2][0] || *strtoul_endp)
		goto usage;

	read_img_file();
	read_inodes();
	walk_tree();
	check_object_names();
	parse_journal();
	check_object_names();	/* rerun for "undeleted" objects */
	if (keep_ino < journal_start_ino || keep_ino > last_inode) {
		fprintf(stderr, "%s: bad inode number specified\n", argv[0]);
		exit(1);
	}
	for (ino = last_inode; ino > keep_ino; ino--)
		roll_back_inode(ino);
	write_new_img(argv[3]);
	exit(0);
}