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 LD=gcc
CFLAGS=-g -std=c99 -W -Wall `pkg-config --cflags libusb-1.0` $(DEFINES) CFLAGS=-g -std=c99 -W -Wall `pkg-config --cflags libusb-1.0` $(DEFINES)
LDFLAGS=`pkg-config --libs libusb-1.0` LDFLAGS=`pkg-config --libs libusb-1.0`
BINS=elftosb sbtoelf sbloader
all: elftosb sbtoelf all: $(BINS)
%.o: %.c %.o: %.c
$(CC) $(CFLAGS) -c -o $@ $< $(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 elftosb: elftosb.o crc.o crypto.o aes128.o sha1.o elf.o dbparser.o misc.o sb.o
$(LD) -o $@ $^ $(LDFLAGS) $(LD) -o $@ $^ $(LDFLAGS)
sbloader: sbloader.o
$(LD) -o $@ $^ $(LDFLAGS)
clean: clean:
rm -fr *.o rm -fr *.o
veryclean: 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_DEVREJECT -5 /* device rejected cypto operation */
#define CRYPTO_ERROR_DEVSILENT -6 /* device did not notify completion */ #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_ERROR_DEVERR -7 /* device did something wrong (like return too small buffer) */
#define CRYPTO_NUM_ERRORS 8
/* return 0 on success, <0 on error */ /* return 0 on success, <0 on error */
int crypto_apply( int crypto_apply(
byte *in_data, /* Input data */ byte *in_data, /* Input data */

View file

@ -19,6 +19,7 @@
* *
****************************************************************************/ ****************************************************************************/
#define _POSIX_C_SOURCE 200809L /* for strdup */
#include <stdio.h> #include <stdio.h>
#include <ctype.h> #include <ctype.h>
#include <stdint.h> #include <stdint.h>
@ -48,6 +49,7 @@ enum lexem_type_t
struct lexem_t struct lexem_t
{ {
enum lexem_type_t type; enum lexem_type_t type;
/* if str is not NULL, it must be a malloc'd pointer */
char *str; char *str;
uint32_t num; uint32_t num;
int line; int line;
@ -390,8 +392,15 @@ struct lex_ctx_t
struct lexem_t lexem; 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); 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 else
parse_error(ctx->lexem, "Number or constant identifier expected\n"); parse_error(ctx->lexem, "Number or constant identifier expected\n");
next(ctx); next(ctx, true);
return ret; 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); uint32_t v = parse_term_expr(ctx, const_list);
while(ctx->lexem.type == LEX_LSHIFT) while(ctx->lexem.type == LEX_LSHIFT)
{ {
next(ctx); next(ctx, true);
v <<= parse_term_expr(ctx, const_list); v <<= parse_term_expr(ctx, const_list);
} }
return v; 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); uint32_t v = parse_shift_expr(ctx, const_list);
while(ctx->lexem.type == LEX_OR) while(ctx->lexem.type == LEX_OR)
{ {
next(ctx); next(ctx, true);
v |= parse_shift_expr(ctx, const_list); v |= parse_shift_expr(ctx, const_list);
} }
return v; 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)); struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t));
memset(opt, 0, 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->is_string = false;
opt->val = init_const_value[i]; opt->val = init_const_value[i];
opt->next = cmd_file->constant_list; 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.begin = buf;
lctx.ctx.ptr = buf; lctx.ctx.ptr = buf;
lctx.ctx.end = buf + size; lctx.ctx.end = buf + size;
#define next() next(&lctx) #define next(clean_lexem) next(&lctx, clean_lexem)
#define lexem lctx.lexem #define lexem lctx.lexem
/* init lexer */ /* init lexer */
next(); next(false); /* don't clean init lexem because it doesn't exist */
/* constants ? */ /* constants ? */
if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "constants")) if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "constants"))
{ {
next(); next(true);
if(lexem.type != LEX_LBRACE) if(lexem.type != LEX_LBRACE)
parse_error(lexem, "'{' expected after 'constants'\n"); 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)); struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t));
memset(opt, 0, sizeof(struct cmd_option_t)); memset(opt, 0, sizeof(struct cmd_option_t));
next(); next(true);
if(lexem.type == LEX_RBRACE) if(lexem.type == LEX_RBRACE)
break; break;
if(lexem.type != LEX_IDENTIFIER) if(lexem.type != LEX_IDENTIFIER)
parse_error(lexem, "Identifier expected in constants\n"); parse_error(lexem, "Identifier expected in constants\n");
opt->name = lexem.str; opt->name = lexem.str;
next(); next(false); /* lexem string is kept as option name */
if(lexem.type != LEX_EQUAL) if(lexem.type != LEX_EQUAL)
parse_error(lexem, "'=' expected after identifier\n"); parse_error(lexem, "'=' expected after identifier\n");
next(); next(true);
opt->is_string = false; opt->is_string = false;
opt->val = parse_intexpr(&lctx, cmd_file->constant_list); opt->val = parse_intexpr(&lctx, cmd_file->constant_list);
opt->next = 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) if(lexem.type != LEX_SEMICOLON)
parse_error(lexem, "';' expected after string\n"); parse_error(lexem, "';' expected after string\n");
} }
next(); next(true);
} }
/* options ? */ /* options ? */
if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "options")) if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "options"))
{ {
next(); next(true);
if(lexem.type != LEX_LBRACE) if(lexem.type != LEX_LBRACE)
parse_error(lexem, "'{' expected after 'options'\n"); parse_error(lexem, "'{' expected after 'options'\n");
while(true) while(true)
{ {
struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t)); next(true);
memset(opt, 0, sizeof(struct cmd_option_t));
next();
if(lexem.type == LEX_RBRACE) if(lexem.type == LEX_RBRACE)
break; 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) if(lexem.type != LEX_IDENTIFIER)
parse_error(lexem, "Identifier expected in options\n"); parse_error(lexem, "Identifier expected in options\n");
opt->name = lexem.str; opt->name = lexem.str;
next(); next(false); /* lexem string is kept as option name */
if(lexem.type != LEX_EQUAL) if(lexem.type != LEX_EQUAL)
parse_error(lexem, "'=' expected after identifier\n"); parse_error(lexem, "'=' expected after identifier\n");
next(); next(true);
if(lexem.type == LEX_STRING) if(lexem.type == LEX_STRING)
{ {
opt->is_string = true; opt->is_string = true;
opt->str = lexem.str; opt->str = lexem.str;
next(); next(false); /* lexem string is kept as option name */
} }
else else
{ {
@ -554,18 +563,18 @@ struct cmd_file_t *db_parse_file(const char *file)
if(lexem.type != LEX_SEMICOLON) if(lexem.type != LEX_SEMICOLON)
parse_error(lexem, "';' expected after string\n"); parse_error(lexem, "';' expected after string\n");
} }
next(); next(true);
} }
/* sources */ /* sources */
if(lexem.type != LEX_IDENTIFIER || strcmp(lexem.str, "sources")) if(lexem.type != LEX_IDENTIFIER || strcmp(lexem.str, "sources"))
parse_error(lexem, "'sources' expected\n"); parse_error(lexem, "'sources' expected\n");
next(); next(true);
if(lexem.type != LEX_LBRACE) if(lexem.type != LEX_LBRACE)
parse_error(lexem, "'{' expected after 'sources'\n"); parse_error(lexem, "'{' expected after 'sources'\n");
while(true) while(true)
{ {
next(); next(true);
if(lexem.type == LEX_RBRACE) if(lexem.type == LEX_RBRACE)
break; break;
struct cmd_source_t *src = xmalloc(sizeof(struct cmd_source_t)); 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) if(lexem.type != LEX_IDENTIFIER)
parse_error(lexem, "identifier expected in sources\n"); parse_error(lexem, "identifier expected in sources\n");
src->identifier = lexem.str; src->identifier = lexem.str;
next(); next(false); /* lexem string is kept as source name */
if(lexem.type != LEX_EQUAL) if(lexem.type != LEX_EQUAL)
parse_error(lexem, "'=' expected after identifier\n"); parse_error(lexem, "'=' expected after identifier\n");
next(); next(true);
if(lexem.type == LEX_STRING) if(lexem.type == LEX_STRING)
{ {
src->is_extern = false; src->is_extern = false;
src->filename = lexem.str; src->filename = lexem.str;
next(); next(false); /* lexem string is kept as file name */
} }
else if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "extern")) else if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "extern"))
{ {
src->is_extern = true; src->is_extern = true;
src->filename = "<extern>"; src->filename = strdup("<extern>"); /* duplicate because it will be free'd */
next(); next(true);
if(lexem.type != LEX_LPAREN) if(lexem.type != LEX_LPAREN)
parse_error(lexem, "'(' expected after 'extern'\n"); parse_error(lexem, "'(' expected after 'extern'\n");
next(); next(true);
src->extern_nr = parse_intexpr(&lctx, cmd_file->constant_list); src->extern_nr = parse_intexpr(&lctx, cmd_file->constant_list);
if(lexem.type != LEX_RPAREN) if(lexem.type != LEX_RPAREN)
parse_error(lexem, "')' expected\n"); parse_error(lexem, "')' expected\n");
next(); next(true);
} }
else else
parse_error(lexem, "String or 'extern' expected after '='\n"); 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; struct cmd_section_t *end_sec = NULL;
while(true) while(true)
{ {
next(true);
if(lexem.type == LEX_EOF)
break;
struct cmd_section_t *sec = xmalloc(sizeof(struct cmd_section_t)); struct cmd_section_t *sec = xmalloc(sizeof(struct cmd_section_t));
struct cmd_inst_t *end_list = NULL; struct cmd_inst_t *end_list = NULL;
memset(sec, 0, sizeof(struct cmd_section_t)); 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) if(lexem.type != LEX_IDENTIFIER || strcmp(lexem.str, "section") != 0)
parse_error(lexem, "'section' expected\n"); parse_error(lexem, "'section' expected\n");
next(); next(true);
if(lexem.type != LEX_LPAREN) if(lexem.type != LEX_LPAREN)
parse_error(lexem, "'(' expected after 'section'\n"); parse_error(lexem, "'(' expected after 'section'\n");
next(); next(true);
/* can be any number */ /* can be any number */
sec->identifier = parse_intexpr(&lctx, cmd_file->constant_list); sec->identifier = parse_intexpr(&lctx, cmd_file->constant_list);
/* options ? */ /* options ? */
@ -631,21 +640,21 @@ struct cmd_file_t *db_parse_file(const char *file)
{ {
do do
{ {
next(); next(true);
struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t)); struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t));
memset(opt, 0, sizeof(struct cmd_option_t)); memset(opt, 0, sizeof(struct cmd_option_t));
if(lexem.type != LEX_IDENTIFIER) if(lexem.type != LEX_IDENTIFIER)
parse_error(lexem, "Identifier expected for section option\n"); parse_error(lexem, "Identifier expected for section option\n");
opt->name = lexem.str; opt->name = lexem.str;
next(); next(false); /* lexem string is kept as option name */
if(lexem.type != LEX_EQUAL) if(lexem.type != LEX_EQUAL)
parse_error(lexem, "'=' expected after option identifier\n"); parse_error(lexem, "'=' expected after option identifier\n");
next(); next(true);
if(lexem.type == LEX_STRING) if(lexem.type == LEX_STRING)
{ {
opt->is_string = true; opt->is_string = true;
opt->str = lexem.str; opt->str = lexem.str;
next(); next(false); /* lexem string is kept as option string */
} }
else else
{ {
@ -658,18 +667,18 @@ struct cmd_file_t *db_parse_file(const char *file)
} }
if(lexem.type != LEX_RPAREN) if(lexem.type != LEX_RPAREN)
parse_error(lexem, "')' expected after section identifier\n"); parse_error(lexem, "')' expected after section identifier\n");
next(); next(true);
if(lexem.type == LEX_LBRACE) if(lexem.type == LEX_LBRACE)
{ {
sec->is_data = false; sec->is_data = false;
/* commands */ /* commands */
while(true) while(true)
{ {
struct cmd_inst_t *inst = xmalloc(sizeof(struct cmd_inst_t)); next(true);
memset(inst, 0, sizeof(struct cmd_inst_t));
next();
if(lexem.type == LEX_RBRACE) if(lexem.type == LEX_RBRACE)
break; 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) if(lexem.type != LEX_IDENTIFIER)
parse_error(lexem, "Instruction expected in section\n"); parse_error(lexem, "Instruction expected in section\n");
if(strcmp(lexem.str, "load") == 0) if(strcmp(lexem.str, "load") == 0)
@ -682,7 +691,7 @@ struct cmd_file_t *db_parse_file(const char *file)
inst->type = CMD_MODE; inst->type = CMD_MODE;
else else
parse_error(lexem, "Instruction expected in section\n"); parse_error(lexem, "Instruction expected in section\n");
next(); next(true);
if(inst->type == CMD_LOAD) if(inst->type == CMD_LOAD)
{ {
@ -691,12 +700,12 @@ struct cmd_file_t *db_parse_file(const char *file)
inst->identifier = lexem.str; inst->identifier = lexem.str;
if(db_find_source_by_id(cmd_file, inst->identifier) == NULL) if(db_find_source_by_id(cmd_file, inst->identifier) == NULL)
parse_error(lexem, "Undefined reference to source '%s'\n", inst->identifier); parse_error(lexem, "Undefined reference to source '%s'\n", inst->identifier);
next(); next(false); /* lexem string kept as identifier */
if(lexem.type == LEX_RANGLE) if(lexem.type == LEX_RANGLE)
{ {
// load at // load at
inst->type = CMD_LOAD_AT; inst->type = CMD_LOAD_AT;
next(); next(true);
inst->addr = parse_intexpr(&lctx, cmd_file->constant_list); inst->addr = parse_intexpr(&lctx, cmd_file->constant_list);
} }
if(lexem.type != LEX_SEMICOLON) if(lexem.type != LEX_SEMICOLON)
@ -709,7 +718,7 @@ struct cmd_file_t *db_parse_file(const char *file)
inst->identifier = lexem.str; inst->identifier = lexem.str;
if(db_find_source_by_id(cmd_file, inst->identifier) == NULL) if(db_find_source_by_id(cmd_file, inst->identifier) == NULL)
parse_error(lexem, "Undefined reference to source '%s'\n", inst->identifier); parse_error(lexem, "Undefined reference to source '%s'\n", inst->identifier);
next(); next(false); /* lexem string kept as identifier */
} }
else else
{ {
@ -719,11 +728,11 @@ struct cmd_file_t *db_parse_file(const char *file)
if(lexem.type == LEX_LPAREN) if(lexem.type == LEX_LPAREN)
{ {
next(); next(true);
inst->argument = parse_intexpr(&lctx, cmd_file->constant_list); inst->argument = parse_intexpr(&lctx, cmd_file->constant_list);
if(lexem.type != LEX_RPAREN) if(lexem.type != LEX_RPAREN)
parse_error(lexem, "Expected closing brace\n"); parse_error(lexem, "Expected closing brace\n");
next(); next(true);
} }
if(lexem.type != LEX_SEMICOLON) if(lexem.type != LEX_SEMICOLON)
parse_error(lexem, "';' expected after command\n"); 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) else if(lexem.type == LEX_LE)
{ {
sec->is_data = true; sec->is_data = true;
next(); next(true);
if(lexem.type != LEX_IDENTIFIER) if(lexem.type != LEX_IDENTIFIER)
parse_error(lexem, "Identifier expected after '<='\n"); parse_error(lexem, "Identifier expected after '<='\n");
sec->source_id = lexem.str; sec->source_id = lexem.str;
next(); next(false); /* lexem string is kept as source id */
if(lexem.type != LEX_SEMICOLON) if(lexem.type != LEX_SEMICOLON)
parse_error(lexem, "';' expected after identifier\n"); parse_error(lexem, "';' expected after identifier\n");
} }
@ -776,6 +785,7 @@ struct cmd_file_t *db_parse_file(const char *file)
#undef lexem #undef lexem
#undef next #undef next
free(buf);
return cmd_file; 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; 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_file_t
{ {
struct cmd_option_t *opt_list; 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_source_t *source_list;
struct cmd_section_t *section_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); bool db_parse_sb_version(struct sb_version_t *ver, char *str);
void db_generate_default_sb_version(struct sb_version_t *ver); void db_generate_default_sb_version(struct sb_version_t *ver);
struct cmd_file_t *db_parse_file(const char *file); 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__ */ #endif /* __DBPARSER__ */

View file

@ -153,10 +153,7 @@ typedef struct
void elf_init(struct elf_params_t *params) void elf_init(struct elf_params_t *params)
{ {
params->has_start_addr = false; memset(params, 0, sizeof(struct elf_params_t));
params->start_addr = 0;
params->first_section = NULL;
params->last_section = NULL;
} }
extern void *xmalloc(size_t s); 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)) if(!read(user, shdr.sh_offset, data, shdr.sh_size))
error_printf("error read self section data\n"); error_printf("error read self section data\n");
elf_add_load_section(params, shdr.sh_addr, shdr.sh_size, data); elf_add_load_section(params, shdr.sh_addr, shdr.sh_size, data);
free(data);
if(strtab) if(strtab)
printf(user, false, "create load segment for %s\n", &strtab[shdr.sh_name]); 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 */ /* run through segments */
for(int i = 1; i < ehdr.e_phnum; i++) 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) void elf_release(struct elf_params_t *params)
{ {
struct elf_section_t *sec, *next_sec; struct elf_section_t *sec = params->first_section;
sec = params->first_section;
while(sec) while(sec)
{ {
next_sec = sec->next; struct elf_section_t *next_sec = sec->next;
if(sec->type == EST_LOAD) if(sec->type == EST_LOAD)
free(sec->section); free(sec->section);
free(sec); free(sec);
sec = next_sec; sec = next_sec;
} }
params->first_section = NULL; struct elf_segment_t *seg = params->first_segment;
params->last_section = NULL; 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 _ISOC99_SOURCE
#define _POSIX_C_SOURCE 200809L /* for strdup */
#include <stdio.h> #include <stdio.h>
#include <errno.h> #include <errno.h>
#include <stdlib.h> #include <stdlib.h>
@ -77,7 +78,9 @@ static void resolve_extern(struct cmd_source_t *src)
src->is_extern = false; src->is_extern = false;
if(src->extern_nr < 0 || src->extern_nr >= g_extern_count) 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); 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) 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].inst = SB_INST_DATA;
sec->insts[0].size = bin->size; sec->insts[0].size = bin->size;
sec->insts[0].data = bin->data; sec->insts[0].data = memdup(bin->data, bin->size);
} }
else 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].inst = SB_INST_LOAD;
sec->insts[idx].addr = esec->addr; sec->insts[idx].addr = esec->addr;
sec->insts[idx].size = esec->size; 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) 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; 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].inst = SB_INST_LOAD;
sec->insts[idx].addr = cinst->addr; 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; sec->insts[idx++].size = bin->size;
} }
else if(cinst->type == CMD_MODE) 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 cmd_file_t *cmd_file = db_parse_file(cmd_filename);
struct sb_file_t *sb_file = apply_cmd_file(cmd_file); struct sb_file_t *sb_file = apply_cmd_file(cmd_file);
db_free(cmd_file);
if(real_key.method == CRYPTO_KEY) 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) 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 */ /* fill with default parameters since there is no command file support for them */
sb_file->drive_tag = 0; sb_file->drive_tag = 0;
@ -444,6 +454,8 @@ int main(int argc, char **argv)
sb_file->minor_version = 1; sb_file->minor_version = 1;
sb_write_file(sb_file, output_filename); sb_write_file(sb_file, output_filename);
sb_free(sb_file);
clear_keys();
return 0; return 0;
} }

