diff options
author | Stefan Hajnoczi <stefanha@gmail.com> | 2009-04-11 11:13:09 +0100 |
---|---|---|
committer | Michael Brown <mcb30@etherboot.org> | 2009-04-15 16:14:47 +0100 |
commit | b149a99302d54728cf1d505b48ef9ebe99733391 (patch) | |
tree | 687c6974dbd6f85882ebe3339e32c2fda42db769 /src/util/zbin.c | |
parent | f44205b9ea928c3cdefb6848e7f20fe11d112522 (diff) | |
download | ipxe-b149a99302d54728cf1d505b48ef9ebe99733391.tar.gz |
[build] Round up SUBx deltas
The zbin compressor fixup utility rounds down file sizes before
calculating their difference. This produces incorrect values and may
cause truncated gPXE images to be loaded at boot.
The following example explains the problem:
ilen = 48 bytes (uncompressed input file)
olen = 17 bytes (compressed output file)
divisor = 16 bytes (paragraph granularity)
fixmeup = 3 paragraphs (value to fix up)
olen / divisor - ilen / divisor
= 1 - 3
= -2 paragraphs (old delta calculation)
( align ( olen, divisor ) - align ( ilen, divisor ) ) / divisor
= 2 - 3
= -1 paragraphs (new delta calculation)
If we perform the SUBx operation with old delta:
fixmeup + -2 = 1 paragraph gets loaded by the prefix
With the new delta:
fixmeup + -1 = 2 paragraphs get loaded by the prefix
The old delta calculation removes the last paragraph; the prefix will
load a truncated copy of gPXE into memory. We need to load 2
paragraphs since olen is 17 bytes. Loading only 1 paragraph (16
bytes) would truncate the last byte.
Signed-off-by: Michael Brown <mcb30@etherboot.org>
Diffstat (limited to 'src/util/zbin.c')
-rw-r--r-- | src/util/zbin.c | 17 |
1 files changed, 10 insertions, 7 deletions
diff --git a/src/util/zbin.c b/src/util/zbin.c index c1082b315..d4eebe579 100644 --- a/src/util/zbin.c +++ b/src/util/zbin.c @@ -57,6 +57,10 @@ struct zinfo_file { unsigned int num_entries; }; +static unsigned long align ( unsigned long value, unsigned long align ) { + return ( ( value + align - 1 ) & ~( align - 1 ) ); +} + static int read_file ( const char *filename, void **buf, size_t *len ) { FILE *file; struct stat stat; @@ -140,14 +144,13 @@ static int process_zinfo_copy ( struct input_file *input, struct zinfo_copy *copy = &zinfo->copy; size_t offset = copy->offset; size_t len = copy->len; - unsigned int align = copy->align; if ( ( offset + len ) > input->len ) { fprintf ( stderr, "Input buffer overrun on copy\n" ); return -1; } - output->len = ( ( output->len + align - 1 ) & ~( align - 1 ) ); + output->len = align ( output->len, copy->align ); if ( ( output->len + len ) > output->max_len ) { fprintf ( stderr, "Output buffer overrun on copy\n" ); return -1; @@ -170,7 +173,6 @@ static int process_zinfo_pack ( struct input_file *input, struct zinfo_pack *pack = &zinfo->pack; size_t offset = pack->offset; size_t len = pack->len; - unsigned int align = pack->align; unsigned long packed_len; if ( ( offset + len ) > input->len ) { @@ -178,7 +180,7 @@ static int process_zinfo_pack ( struct input_file *input, return -1; } - output->len = ( ( output->len + align - 1 ) & ~( align - 1 ) ); + output->len = align ( output->len, pack->align ); if ( output->len > output->max_len ) { fprintf ( stderr, "Output buffer overrun on pack\n" ); return -1; @@ -222,8 +224,9 @@ static int process_zinfo_subtract ( struct input_file *input, } target = ( output->buf + offset ); - delta = ( ( output->len / subtract->divisor ) - - ( input->len / subtract->divisor ) ); + delta = ( ( align ( output->len, subtract->divisor ) - + align ( input->len, subtract->divisor ) ) + / subtract->divisor ); switch ( datasize ) { case 1: { @@ -251,7 +254,7 @@ static int process_zinfo_subtract ( struct input_file *input, } if ( DEBUG ) { - fprintf ( stderr, "SUBx [%#zx,%#zx) (%#lx+(%#lx/%#lx)-(%#lx/%#lx)) = %#lx\n", + fprintf ( stderr, "SUBx [%#zx,%#zx) (%#lx+(%#lx/%#x)-(%#lx/%#x)) = %#lx\n", offset, ( offset + datasize ), old, output->len, subtract->divisor, input->len, subtract->divisor, new ); } |