sbtools: rename to imxtools, move imx_hid_recovery to imxtools/sbloader, fix tools to correctly handle/free memory, properly return error codes

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30907 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Amaury Pouly 2011-11-06 01:49:13 +00:00
parent 33d6bd61b5
commit 5827937270
20 changed files with 392 additions and 198 deletions

View file

@ -1,15 +0,0 @@
CC=gcc
LD=gcc
all: imx_hid_recovery
imx_hid_recovery.o: imx_hid_recovery.c
$(CC) -c -Wall -O2 -std=c99 `pkg-config --cflags libusb-1.0` -o $@ $<
imx_hid_recovery: imx_hid_recovery.o
$(LD) -o $@ $< `pkg-config --libs libusb-1.0`
clean:
rm -rf imx_hid_recovery.o

View file

@ -3,8 +3,9 @@ CC=gcc
LD=gcc
CFLAGS=-g -std=c99 -W -Wall `pkg-config --cflags libusb-1.0` $(DEFINES)
LDFLAGS=`pkg-config --libs libusb-1.0`
BINS=elftosb sbtoelf sbloader
all: elftosb sbtoelf
all: $(BINS)
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
@ -15,8 +16,11 @@ sbtoelf: sbtoelf.o crc.o crypto.o aes128.o sha1.o elf.o misc.o sb.o
elftosb: elftosb.o crc.o crypto.o aes128.o sha1.o elf.o dbparser.o misc.o sb.o
$(LD) -o $@ $^ $(LDFLAGS)
sbloader: sbloader.o
$(LD) -o $@ $^ $(LDFLAGS)
clean:
rm -fr *.o
veryclean:
rm -rf sbtoelf elftosb
rm -rf $(BINS)

View file