View file

@ -29,6 +29,14 @@ bool g_debug = false;
/** /**
* Misc * 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) void generate_random_data(void *buf, size_t sz)
{ {
FILE *rand_fd = fopen("/dev/urandom", "rb"); FILE *rand_fd = fopen("/dev/urandom", "rb");
@ -144,6 +152,12 @@ void add_keys(key_array_t ka, int kac)
g_nr_keys += 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) void add_keys_from_file(const char *key_file)
{ {
int size; int size;

View file

@ -38,6 +38,7 @@ typedef struct crypto_key_t *key_array_t;
int g_nr_keys; int g_nr_keys;
key_array_t g_key_array; 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 *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 generate_random_data(void *buf, size_t sz);
void *xmalloc(size_t s); 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); bool parse_key(char **str, struct crypto_key_t *key);
void add_keys_from_file(const char *key_file); void add_keys_from_file(const char *key_file);
void print_key(struct crypto_key_t *key, bool newline); void print_key(struct crypto_key_t *key, bool newline);
void clear_keys();
typedef char color_t[]; 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) if(sb->sections[i].is_data)
{ {
nr_aug_insts = 1; 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)); memset(aug_insts, 0, sizeof(struct sb_inst_t));
aug_insts[0].inst = SB_INST_DATA; aug_insts[0].inst = SB_INST_DATA;
aug_insts[0].size = missing_sz * BLOCK_SIZE; aug_insts[0].size = missing_sz * BLOCK_SIZE;
@ -150,7 +150,7 @@ static void compute_sb_offsets(struct sb_file_t *sb)
else else
{ {
nr_aug_insts = missing_sz; 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); memset(aug_insts, 0, sizeof(struct sb_inst_t) * nr_aug_insts);
for(int j = 0; j < nr_aug_insts; j++) 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].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, aug_insts, nr_aug_insts);
sb->sections[i].nr_insts += nr_aug_insts; sb->sections[i].nr_insts += nr_aug_insts;
free(aug_insts);
/* augment image and section size */ /* augment image and section size */
sb->image_size += missing_sz; 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); 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; struct crypto_key_t real_key;
real_key.method = CRYPTO_KEY; real_key.method = CRYPTO_KEY;
byte crypto_iv[16]; byte crypto_iv[16];
@ -324,8 +321,13 @@ void sb_write_file(struct sb_file_t *sb, const char *filename)
/* produce and write header */ /* produce and write header */
struct sb_header_t sb_hdr; struct sb_header_t sb_hdr;
produce_sb_header(sb, &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)); 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); 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; struct sb_section_header_t sb_sec_hdr;
produce_sb_section_header(&sb->sections[i], &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)); 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 */ /* update CBC-MACs */
for(int j = 0; j < g_nr_keys; j++) for(int j = 0; j < g_nr_keys; j++)
crypto_cbc((byte *)&sb_sec_hdr, NULL, sizeof(sb_sec_hdr) / BLOCK_SIZE, 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_cbc(real_key.u.key, entry.key, 1, &g_key_array[i],
crypto_iv, NULL, 1); crypto_iv, NULL, 1);
fwrite(&entry, 1, sizeof(entry), fd); write(&entry, sizeof(entry));
sha_1_update(&file_sha1, (byte *)&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 */ /* 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 */ /* Image crafting, don't use it unless you understand what you do */
if(sb->real_key != NULL) if(sb->override_real_key)
memcpy(real_key.u.key, *sb->real_key, 16); memcpy(real_key.u.key, sb->real_key, 16);
if(sb->crypto_iv != NULL) if(sb->override_crypto_iv)
memcpy(crypto_iv, *sb->crypto_iv, 16); memcpy(crypto_iv, sb->crypto_iv, 16);
/* KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH */ /* KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH */
if(g_debug) 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, crypto_cbc((byte *)&tag_cmd, (byte *)&tag_cmd, sizeof(tag_cmd) / BLOCK_SIZE,
&real_key, crypto_iv, NULL, 1); &real_key, crypto_iv, NULL, 1);
sha_1_update(&file_sha1, (byte *)&tag_cmd, sizeof(tag_cmd)); 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 */ /* produce other commands */
byte cur_cbc_mac[16]; byte cur_cbc_mac[16];
memcpy(cur_cbc_mac, crypto_iv, 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, crypto_cbc((byte *)&cmd, (byte *)&cmd, sizeof(cmd) / BLOCK_SIZE,
&real_key, cur_cbc_mac, &cur_cbc_mac, 1); &real_key, cur_cbc_mac, &cur_cbc_mac, 1);
sha_1_update(&file_sha1, (byte *)&cmd, sizeof(cmd)); sha_1_update(&file_sha1, (byte *)&cmd, sizeof(cmd));
fwrite(&cmd, 1, sizeof(cmd), fd); write(&cmd, sizeof(cmd));
} }
/* data */ /* data */
if(inst->inst == SB_INST_LOAD || inst->inst == SB_INST_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, crypto_cbc(data, data, sz / BLOCK_SIZE,
&real_key, cur_cbc_mac, &cur_cbc_mac, 1); &real_key, cur_cbc_mac, &cur_cbc_mac, 1);
sha_1_update(&file_sha1, data, sz); sha_1_update(&file_sha1, data, sz);
fwrite(data, 1, sz, fd); write(data, sz);
free(data); 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); generate_random_data(final_sig + 20, 12);
if(g_nr_keys > 0) if(g_nr_keys > 0)
crypto_cbc(final_sig, final_sig, 2, &real_key, crypto_iv, NULL, 1); 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);
}
static void *memdup(void *p, size_t len) if(buf_p - buf != sb_hdr.image_size * BLOCK_SIZE)
{ bug("SB image buffer was not entirely filled !");
void *cpy = xmalloc(len);
memcpy(cpy, p, len); FILE *fd = fopen(filename, "wb");
return cpy; if(fd == NULL)
return SB_OPEN_ERROR;
if(fwrite(buf, sb_hdr.image_size * BLOCK_SIZE, 1, fd) != 1)
{
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, 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 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)); struct sb_section_t *sec = xmalloc(sizeof(struct sb_section_t));
memset(sec, 0, 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); printf(OFF, "%s", indent);
uint8_t checksum = instruction_checksum(hdr); uint8_t checksum = instruction_checksum(hdr);
if(checksum != hdr->checksum) if(checksum != hdr->checksum)
printf(GREY, "[Bad checksum]"); fatal(SB_CHECKSUM_ERROR, "Bad instruction checksum");
if(hdr->flags != 0) if(hdr->flags != 0)
{ {
printf(GREY, "["); 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) if(load->crc == computed_crc)
printf(RED, " Ok\n"); printf(RED, " Ok\n");
else else
{
printf(RED, " Failed (crc=0x%08x)\n", computed_crc); 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); 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 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; break;
} }
@ -569,6 +589,7 @@ static struct sb_section_t *read_section(bool data_sec, uint32_t id, byte *buf,
return sec; return sec;
#undef printf #undef printf
#undef fatal
} }
void sb_fill_section_name(char name[5], uint32_t identifier) 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, 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 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) \ #define print_hex(c, p, len, nl) \
do { printf(c, ""); print_hex(p, len, nl); } while(0) do { printf(c, ""); print_hex(p, len, nl); } while(0)
FILE *f = fopen(filename, "rb"); FILE *f = fopen(filename, "rb");
if(f == NULL) 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); fseek(f, 0, SEEK_END);
long filesize = ftell(f); long filesize = ftell(f);
fseek(f, 0, SEEK_SET); fseek(f, 0, SEEK_SET);
uint8_t *buf = xmalloc(filesize); buf = xmalloc(filesize);
fread(buf, 1, filesize, f); if(fread(buf, filesize, 1, f) != 1)
{
fclose(f);
fatal(SB_READ_ERROR, "Cannot read file\n");
}
fclose(f); fclose(f);
struct sha_1_params_t sha_1_params; 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)); memset(sb_file, 0, sizeof(struct sb_file_t));
struct sb_header_t *sb_header = (struct sb_header_t *)buf; 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; sb_file->first_boot_sec_id = sb_header->first_boot_sec_id;
if(memcmp(sb_header->signature, "STMP", 4) != 0) 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) 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)) 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)) 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) if(filesize > sb_header->image_size * BLOCK_SIZE)
{ {
@ -707,87 +740,107 @@ struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
/* encryption cbc-mac */ /* encryption cbc-mac */
byte real_key[16]; byte real_key[16];
bool valid_key = false; /* false until a matching key was found */ bool valid_key = false; /* false until a matching key was found */
if(sb_header->nr_keys > 0) if(sb_header->nr_keys > 0)
{ {
if(sb_header->nr_keys > g_nr_keys) byte (*cbcmacs)[16] = xmalloc(16 * g_nr_keys);
{ printf(BLUE, "Encryption keys\n");
fatal("SB file has %d keys but only %d were specified\n", for(int i = 0; i < g_nr_keys; i++)
sb_header->nr_keys, g_nr_keys);
}
printf(BLUE, "Encryption data\n");
for(int i = 0; i < sb_header->nr_keys; i++)
{ {
printf(RED, " Key %d: ", i); printf(RED, " Key %d: ", i);
printf(YELLOW, ""); printf(YELLOW, "");
print_key(&g_key_array[i], true); 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) uint32_t ofs = sizeof(struct sb_header_t)
+ sizeof(struct sb_section_header_t) * sb_header->nr_sections + sizeof(struct sb_section_header_t) * sb_header->nr_sections
+ sizeof(struct sb_key_dictionary_entry_t) * i; + sizeof(struct sb_key_dictionary_entry_t) * i;
struct sb_key_dictionary_entry_t *dict_entry = struct sb_key_dictionary_entry_t *dict_entry =
(struct sb_key_dictionary_entry_t *)&buf[ofs]; (struct sb_key_dictionary_entry_t *)&buf[ofs];
/* cbc mac */ /* cbc mac */
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); print_hex(YELLOW, dict_entry->hdr_cbc_mac, 16, false);
/* check it */ /* check it */
byte computed_cbc_mac[16]; int idx = 0;
byte zero[16]; while(idx < g_nr_keys && memcmp(dict_entry->hdr_cbc_mac, cbcmacs[idx], 16) != 0)
memset(zero, 0, 16); idx++;
crypto_cbc(buf, NULL, sb_header->header_size + sb_header->nr_sections, if(idx != g_nr_keys)
&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, " Match\n");
printf(RED, " Ok\n"); /* decrypt */
byte decrypted_key[16];
byte iv[16];
memcpy(iv, buf, 16); /* uses the first 16-bytes of SHA-1 sig as IV */
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);
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 else
printf(RED, " Failed\n"); printf(RED, " Don't Match\n");
printf(GREEN, " Encrypted key : ");
print_hex(YELLOW, dict_entry->key, 16, true);
/* 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);
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(memcmp(real_key, decrypted_key, 16) == 0)
printf(RED, " Cross-Check Ok");
else
printf(RED, " Cross-Check Failed");
}
printf(OFF, "\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;
char *env = getenv("SB_REAL_KEY");
if(!parse_key(&env, &k) || *env)
bug("Invalid SB_REAL_KEY\n");
memcpy(real_key, k.u.key, 16);
}
printf(RED, " Summary:\n");
printf(GREEN, " Real key: ");
print_hex(YELLOW, real_key, 16, true);
printf(GREEN, " IV : ");
print_hex(YELLOW, buf, 16, true);
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);
} }
if(getenv("SB_REAL_KEY") != 0)
{
struct crypto_key_t k;
char *env = getenv("SB_REAL_KEY");
if(!parse_key(&env, &k) || *env)
bug("Invalid SB_REAL_KEY\n");
memcpy(real_key, k.u.key, 16);
}
printf(RED, " Summary:\n");
printf(GREEN, " Real key: ");
print_hex(YELLOW, real_key, 16, true);
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);
/* sections */ /* sections */
if(!raw_mode) 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); memcpy(sec, buf + pos, size);
struct sb_section_t *s = read_section(data_sec, sec_hdr->identifier, struct sb_section_t *s = read_section(data_sec, sec_hdr->identifier,
sec, size, " ", u, cprintf); sec, size, " ", u, cprintf, err);
if(s) if(s)
{ {
s->is_cleartext = !encrypted; 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)); memcpy(&sb_file->sections[i], s, sizeof(struct sb_section_t));
free(s); free(s);
} }
else
fatal(*err, "Error reading section\n");
free(sec); 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); memcpy(sec, buf + pos, size);
struct sb_section_t *s = read_section(data_sec, tag->identifier, struct sb_section_t *s = read_section(data_sec, tag->identifier,
sec, size, " ", u, cprintf); sec, size, " ", u, cprintf, err);
if(s) if(s)
{ {
s->is_cleartext = !encrypted; 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); s, 1);
free(s); free(s);
} }
else
fatal(*err, "Error reading section\n");
free(sec); free(sec);
/* last one ? */ /* last one ? */
@ -938,7 +995,7 @@ struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
} }
else 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; 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) if(memcmp(decrypted_block, computed_sha1, 20) == 0)
printf(RED, " Ok\n"); printf(RED, " Ok\n");
else else
{
printf(RED, " Failed\n"); printf(RED, " Failed\n");
fatal(SB_CHECKSUM_ERROR, "File SHA-1 error\n");
}
free(buf); free(buf);
return sb_file; 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 #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) void sb_dump(struct sb_file_t *file, void *u, sb_color_printf cprintf)
{ {
#define printf(c, ...) cprintf(u, false, c, __VA_ARGS__) #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); sb_fill_section_name(name, file->first_boot_sec_id);
printf(TEXT, "%08x (%s)\n", file->first_boot_sec_id, name); printf(TEXT, "%08x (%s)\n", file->first_boot_sec_id, name);
if(file->real_key) if(file->override_real_key)
{ {
printf(TREE, "+-"); printf(TREE, "+-");
printf(HEADER, "Real key: "); 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(TREE, "+-");
printf(HEADER, "IV : "); printf(HEADER, "IV : ");
print_hex(TEXT, *file->crypto_iv, 16, true); print_hex(TEXT, file->crypto_iv, 16, true);
} }
printf(TREE, "+-"); printf(TREE, "+-");
printf(HEADER, "Product Version: "); printf(HEADER, "Product Version: ");

View file

@ -191,9 +191,11 @@ struct sb_section_t
struct sb_file_t struct sb_file_t
{ {
/* override real, otherwise it is randomly generated */ /* 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 */ /* 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; int nr_sections;
uint16_t drive_tag; uint16_t drive_tag;
@ -207,13 +209,29 @@ struct sb_file_t
uint32_t image_size; /* in blocks */ 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, ...); 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, 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_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_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__ */ #endif /* __SB_H__ */

View file

@ -268,7 +268,15 @@ int main(int argc, char **argv)
const char *sb_filename = argv[optind]; 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); color(OFF);
if(g_out_prefix) if(g_out_prefix)
extract_sb_file(file); 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 /* 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 * them when looping back otherwise the output will be inconsistent and
* garbage */ * garbage */
free(file->real_key); file->override_real_key = false;
file->real_key = NULL; file->override_crypto_iv = false;
free(file->crypto_iv);
file->crypto_iv = NULL;
sb_write_file(file, loopback); sb_write_file(file, loopback);
} }
sb_free(file);
clear_keys();
return 0; return 0;
} }