@ -63,6 +63,7 @@ void crypto_setup(enum crypto_method_t method, void *param);
#define CRYPTO_ERROR_DEVREJECT -5 /* device rejected cypto operation */
#define CRYPTO_ERROR_DEVSILENT -6 /* device did not notify completion */
#define CRYPTO_ERROR_DEVERR -7 /* device did something wrong (like return too small buffer) */
#define CRYPTO_NUM_ERRORS 8
/* return 0 on success, <0 on error */
int crypto_apply(
byte *in_data, /* Input data */

View file

@ -19,6 +19,7 @@
*
****************************************************************************/
#define _POSIX_C_SOURCE 200809L /* for strdup */
#include <stdio.h>
#include <ctype.h>
#include <stdint.h>
@ -48,6 +49,7 @@ enum lexem_type_t
struct lexem_t
{
enum lexem_type_t type;
/* if str is not NULL, it must be a malloc'd pointer */
char *str;
uint32_t num;
int line;
@ -390,8 +392,15 @@ struct lex_ctx_t
struct lexem_t lexem;
};
static inline void next(struct lex_ctx_t *ctx)
/* When lexems hold strings (like identifier), it might be useful to steal
* the pointer and don't clean the lexem but in other case, one don't want
* to keep the pointer to the string and just want to release the memory.
* Thus clean_lexem should be true except when one keeps a pointer */
static inline void next(struct lex_ctx_t *ctx, bool clean_lexem)
{
if(clean_lexem)
free(ctx->lexem.str);
memset(&ctx->lexem, 0, sizeof(struct lexem_t));
next_lexem(&ctx->ctx, &ctx->lexem);
}
@ -411,7 +420,7 @@ static uint32_t parse_term_expr(struct lex_ctx_t *ctx, struct cmd_option_t *cons
}
else
parse_error(ctx->lexem, "Number or constant identifier expected\n");
next(ctx);
next(ctx, true);
return ret;
}
@ -420,7 +429,7 @@ static uint32_t parse_shift_expr(struct lex_ctx_t *ctx, struct cmd_option_t *con
uint32_t v = parse_term_expr(ctx, const_list);
while(ctx->lexem.type == LEX_LSHIFT)
{
next(ctx);
next(ctx, true);
v <<= parse_term_expr(ctx, const_list);
}
return v;
@ -431,7 +440,7 @@ static uint32_t parse_or_expr(struct lex_ctx_t *ctx, struct cmd_option_t *const_
uint32_t v = parse_shift_expr(ctx, const_list);
while(ctx->lexem.type == LEX_OR)
{
next(ctx);
next(ctx, true);
v |= parse_shift_expr(ctx, const_list);
}
return v;
@ -470,7 +479,7 @@ struct cmd_file_t *db_parse_file(const char *file)
{
struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t));
memset(opt, 0, sizeof(struct cmd_option_t));
opt->name = init_const_name[i];
opt->name = strdup(init_const_name[i]);
opt->is_string = false;
opt->val = init_const_value[i];
opt->next = cmd_file->constant_list;
@ -483,14 +492,14 @@ struct cmd_file_t *db_parse_file(const char *file)
lctx.ctx.begin = buf;
lctx.ctx.ptr = buf;
lctx.ctx.end = buf + size;
#define next() next(&lctx)
#define next(clean_lexem) next(&lctx, clean_lexem)
#define lexem lctx.lexem
/* init lexer */
next();
next(false); /* don't clean init lexem because it doesn't exist */
/* constants ? */
if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "constants"))
{
next();
next(true);
if(lexem.type != LEX_LBRACE)
parse_error(lexem, "'{' expected after 'constants'\n");
@ -498,16 +507,16 @@ struct cmd_file_t *db_parse_file(const char *file)
{
struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t));
memset(opt, 0, sizeof(struct cmd_option_t));
next();
next(true);
if(lexem.type == LEX_RBRACE)
break;
if(lexem.type != LEX_IDENTIFIER)
parse_error(lexem, "Identifier expected in constants\n");
opt->name = lexem.str;
next();
next(false); /* lexem string is kept as option name */
if(lexem.type != LEX_EQUAL)
parse_error(lexem, "'=' expected after identifier\n");
next();
next(true);
opt->is_string = false;
opt->val = parse_intexpr(&lctx, cmd_file->constant_list);
opt->next = cmd_file->constant_list;
@ -515,34 +524,34 @@ struct cmd_file_t *db_parse_file(const char *file)
if(lexem.type != LEX_SEMICOLON)
parse_error(lexem, "';' expected after string\n");
}
next();
next(true);
}
/* options ? */
if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "options"))
{
next();
next(true);
if(lexem.type != LEX_LBRACE)
parse_error(lexem, "'{' expected after 'options'\n");
while(true)
{
struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t));
memset(opt, 0, sizeof(struct cmd_option_t));
next();
next(true);
if(lexem.type == LEX_RBRACE)
break;
struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t));
memset(opt, 0, sizeof(struct cmd_option_t));
if(lexem.type != LEX_IDENTIFIER)
parse_error(lexem, "Identifier expected in options\n");
opt->name = lexem.str;
next();
next(false); /* lexem string is kept as option name */
if(lexem.type != LEX_EQUAL)
parse_error(lexem, "'=' expected after identifier\n");
next();
next(true);
if(lexem.type == LEX_STRING)
{
opt->is_string = true;
opt->str = lexem.str;
next();
next(false); /* lexem string is kept as option name */
}
else
{
@ -554,18 +563,18 @@ struct cmd_file_t *db_parse_file(const char *file)
if(lexem.type != LEX_SEMICOLON)
parse_error(lexem, "';' expected after string\n");
}
next();
next(true);
}
/* sources */
if(lexem.type != LEX_IDENTIFIER || strcmp(lexem.str, "sources"))
parse_error(lexem, "'sources' expected\n");
next();
next(true);
if(lexem.type != LEX_LBRACE)
parse_error(lexem, "'{' expected after 'sources'\n");
while(true)
{
next();
next(true);
if(lexem.type == LEX_RBRACE)
break;
struct cmd_source_t *src = xmalloc(sizeof(struct cmd_source_t));
@ -573,28 +582,28 @@ struct cmd_file_t *db_parse_file(const char *file)
if(lexem.type != LEX_IDENTIFIER)
parse_error(lexem, "identifier expected in sources\n");
src->identifier = lexem.str;
next();
next(false); /* lexem string is kept as source name */
if(lexem.type != LEX_EQUAL)
parse_error(lexem, "'=' expected after identifier\n");
next();
next(true);
if(lexem.type == LEX_STRING)
{
src->is_extern = false;
src->filename = lexem.str;
next();
next(false); /* lexem string is kept as file name */
}
else if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "extern"))
{
src->is_extern = true;
src->filename = "<extern>";
next();
src->filename = strdup("<extern>"); /* duplicate because it will be free'd */
next(true);
if(lexem.type != LEX_LPAREN)
parse_error(lexem, "'(' expected after 'extern'\n");
next();
next(true);
src->extern_nr = parse_intexpr(&lctx, cmd_file->constant_list);
if(lexem.type != LEX_RPAREN)
parse_error(lexem, "')' expected\n");
next();
next(true);
}
else
parse_error(lexem, "String or 'extern' expected after '='\n");
@ -612,18 +621,18 @@ struct cmd_file_t *db_parse_file(const char *file)
struct cmd_section_t *end_sec = NULL;
while(true)
{
next(true);
if(lexem.type == LEX_EOF)
break;
struct cmd_section_t *sec = xmalloc(sizeof(struct cmd_section_t));
struct cmd_inst_t *end_list = NULL;
memset(sec, 0, sizeof(struct cmd_section_t));
next();
if(lexem.type == LEX_EOF)
break;
if(lexem.type != LEX_IDENTIFIER || strcmp(lexem.str, "section") != 0)
parse_error(lexem, "'section' expected\n");
next();
next(true);
if(lexem.type != LEX_LPAREN)
parse_error(lexem, "'(' expected after 'section'\n");
next();
next(true);
/* can be any number */
sec->identifier = parse_intexpr(&lctx, cmd_file->constant_list);
/* options ? */
@ -631,21 +640,21 @@ struct cmd_file_t *db_parse_file(const char *file)
{
do
{
next();
next(true);
struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t));
memset(opt, 0, sizeof(struct cmd_option_t));
if(lexem.type != LEX_IDENTIFIER)
parse_error(lexem, "Identifier expected for section option\n");
opt->name = lexem.str;
next();
next(false); /* lexem string is kept as option name */
if(lexem.type != LEX_EQUAL)
parse_error(lexem, "'=' expected after option identifier\n");
next();
next(true);
if(lexem.type == LEX_STRING)
{
opt->is_string = true;
opt->str = lexem.str;
next();
next(false); /* lexem string is kept as option string */
}
else
{
@ -658,18 +667,18 @@ struct cmd_file_t *db_parse_file(const char *file)
}
if(lexem.type != LEX_RPAREN)
parse_error(lexem, "')' expected after section identifier\n");
next();
next(true);
if(lexem.type == LEX_LBRACE)
{
sec->is_data = false;
/* commands */
while(true)
{
struct cmd_inst_t *inst = xmalloc(sizeof(struct cmd_inst_t));
memset(inst, 0, sizeof(struct cmd_inst_t));
next();
next(true);
if(lexem.type == LEX_RBRACE)
break;
struct cmd_inst_t *inst = xmalloc(sizeof(struct cmd_inst_t));
memset(inst, 0, sizeof(struct cmd_inst_t));
if(lexem.type != LEX_IDENTIFIER)
parse_error(lexem, "Instruction expected in section\n");
if(strcmp(lexem.str, "load") == 0)
@ -682,7 +691,7 @@ struct cmd_file_t *db_parse_file(const char *file)
inst->type = CMD_MODE;
else
parse_error(lexem, "Instruction expected in section\n");
next();
next(true);
if(inst->type == CMD_LOAD)
{
@ -691,12 +700,12 @@ struct cmd_file_t *db_parse_file(const char *file)
inst->identifier = lexem.str;
if(db_find_source_by_id(cmd_file, inst->identifier) == NULL)
parse_error(lexem, "Undefined reference to source '%s'\n", inst->identifier);
next();
next(false); /* lexem string kept as identifier */
if(lexem.type == LEX_RANGLE)
{
// load at
inst->type = CMD_LOAD_AT;
next();
next(true);
inst->addr = parse_intexpr(&lctx, cmd_file->constant_list);
}
if(lexem.type != LEX_SEMICOLON)
@ -709,7 +718,7 @@ struct cmd_file_t *db_parse_file(const char *file)
inst->identifier = lexem.str;
if(db_find_source_by_id(cmd_file, inst->identifier) == NULL)
parse_error(lexem, "Undefined reference to source '%s'\n", inst->identifier);
next();
next(false); /* lexem string kept as identifier */
}
else
{
@ -719,11 +728,11 @@ struct cmd_file_t *db_parse_file(const char *file)
if(lexem.type == LEX_LPAREN)
{
next();
next(true);
inst->argument = parse_intexpr(&lctx, cmd_file->constant_list);
if(lexem.type != LEX_RPAREN)
parse_error(lexem, "Expected closing brace\n");
next();
next(true);
}
if(lexem.type != LEX_SEMICOLON)
parse_error(lexem, "';' expected after command\n");
@ -751,11 +760,11 @@ struct cmd_file_t *db_parse_file(const char *file)
else if(lexem.type == LEX_LE)
{
sec->is_data = true;
next();
next(true);
if(lexem.type != LEX_IDENTIFIER)
parse_error(lexem, "Identifier expected after '<='\n");
sec->source_id = lexem.str;
next();
next(false); /* lexem string is kept as source id */
if(lexem.type != LEX_SEMICOLON)
parse_error(lexem, "';' expected after identifier\n");
}
@ -776,6 +785,7 @@ struct cmd_file_t *db_parse_file(const char *file)
#undef lexem
#undef next
free(buf);
return cmd_file;
}
@ -783,3 +793,57 @@ void db_generate_default_sb_version(struct sb_version_t *ver)
{
ver->major = ver->minor = ver->revision = 0x999;
}
void db_free_option_list(struct cmd_option_t *opt_list)
{
while(opt_list)
{
struct cmd_option_t *next = opt_list->next;
fflush(stdout);
free(opt_list->name);
free(opt_list->str);
free(opt_list);
opt_list = next;
}
}
void db_free(struct cmd_file_t *file)
{
db_free_option_list(file->opt_list);
db_free_option_list(file->constant_list);
struct cmd_source_t *src = file->source_list;
while(src)
{
struct cmd_source_t *next = src->next;
free(src->identifier);
fflush(stdout);
free(src->filename);
if(src->loaded)
{
if(src->type == CMD_SRC_BIN)
free(src->bin.data);
if(src->type == CMD_SRC_ELF)
elf_release(&src->elf);
}
free(src);
src = next;
}
struct cmd_section_t *sec = file->section_list;
while(sec)
{
struct cmd_section_t *next = sec->next;
db_free_option_list(sec->opt_list);
free(sec->source_id);
struct cmd_inst_t *inst = sec->inst_list;
while(inst)
{
struct cmd_inst_t *next = inst->next;
free(inst->identifier);
free(inst);
inst = next;
}
free(sec);
sec = next;
}
free(file);
}

View file

@ -102,7 +102,7 @@ struct cmd_section_t
struct cmd_file_t
{
struct cmd_option_t *opt_list;
struct cmd_option_t *constant_list; /* constant all always integers */
struct cmd_option_t *constant_list; /* constant are always integers */
struct cmd_source_t *source_list;
struct cmd_section_t *section_list;
};
@ -112,5 +112,7 @@ struct cmd_option_t *db_find_option_by_id(struct cmd_option_t *opt, const char *
bool db_parse_sb_version(struct sb_version_t *ver, char *str);
void db_generate_default_sb_version(struct sb_version_t *ver);
struct cmd_file_t *db_parse_file(const char *file);
void db_free_option_list(struct cmd_option_t *opt_list);
void db_free(struct cmd_file_t *file);
#endif /* __DBPARSER__ */

View file

@ -153,10 +153,7 @@ typedef struct
void elf_init(struct elf_params_t *params)
{
params->has_start_addr = false;
params->start_addr = 0;
params->first_section = NULL;
params->last_section = NULL;
memset(params, 0, sizeof(struct elf_params_t));
}
extern void *xmalloc(size_t s);
@ -463,6 +460,7 @@ bool elf_read_file(struct elf_params_t *params, elf_read_fn_t read,
if(!read(user, shdr.sh_offset, data, shdr.sh_size))
error_printf("error read self section data\n");
elf_add_load_section(params, shdr.sh_addr, shdr.sh_size, data);
free(data);
if(strtab)
printf(user, false, "create load segment for %s\n", &strtab[shdr.sh_name]);
@ -480,6 +478,7 @@ bool elf_read_file(struct elf_params_t *params, elf_read_fn_t read,
}
}
free(strtab);
/* run through segments */
for(int i = 1; i < ehdr.e_phnum; i++)
{
@ -557,16 +556,20 @@ int elf_get_nr_sections(struct elf_params_t *params)
void elf_release(struct elf_params_t *params)
{
struct elf_section_t *sec, *next_sec;
sec = params->first_section;
struct elf_section_t *sec = params->first_section;
while(sec)
{
next_sec = sec->next;
struct elf_section_t *next_sec = sec->next;
if(sec->type == EST_LOAD)
free(sec->section);
free(sec);
sec = next_sec;
}
params->first_section = NULL;
params->last_section = NULL;
struct elf_segment_t *seg = params->first_segment;
while(seg)
{
struct elf_segment_t *next_seg = seg->next;
free(seg);
seg = next_seg;
}
}

View file

@ -20,6 +20,7 @@
****************************************************************************/
#define _ISOC99_SOURCE
#define _POSIX_C_SOURCE 200809L /* for strdup */
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
@ -77,7 +78,9 @@ static void resolve_extern(struct cmd_source_t *src)
src->is_extern = false;
if(src->extern_nr < 0 || src->extern_nr >= g_extern_count)
bug("There aren't enough file on command file to resolve extern(%d)\n", src->extern_nr);
src->filename = g_extern[src->extern_nr];
/* first free the old src->filename content */
free(src->filename);
src->filename = strdup(g_extern[src->extern_nr]);
}
static void load_elf_by_id(struct cmd_file_t *cmd_file, const char *id)
@ -206,7 +209,7 @@ static struct sb_file_t *apply_cmd_file(struct cmd_file_t *cmd_file)
sec->insts[0].inst = SB_INST_DATA;
sec->insts[0].size = bin->size;
sec->insts[0].data = bin->data;
sec->insts[0].data = memdup(bin->data, bin->size);
}
else
{
@ -266,7 +269,7 @@ static struct sb_file_t *apply_cmd_file(struct cmd_file_t *cmd_file)
sec->insts[idx].inst = SB_INST_LOAD;
sec->insts[idx].addr = esec->addr;
sec->insts[idx].size = esec->size;
sec->insts[idx++].data = esec->section;
sec->insts[idx++].data = memdup(esec->section, esec->size);
}
else if(esec->type == EST_FILL)
{
@ -296,7 +299,7 @@ static struct sb_file_t *apply_cmd_file(struct cmd_file_t *cmd_file)
struct bin_param_t *bin = &db_find_source_by_id(cmd_file, cinst->identifier)->bin;
sec->insts[idx].inst = SB_INST_LOAD;
sec->insts[idx].addr = cinst->addr;
sec->insts[idx].data = bin->data;
sec->insts[idx].data = memdup(bin->data, bin->size);
sec->insts[idx++].size = bin->size;
}
else if(cinst->type == CMD_MODE)
@ -431,11 +434,18 @@ int main(int argc, char **argv)
struct cmd_file_t *cmd_file = db_parse_file(cmd_filename);
struct sb_file_t *sb_file = apply_cmd_file(cmd_file);
db_free(cmd_file);
if(real_key.method == CRYPTO_KEY)
sb_file->real_key = &real_key.u.key;
{
sb_file->override_real_key = true;
memcpy(sb_file->real_key, real_key.u.key, 16);
}
if(crypto_iv.method == CRYPTO_KEY)
sb_file->crypto_iv = &crypto_iv.u.key;
{
sb_file->override_crypto_iv = true;
memcpy(sb_file->crypto_iv, crypto_iv.u.key, 16);
}
/* fill with default parameters since there is no command file support for them */
sb_file->drive_tag = 0;
@ -444,6 +454,8 @@ int main(int argc, char **argv)
sb_file->minor_version = 1;
sb_write_file(sb_file, output_filename);
sb_free(sb_file);
clear_keys();
return 0;
}

View file

@ -29,6 +29,14 @@ bool g_debug = false;
/**
* Misc
*/
void *memdup(void *p, size_t len)
{
void *cpy = xmalloc(len);
memcpy(cpy, p, len);
return cpy;
}
void generate_random_data(void *buf, size_t sz)
{
FILE *rand_fd = fopen("/dev/urandom", "rb");
@ -144,6 +152,12 @@ void add_keys(key_array_t ka, int kac)
g_nr_keys += kac;
}
void clear_keys()
{
free(g_key_array);
g_nr_keys = 0;
}
void add_keys_from_file(const char *key_file)
{
int size;

View file

@ -38,6 +38,7 @@ typedef struct crypto_key_t *key_array_t;
int g_nr_keys;
key_array_t g_key_array;
void *memdup(void *p, size_t len);
void *augment_array(void *arr, size_t elem_sz, size_t cnt, void *aug, size_t aug_cnt);
void generate_random_data(void *buf, size_t sz);
void *xmalloc(size_t s);
@ -47,6 +48,7 @@ void add_keys(key_array_t ka, int kac);
bool parse_key(char **str, struct crypto_key_t *key);
void add_keys_from_file(const char *key_file);
void print_key(struct crypto_key_t *key, bool newline);
void clear_keys();
typedef char color_t[];

View file

@ -138,7 +138,7 @@ static void compute_sb_offsets(struct sb_file_t *sb)
if(sb->sections[i].is_data)
{
nr_aug_insts = 1;
aug_insts = malloc(sizeof(struct sb_inst_t));
aug_insts = xmalloc(sizeof(struct sb_inst_t));
memset(aug_insts, 0, sizeof(struct sb_inst_t));
aug_insts[0].inst = SB_INST_DATA;
aug_insts[0].size = missing_sz * BLOCK_SIZE;
@ -150,7 +150,7 @@ static void compute_sb_offsets(struct sb_file_t *sb)
else
{
nr_aug_insts = missing_sz;
aug_insts = malloc(sizeof(struct sb_inst_t) * nr_aug_insts);
aug_insts = xmalloc(sizeof(struct sb_inst_t) * nr_aug_insts);
memset(aug_insts, 0, sizeof(struct sb_inst_t) * nr_aug_insts);
for(int j = 0; j < nr_aug_insts; j++)
{
@ -163,6 +163,7 @@ static void compute_sb_offsets(struct sb_file_t *sb)
sb->sections[i].insts = augment_array(sb->sections[i].insts, sizeof(struct sb_inst_t),
sb->sections[i].nr_insts, aug_insts, nr_aug_insts);
sb->sections[i].nr_insts += nr_aug_insts;
free(aug_insts);
/* augment image and section size */
sb->image_size += missing_sz;
@ -299,12 +300,8 @@ void produce_sb_instruction(struct sb_inst_t *inst,
cmd->hdr.checksum = instruction_checksum(&cmd->hdr);
}
void sb_write_file(struct sb_file_t *sb, const char *filename)
enum sb_error_t sb_write_file(struct sb_file_t *sb, const char *filename)
{
FILE *fd = fopen(filename, "wb");
if(fd == NULL)
bugp("cannot open output file");
struct crypto_key_t real_key;
real_key.method = CRYPTO_KEY;
byte crypto_iv[16];
@ -324,8 +321,13 @@ void sb_write_file(struct sb_file_t *sb, const char *filename)
/* produce and write header */
struct sb_header_t sb_hdr;
produce_sb_header(sb, &sb_hdr);
/* allocate image */
byte *buf = xmalloc(sb_hdr.image_size * BLOCK_SIZE);
byte *buf_p = buf;
#define write(p, sz) do { memcpy(buf_p, p, sz); buf_p += sz; } while(0)
sha_1_update(&file_sha1, (byte *)&sb_hdr, sizeof(sb_hdr));
fwrite(&sb_hdr, 1, sizeof(sb_hdr), fd);
write(&sb_hdr, sizeof(sb_hdr));
memcpy(crypto_iv, &sb_hdr, 16);
@ -340,7 +342,7 @@ void sb_write_file(struct sb_file_t *sb, const char *filename)
struct sb_section_header_t sb_sec_hdr;
produce_sb_section_header(&sb->sections[i], &sb_sec_hdr);
sha_1_update(&file_sha1, (byte *)&sb_sec_hdr, sizeof(sb_sec_hdr));
fwrite(&sb_sec_hdr, 1, sizeof(sb_sec_hdr), fd);
write(&sb_sec_hdr, sizeof(sb_sec_hdr));
/* update CBC-MACs */
for(int j = 0; j < g_nr_keys; j++)
crypto_cbc((byte *)&sb_sec_hdr, NULL, sizeof(sb_sec_hdr) / BLOCK_SIZE,
@ -354,16 +356,18 @@ void sb_write_file(struct sb_file_t *sb, const char *filename)
crypto_cbc(real_key.u.key, entry.key, 1, &g_key_array[i],
crypto_iv, NULL, 1);
fwrite(&entry, 1, sizeof(entry), fd);
write(&entry, sizeof(entry));
sha_1_update(&file_sha1, (byte *)&entry, sizeof(entry));
}
free(cbc_macs);
/* HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK */
/* Image crafting, don't use it unless you understand what you do */
if(sb->real_key != NULL)
memcpy(real_key.u.key, *sb->real_key, 16);
if(sb->crypto_iv != NULL)
memcpy(crypto_iv, *sb->crypto_iv, 16);
if(sb->override_real_key)
memcpy(real_key.u.key, sb->real_key, 16);
if(sb->override_crypto_iv)
memcpy(crypto_iv, sb->crypto_iv, 16);
/* KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH */
if(g_debug)
{
@ -386,7 +390,7 @@ void sb_write_file(struct sb_file_t *sb, const char *filename)
crypto_cbc((byte *)&tag_cmd, (byte *)&tag_cmd, sizeof(tag_cmd) / BLOCK_SIZE,
&real_key, crypto_iv, NULL, 1);
sha_1_update(&file_sha1, (byte *)&tag_cmd, sizeof(tag_cmd));
fwrite(&tag_cmd, 1, sizeof(tag_cmd), fd);
write(&tag_cmd, sizeof(tag_cmd));
/* produce other commands */
byte cur_cbc_mac[16];
memcpy(cur_cbc_mac, crypto_iv, 16);
@ -402,7 +406,7 @@ void sb_write_file(struct sb_file_t *sb, const char *filename)
crypto_cbc((byte *)&cmd, (byte *)&cmd, sizeof(cmd) / BLOCK_SIZE,
&real_key, cur_cbc_mac, &cur_cbc_mac, 1);
sha_1_update(&file_sha1, (byte *)&cmd, sizeof(cmd));
fwrite(&cmd, 1, sizeof(cmd), fd);
write(&cmd, sizeof(cmd));
}
/* data */
if(inst->inst == SB_INST_LOAD || inst->inst == SB_INST_DATA)
@ -415,7 +419,7 @@ void sb_write_file(struct sb_file_t *sb, const char *filename)
crypto_cbc(data, data, sz / BLOCK_SIZE,
&real_key, cur_cbc_mac, &cur_cbc_mac, 1);
sha_1_update(&file_sha1, data, sz);
fwrite(data, 1, sz, fd);
write(data, sz);
free(data);
}
}
@ -427,22 +431,35 @@ void sb_write_file(struct sb_file_t *sb, const char *filename)
generate_random_data(final_sig + 20, 12);
if(g_nr_keys > 0)
crypto_cbc(final_sig, final_sig, 2, &real_key, crypto_iv, NULL, 1);
fwrite(final_sig, 1, 32, fd);
write(final_sig, 32);
fclose(fd);
}
if(buf_p - buf != sb_hdr.image_size * BLOCK_SIZE)
bug("SB image buffer was not entirely filled !");
static void *memdup(void *p, size_t len)
FILE *fd = fopen(filename, "wb");
if(fd == NULL)
return SB_OPEN_ERROR;
if(fwrite(buf, sb_hdr.image_size * BLOCK_SIZE, 1, fd) != 1)
{
void *cpy = xmalloc(len);
memcpy(cpy, p, len);
return cpy;
free(buf);
return SB_WRITE_ERROR;
}
fclose(fd);
free(buf);
return SB_SUCCESS;
}
static struct sb_section_t *read_section(bool data_sec, uint32_t id, byte *buf,
int size, const char *indent, void *u, sb_color_printf cprintf)
int size, const char *indent, void *u, sb_color_printf cprintf, enum sb_error_t *err)
{
#define printf(c, ...) cprintf(u, false, c, __VA_ARGS__)
#define fatal(e, ...) \
do { if(err) *err = e; \
cprintf(u, true, GREY, __VA_ARGS__); \
sb_free_section(*sec); \
free(sec); \
return NULL; } while(0)
struct sb_section_t *sec = xmalloc(sizeof(struct sb_section_t));
memset(sec, 0, sizeof(struct sb_section_t));
@ -474,7 +491,7 @@ static struct sb_section_t *read_section(bool data_sec, uint32_t id, byte *buf,
printf(OFF, "%s", indent);
uint8_t checksum = instruction_checksum(hdr);
if(checksum != hdr->checksum)
printf(GREY, "[Bad checksum]");
fatal(SB_CHECKSUM_ERROR, "Bad instruction checksum");
if(hdr->flags != 0)
{
printf(GREY, "[");
@ -501,7 +518,10 @@ static struct sb_section_t *read_section(bool data_sec, uint32_t id, byte *buf,
if(load->crc == computed_crc)
printf(RED, " Ok\n");
else
{
printf(RED, " Failed (crc=0x%08x)\n", computed_crc);
fatal(SB_CHECKSUM_ERROR, "Instruction data crc error\n");
}
pos += load->len + sizeof(struct sb_instruction_load_t);
}
@ -559,7 +579,7 @@ static struct sb_section_t *read_section(bool data_sec, uint32_t id, byte *buf,
}
else
{
printf(RED, "Unknown instruction %d at address 0x%08lx\n", hdr->opcode, (unsigned long)pos);
fatal(SB_FORMAT_ERROR, "Unknown instruction %d at address 0x%08lx\n", hdr->opcode, (unsigned long)pos);
break;
}
@ -569,6 +589,7 @@ static struct sb_section_t *read_section(bool data_sec, uint32_t id, byte *buf,
return sec;
#undef printf
#undef fatal
}
void sb_fill_section_name(char name[5], uint32_t identifier)
@ -595,25 +616,37 @@ static uint32_t guess_alignment(uint32_t off)
}
struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
sb_color_printf cprintf)
sb_color_printf cprintf, enum sb_error_t *err)
{
uint8_t *buf = NULL;
struct sb_file_t *sb_file = NULL;
#define printf(c, ...) cprintf(u, false, c, __VA_ARGS__)
#define fatal(...) do { cprintf(u, true, GREY, __VA_ARGS__); return NULL; } while(0)
#define fatal(e, ...) \
do { if(err) *err = e; \
cprintf(u, true, GREY, __VA_ARGS__); \
free(buf); \
sb_free(sb_file); \
return NULL; } while(0)
#define print_hex(c, p, len, nl) \
do { printf(c, ""); print_hex(p, len, nl); } while(0)
FILE *f = fopen(filename, "rb");
if(f == NULL)
fatal("Cannot open file for reading\n");
fatal(SB_OPEN_ERROR, "Cannot open file for reading\n");
fseek(f, 0, SEEK_END);
long filesize = ftell(f);
fseek(f, 0, SEEK_SET);
uint8_t *buf = xmalloc(filesize);
fread(buf, 1, filesize, f);
buf = xmalloc(filesize);
if(fread(buf, filesize, 1, f) != 1)
{
fclose(f);
fatal(SB_READ_ERROR, "Cannot read file\n");
}
fclose(f);
struct sha_1_params_t sha_1_params;
struct sb_file_t *sb_file = xmalloc(sizeof(struct sb_file_t));
sb_file = xmalloc(sizeof(struct sb_file_t));
memset(sb_file, 0, sizeof(struct sb_file_t));
struct sb_header_t *sb_header = (struct sb_header_t *)buf;
@ -624,13 +657,13 @@ struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
sb_file->first_boot_sec_id = sb_header->first_boot_sec_id;
if(memcmp(sb_header->signature, "STMP", 4) != 0)
fatal("Bad signature\n");
fatal(SB_FORMAT_ERROR, "Bad signature\n");
if(sb_header->image_size * BLOCK_SIZE > filesize)
fatal("File too small mismatch");
fatal(SB_FORMAT_ERROR, "File too small");
if(sb_header->header_size * BLOCK_SIZE != sizeof(struct sb_header_t))
fatal("Bad header size");
fatal(SB_FORMAT_ERROR, "Bad header size");
if(sb_header->sec_hdr_size * BLOCK_SIZE != sizeof(struct sb_section_header_t))
fatal("Bad section header size");
fatal(SB_FORMAT_ERROR, "Bad section header size");
if(filesize > sb_header->image_size * BLOCK_SIZE)
{
@ -707,67 +740,86 @@ struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
/* encryption cbc-mac */
byte real_key[16];
bool valid_key = false; /* false until a matching key was found */
if(sb_header->nr_keys > 0)
{
if(sb_header->nr_keys > g_nr_keys)
{
fatal("SB file has %d keys but only %d were specified\n",
sb_header->nr_keys, g_nr_keys);
}
printf(BLUE, "Encryption data\n");
for(int i = 0; i < sb_header->nr_keys; i++)
byte (*cbcmacs)[16] = xmalloc(16 * g_nr_keys);
printf(BLUE, "Encryption keys\n");
for(int i = 0; i < g_nr_keys; i++)
{
printf(RED, " Key %d: ", i);
printf(YELLOW, "");
print_key(&g_key_array[i], true);
printf(GREEN, " CBC-MAC of headers: ");
printf(GREEN, " CBC-MAC: ");
/* check it */
byte zero[16];
memset(zero, 0, 16);
int ret = crypto_cbc(buf, NULL, sb_header->header_size + sb_header->nr_sections,
&g_key_array[i], zero, &cbcmacs[i], 1);
if(ret != CRYPTO_ERROR_SUCCESS)
{
free(cbcmacs);
fatal(SB_FIRST_CRYPTO_ERROR + ret, "Crypto error: %d", ret);
}
print_hex(YELLOW, cbcmacs[i], 16, true);
}
printf(BLUE, "DEK\n");
for(int i = 0; i < sb_header->nr_keys; i++)
{
printf(RED, " Entry %d\n", i);
uint32_t ofs = sizeof(struct sb_header_t)
+ sizeof(struct sb_section_header_t) * sb_header->nr_sections
+ sizeof(struct sb_key_dictionary_entry_t) * i;
struct sb_key_dictionary_entry_t *dict_entry =
(struct sb_key_dictionary_entry_t *)&buf[ofs];
/* cbc mac */
print_hex(YELLOW, dict_entry->hdr_cbc_mac, 16, false);
/* check it */
byte computed_cbc_mac[16];
byte zero[16];
memset(zero, 0, 16);
crypto_cbc(buf, NULL, sb_header->header_size + sb_header->nr_sections,
&g_key_array[i], zero, &computed_cbc_mac, 1);
bool ok = memcmp(dict_entry->hdr_cbc_mac, computed_cbc_mac, 16) == 0;
if(ok)
{
valid_key = true;
printf(RED, " Ok\n");
}
else
printf(RED, " Failed\n");
printf(GREEN, " Encrypted key: ");
print_hex(YELLOW, dict_entry->key, 16, true);
printf(GREEN, " CBC-MAC : ");
print_hex(YELLOW, dict_entry->hdr_cbc_mac, 16, false);
/* check it */
int idx = 0;
while(idx < g_nr_keys && memcmp(dict_entry->hdr_cbc_mac, cbcmacs[idx], 16) != 0)
idx++;
if(idx != g_nr_keys)
{
printf(RED, " Match\n");
/* decrypt */
byte decrypted_key[16];
byte iv[16];
memcpy(iv, buf, 16); /* uses the first 16-bytes of SHA-1 sig as IV */
crypto_cbc(dict_entry->key, decrypted_key, 1, &g_key_array[i], iv, NULL, 0);
int ret = crypto_cbc(dict_entry->key, decrypted_key, 1, &g_key_array[idx], iv, NULL, 0);
if(ret != CRYPTO_ERROR_SUCCESS)
{
free(cbcmacs);
fatal(SB_FIRST_CRYPTO_ERROR + ret, "Crypto error: %d\n", ret);
}
printf(GREEN, " Decrypted key: ");
print_hex(YELLOW, decrypted_key, 16, false);
/* cross-check or copy */
if(valid_key && ok)
memcpy(real_key, decrypted_key, 16);
else if(valid_key)
if(valid_key)
{
if(memcmp(real_key, decrypted_key, 16) == 0)
printf(RED, " Cross-Check Ok");
else
printf(RED, " Cross-Check Failed");
}
else
{
memcpy(real_key, decrypted_key, 16);
valid_key = true;
}
printf(OFF, "\n");
}
else
printf(RED, " Don't Match\n");
}
free(cbcmacs);
if(!valid_key)
fatal(SB_NO_VALID_KEY, "No valid key found\n");
if(getenv("SB_REAL_KEY") != 0)
{
struct crypto_key_t k;
@ -783,10 +835,11 @@ struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
printf(GREEN, " IV : ");
print_hex(YELLOW, buf, 16, true);
sb_file->real_key = xmalloc(16);
memcpy(*sb_file->real_key, real_key, 16);
sb_file->crypto_iv = xmalloc(16);
memcpy(*sb_file->crypto_iv, buf, 16);
sb_file->override_real_key = true;
memcpy(sb_file->real_key, real_key, 16);
sb_file->override_crypto_iv = true;
memcpy(sb_file->crypto_iv, buf, 16);
}
/* sections */
if(!raw_mode)
@ -831,7 +884,7 @@ struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
memcpy(sec, buf + pos, size);
struct sb_section_t *s = read_section(data_sec, sec_hdr->identifier,
sec, size, " ", u, cprintf);
sec, size, " ", u, cprintf, err);
if(s)
{
s->is_cleartext = !encrypted;
@ -839,6 +892,8 @@ struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
memcpy(&sb_file->sections[i], s, sizeof(struct sb_section_t));
free(s);
}
else
fatal(*err, "Error reading section\n");
free(sec);
}
@ -919,7 +974,7 @@ struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
memcpy(sec, buf + pos, size);
struct sb_section_t *s = read_section(data_sec, tag->identifier,
sec, size, " ", u, cprintf);
sec, size, " ", u, cprintf, err);
if(s)
{
s->is_cleartext = !encrypted;
@ -929,6 +984,8 @@ struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
s, 1);
free(s);
}
else
fatal(*err, "Error reading section\n");
free(sec);
/* last one ? */
@ -938,7 +995,7 @@ struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
}
else
{
printf(RED, "Unknown instruction %d at address 0x%08lx\n", hdr->opcode, (long)offset);
fatal(SB_FORMAT_ERROR, "Unknown instruction %d at address 0x%08lx\n", hdr->opcode, (long)offset);
break;
}
}
@ -970,7 +1027,10 @@ struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
if(memcmp(decrypted_block, computed_sha1, 20) == 0)
printf(RED, " Ok\n");
else
{
printf(RED, " Failed\n");
fatal(SB_CHECKSUM_ERROR, "File SHA-1 error\n");
}
free(buf);
return sb_file;
@ -979,6 +1039,27 @@ struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
#undef print_hex
}
void sb_free_section(struct sb_section_t sec)
{
for(int j = 0; j < sec.nr_insts; j++)
{
free(sec.insts[j].padding);
free(sec.insts[j].data);
}
free(sec.insts);
}
void sb_free(struct sb_file_t *file)
{
if(!file) return;
for(int i = 0; i < file->nr_sections; i++)
sb_free_section(file->sections[i]);
free(file->sections);
free(file);
}
void sb_dump(struct sb_file_t *file, void *u, sb_color_printf cprintf)
{
#define printf(c, ...) cprintf(u, false, c, __VA_ARGS__)
@ -1007,17 +1088,17 @@ void sb_dump(struct sb_file_t *file, void *u, sb_color_printf cprintf)
sb_fill_section_name(name, file->first_boot_sec_id);
printf(TEXT, "%08x (%s)\n", file->first_boot_sec_id, name);
if(file->real_key)
if(file->override_real_key)
{
printf(TREE, "+-");
printf(HEADER, "Real key: ");
print_hex(TEXT, *file->real_key, 16, true);
print_hex(TEXT, file->real_key, 16, true);
}
if(file->crypto_iv)
if(file->override_crypto_iv)
{
printf(TREE, "+-");
printf(HEADER, "IV : ");
print_hex(TEXT, *file->crypto_iv, 16, true);
print_hex(TEXT, file->crypto_iv, 16, true);
}
printf(TREE, "+-");
printf(HEADER, "Product Version: ");

View file

@ -191,9 +191,11 @@ struct sb_section_t
struct sb_file_t
{
/* override real, otherwise it is randomly generated */
uint8_t (*real_key)[16];
bool override_real_key;
uint8_t real_key[16];
/* override crypto IV, use with caution ! Use NULL to generate it */
uint8_t (*crypto_iv)[16];
bool override_crypto_iv;
uint8_t crypto_iv[16];
int nr_sections;
uint16_t drive_tag;
@ -207,13 +209,29 @@ struct sb_file_t
uint32_t image_size; /* in blocks */
};
void sb_write_file(struct sb_file_t *sb, const char *filename);
enum sb_error_t
{
SB_SUCCESS = 0,
SB_ERROR = -1,
SB_OPEN_ERROR = -2,
SB_READ_ERROR = -3,
SB_WRITE_ERROR = -4,
SB_FORMAT_ERROR = -5,
SB_CHECKSUM_ERROR = -6,
SB_NO_VALID_KEY = -7,
SB_FIRST_CRYPTO_ERROR = -8,
SB_LAST_CRYPTO_ERROR = SB_FIRST_CRYPTO_ERROR - CRYPTO_NUM_ERRORS,
};
enum sb_error_t sb_write_file(struct sb_file_t *sb, const char *filename);
typedef void (*sb_color_printf)(void *u, bool err, color_t c, const char *f, ...);
struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
sb_color_printf printf);
sb_color_printf printf, enum sb_error_t *err);
void sb_fill_section_name(char name[5], uint32_t identifier);
void sb_dump(struct sb_file_t *file, void *u, sb_color_printf printf);
void sb_free_section(struct sb_section_t file);
void sb_free(struct sb_file_t *file);
#endif /* __SB_H__ */

View file

@ -268,7 +268,15 @@ int main(int argc, char **argv)
const char *sb_filename = argv[optind];
struct sb_file_t *file = sb_read_file(sb_filename, raw_mode, NULL, sb_printf);
enum sb_error_t err;
struct sb_file_t *file = sb_read_file(sb_filename, raw_mode, NULL, sb_printf, &err);
if(file == NULL)
{
color(OFF);
printf("SB read failed: %d\n", err);
return 1;
}
color(OFF);
if(g_out_prefix)
extract_sb_file(file);
@ -283,12 +291,12 @@ int main(int argc, char **argv)
/* sb_read_file will fill real key and IV but we don't want to override
* them when looping back otherwise the output will be inconsistent and
* garbage */
free(file->real_key);
file->real_key = NULL;
free(file->crypto_iv);
file->crypto_iv = NULL;
file->override_real_key = false;
file->override_crypto_iv = false;
sb_write_file(file, loopback);
}
sb_free(file);
clear_keys();
return 0;
}