[prefix] Use CRC32 to verify each block prior to decompression

Signed-off-by: Michael Brown <mcb30@ipxe.org>
pull/52/head
Michael Brown 2016-03-23 13:41:17 +00:00
parent 05027a7a12
commit c4e8c40227
3 changed files with 160 additions and 45 deletions

View File

@ -341,6 +341,7 @@ zero_bytes:
* Returns: * Returns:
* %esi : next source physical address * %esi : next source physical address
* %edi : next destination physical address * %edi : next destination physical address
* CF : as returned by memcpy()-like function
* Corrupts: * Corrupts:
* None * None
**************************************************************************** ****************************************************************************
@ -356,6 +357,7 @@ process_bytes:
pushl %ebp pushl %ebp
/* Construct GDT on stack (since .prefix may not be writable) */ /* Construct GDT on stack (since .prefix may not be writable) */
.equ GDT_LEN, 0x20
.equ PM_DS, 0x18 /* Flat data segment */ .equ PM_DS, 0x18 /* Flat data segment */
pushl $0x00cf9300 pushl $0x00cf9300
pushl $0x0000ffff pushl $0x0000ffff
@ -369,7 +371,7 @@ process_bytes:
pushw $0xffff pushw $0xffff
pushl $0 /* Base and length */ pushl $0 /* Base and length */
pushw %ss pushw %ss
pushw $0x1f pushw $( GDT_LEN - 1 )
movzwl %sp, %ebp movzwl %sp, %ebp
shll $4, 0x02(%bp) shll $4, 0x02(%bp)
addl %ebp, 0x02(%bp) addl %ebp, 0x02(%bp)
@ -407,7 +409,9 @@ process_bytes:
/* Return to (flat) real mode */ /* Return to (flat) real mode */
movl %cr0, %eax movl %cr0, %eax
pushfw
andb $0!CR0_PE, %al andb $0!CR0_PE, %al
popfw
movl %eax, %cr0 movl %eax, %cr0
lret lret
2: /* lret will ljmp to here */ 2: /* lret will ljmp to here */
@ -433,7 +437,7 @@ process_bytes:
/* Restore GDT */ /* Restore GDT */
data32 lgdt -8(%bp) data32 lgdt -8(%bp)
addw $( 8 /* saved GDT */ + ( PM_DS + 8 ) /* GDT on stack */ ), %sp leaw GDT_LEN(%bp), %sp
/* Restore registers and return */ /* Restore registers and return */
popl %ebp popl %ebp
@ -461,6 +465,7 @@ process_bytes:
call *%bx call *%bx
/* Convert %ds:esi and %es:edi back to physical addresses */ /* Convert %ds:esi and %es:edi back to physical addresses */
pushfw
xorl %eax, %eax xorl %eax, %eax
movw %ds, %ax movw %ds, %ax
shll $4, %eax shll $4, %eax
@ -469,6 +474,7 @@ process_bytes:
movw %es, %ax movw %es, %ax
shll $4, %eax shll $4, %eax
addl %eax, %edi addl %eax, %edi
popfw
/* Restore registers and return */ /* Restore registers and return */
popw %es popw %es
@ -493,6 +499,7 @@ process_bytes:
* Returns: * Returns:
* %esi : next source physical address (will be a multiple of 16) * %esi : next source physical address (will be a multiple of 16)
* %edi : next destination physical address (will be a multiple of 16) * %edi : next destination physical address (will be a multiple of 16)
* CF set on failure
* Corrupts: * Corrupts:
* none * none
**************************************************************************** ****************************************************************************
@ -511,6 +518,7 @@ install_block:
movw $copy_bytes, %bx movw $copy_bytes, %bx
#endif #endif
call process_bytes call process_bytes
jc 99f
/* Zero .bss portion */ /* Zero .bss portion */
negl %ecx negl %ecx
@ -522,9 +530,9 @@ install_block:
addl $0xf, %esi addl $0xf, %esi
andl $~0xf, %esi andl $~0xf, %esi
addl $0xf, %edi addl $0xf, %edi
andl $~0xf, %edi andl $~0xf, %edi /* Will also clear CF */
/* Restore registers and return */ 99: /* Restore registers and return */
popw %bx popw %bx
popl %ecx popl %ecx
ret ret
@ -730,6 +738,7 @@ install_prealloc:
movl $_text16_early_filesz, %ecx movl $_text16_early_filesz, %ecx
movl $_text16_early_memsz, %edx movl $_text16_early_memsz, %edx
call install_block /* .text16.early */ call install_block /* .text16.early */
jc install_block_death
popl %ecx /* Calculate offset to next block */ popl %ecx /* Calculate offset to next block */
subl %esi, %ecx subl %esi, %ecx
negl %ecx negl %ecx
@ -748,17 +757,8 @@ install_prealloc:
pushw $access_highmem pushw $access_highmem
lret lret
1: /* Die if we could not access high memory */ 1: /* Die if we could not access high memory */
jnc 3f jc access_highmem_death
movw $a20_death_message, %si
xorw %di, %di
call print_message
2: jmp 2b
.section ".prefix.data.a20_death_message", "aw", @progbits
a20_death_message:
.asciz "\nHigh memory inaccessible - cannot continue\n"
.size a20_death_message, . - a20_death_message
.previous
3:
#endif #endif
/* Open payload (which may not yet be in memory) */ /* Open payload (which may not yet be in memory) */
@ -769,25 +769,7 @@ a20_death_message:
pushw $open_payload pushw $open_payload
lret lret
1: /* Die if we could not access the payload */ 1: /* Die if we could not access the payload */
jnc 3f jc open_payload_death
xorw %di, %di
movl %esi, %eax
call print_hex_dword
call print_space
movl %ecx, %eax
call print_hex_dword
movw $payload_death_message, %si
call print_message
2: /* Halt system */
cli
hlt
jmp 2b
.section ".prefix.data.payload_death_message", "aw", @progbits
payload_death_message:
.asciz "\nPayload inaccessible - cannot continue\n"
.size payload_death_message, . - payload_death_message
.previous
3:
/* Calculate physical address of payload (i.e. first source) */ /* Calculate physical address of payload (i.e. first source) */
testl %esi, %esi testl %esi, %esi
@ -801,12 +783,14 @@ payload_death_message:
movl $_text16_late_filesz, %ecx movl $_text16_late_filesz, %ecx
movl $_text16_late_memsz, %edx movl $_text16_late_memsz, %edx
call install_block /* .text16.late */ call install_block /* .text16.late */
jc install_block_death
progress " .data16\n" progress " .data16\n"
movzwl %bx, %edi movzwl %bx, %edi
shll $4, %edi shll $4, %edi
movl $_data16_filesz, %ecx movl $_data16_filesz, %ecx
movl $_data16_filesz, %edx /* do not zero our temporary stack */ movl $_data16_filesz, %edx /* do not zero our temporary stack */
call install_block /* .data16 */ call install_block /* .data16 */
jc install_block_death
/* Set up %ds for access to .data16 */ /* Set up %ds for access to .data16 */
movw %bx, %ds movw %bx, %ds
@ -846,6 +830,7 @@ payload_death_message:
movl $_textdata_filesz, %ecx movl $_textdata_filesz, %ecx
movl $_textdata_memsz, %edx movl $_textdata_memsz, %edx
call install_block call install_block
jc install_block_death
popl %edi popl %edi
#endif /* KEEP_IT_REAL */ #endif /* KEEP_IT_REAL */
@ -960,6 +945,52 @@ close_payload:
.size open_payload, . - open_payload .size open_payload, . - open_payload
.size close_payload, . - close_payload .size close_payload, . - close_payload
/* Report installation failure */
.section ".prefix.install_death", "ax", @progbits
install_death:
pushw %cs
popw %ds
xorw %di, %di
call print_hex_dword
call print_space
movl %esi, %eax
call print_hex_dword
call print_space
movl %ecx, %eax
call print_hex_dword
movw $install_death_message, %si
call print_message
2: /* Halt system */
cli
hlt
jmp 2b
.size install_death, . - install_death
.section ".prefix.data.install_death_message", "aw", @progbits
install_death_message:
.asciz "\nInstallation failed - cannot continue\n"
.size install_death_message, . - install_death_message
/* Report failure to access high memory */
.section ".prefix.install_block_death", "ax", @progbits
install_block_death:
movl $0x1b101b10, %eax
jmp install_death
.size install_block_death, . - install_block_death
/* Report failure to access high memory */
.section ".prefix.access_highmem_death", "ax", @progbits
access_highmem_death:
movl $0x0a200a20, %eax
jmp install_death
.size access_highmem_death, . - access_highmem_death
/* Report failure to open payload */
.section ".prefix.open_payload_death", "ax", @progbits
open_payload_death:
xorl %eax, %eax
jmp install_death
.size open_payload_death, . - open_payload_death
/**************************************************************************** /****************************************************************************
* uninstall * uninstall
* *

View File

@ -58,6 +58,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
.code32 .code32
#endif /* CODE16 */ #endif /* CODE16 */
#define CRCPOLY 0xedb88320
#define CRCSEED 0xffffffff
/**************************************************************************** /****************************************************************************
* Debugging * Debugging
**************************************************************************** ****************************************************************************
@ -862,6 +865,44 @@ bcj_filter:
ret ret
.size bcj_filter, . - bcj_filter .size bcj_filter, . - bcj_filter
/****************************************************************************
* Verify CRC32
*
* Parameters:
* %ds:%esi : Start of compressed input data
* %edx : Length of compressed input data (including CRC)
* Returns:
* CF clear if CRC32 is zero
* All other registers are preserved
* Corrupts:
* %eax
* %ebx
* %ecx
* %edx
* %esi
****************************************************************************
*/
verify_crc32:
/* Calculate CRC */
addl %esi, %edx
movl $CRCSEED, %ebx
1: ADDR32 lodsb
xorb %al, %bl
movw $8, %cx
2: rcrl %ebx
jnc 3f
xorl $CRCPOLY, %ebx
3: ADDR16 loop 2b
cmpl %esi, %edx
jne 1b
/* Set CF if result is nonzero */
testl %ebx, %ebx
jz 1f
stc
1: /* Return */
ret
.size verify_crc32, . - verify_crc32
/**************************************************************************** /****************************************************************************
* decompress (real-mode or 16/32-bit protected-mode near call) * decompress (real-mode or 16/32-bit protected-mode near call)
* *
@ -873,6 +914,7 @@ bcj_filter:
* Returns: * Returns:
* %ds:%esi - End of compressed input data * %ds:%esi - End of compressed input data
* %es:%edi - End of decompressed output data * %es:%edi - End of decompressed output data
* CF set if CRC32 was incorrect
* All other registers are preserved * All other registers are preserved
* *
* NOTE: It would be possible to build a smaller version of the * NOTE: It would be possible to build a smaller version of the
@ -888,6 +930,13 @@ decompress:
pushl %ecx pushl %ecx
pushl %edx pushl %edx
pushl %ebp pushl %ebp
/* Verify CRC32 */
ADDR32 lodsl
movl %eax, %edx
pushl %esi
call verify_crc32
popl %esi
jc 99f
/* Allocate parameter block */ /* Allocate parameter block */
subl $sizeof__lzma_dec, %esp subl $sizeof__lzma_dec, %esp
movl %esp, %ebp movl %esp, %ebp
@ -928,8 +977,11 @@ decompress:
movl out_start(%ebp), %esi movl out_start(%ebp), %esi
call bcj_filter call bcj_filter
popl %esi popl %esi
/* Restore registers and return */ /* Skip CRC */
ADDR32 lodsl
/* Free parameter block (and clear CF) */
addl $sizeof__lzma_dec, %esp addl $sizeof__lzma_dec, %esp
99: /* Restore registers and return */
popl %ebp popl %ebp
popl %edx popl %edx
popl %ecx popl %ecx

View File

@ -144,6 +144,7 @@ static int read_zinfo_file ( const char *filename,
static int alloc_output_file ( size_t max_len, struct output_file *output ) { static int alloc_output_file ( size_t max_len, struct output_file *output ) {
output->len = 0; output->len = 0;
output->hdr_len = 0;
output->max_len = ( max_len ); output->max_len = ( max_len );
output->buf = malloc ( max_len ); output->buf = malloc ( max_len );
if ( ! output->buf ) { if ( ! output->buf ) {
@ -241,19 +242,41 @@ static void bcj_filter ( void *data, size_t len ) {
}; };
} }
#define CRCPOLY 0xedb88320
#define CRCSEED 0xffffffff
static uint32_t crc32_le ( uint32_t crc, const void *data, size_t len ) {
const uint8_t *src = data;
uint32_t mult;
unsigned int i;
while ( len-- ) {
crc ^= *(src++);
for ( i = 0 ; i < 8 ; i++ ) {
mult = ( ( crc & 1 ) ? CRCPOLY : 0 );
crc = ( ( crc >> 1 ) ^ mult );
}
}
return crc;
}
static int process_zinfo_pack ( struct input_file *input, static int process_zinfo_pack ( struct input_file *input,
struct output_file *output, struct output_file *output,
union zinfo_record *zinfo ) { union zinfo_record *zinfo ) {
struct zinfo_pack *pack = &zinfo->pack; struct zinfo_pack *pack = &zinfo->pack;
size_t offset = pack->offset; size_t offset = pack->offset;
size_t len = pack->len; size_t len = pack->len;
size_t start_len;
size_t packed_len = 0; size_t packed_len = 0;
size_t remaining = ( output->max_len - output->len ); size_t remaining;
lzma_options_lzma options; lzma_options_lzma options;
const lzma_filter filters[] = { const lzma_filter filters[] = {
{ .id = LZMA_FILTER_LZMA1, .options = &options }, { .id = LZMA_FILTER_LZMA1, .options = &options },
{ .id = LZMA_VLI_UNKNOWN } { .id = LZMA_VLI_UNKNOWN }
}; };
void *packed;
uint32_t *len32;
uint32_t *crc32;
if ( ( offset + len ) > input->len ) { if ( ( offset + len ) > input->len ) {
fprintf ( stderr, "Input buffer overrun on pack\n" ); fprintf ( stderr, "Input buffer overrun on pack\n" );
@ -261,6 +284,9 @@ static int process_zinfo_pack ( struct input_file *input,
} }
output->len = align ( output->len, pack->align ); output->len = align ( output->len, pack->align );
start_len = output->len;
len32 = ( output->buf + output->len );
output->len += sizeof ( *len32 );
if ( output->len > output->max_len ) { if ( output->len > output->max_len ) {
fprintf ( stderr, "Output buffer overrun on pack\n" ); fprintf ( stderr, "Output buffer overrun on pack\n" );
return -1; return -1;
@ -268,28 +294,34 @@ static int process_zinfo_pack ( struct input_file *input,
bcj_filter ( ( input->buf + offset ), len ); bcj_filter ( ( input->buf + offset ), len );
packed = ( output->buf + output->len );
remaining = ( output->max_len - output->len );
lzma_lzma_preset ( &options, LZMA_PRESET ); lzma_lzma_preset ( &options, LZMA_PRESET );
options.lc = LZMA_LC; options.lc = LZMA_LC;
options.lp = LZMA_LP; options.lp = LZMA_LP;
options.pb = LZMA_PB; options.pb = LZMA_PB;
if ( lzma_raw_buffer_encode ( filters, NULL, ( input->buf + offset ), if ( lzma_raw_buffer_encode ( filters, NULL, ( input->buf + offset ),
len, ( output->buf + output->len ), len, packed, &packed_len,
&packed_len, remaining ) != LZMA_OK ) { remaining ) != LZMA_OK ) {
fprintf ( stderr, "Compression failure\n" ); fprintf ( stderr, "Compression failure\n" );
return -1; return -1;
} }
if ( DEBUG ) {
fprintf ( stderr, "PACK [%#zx,%#zx) to [%#zx,%#zx)\n",
offset, ( offset + len ), output->len,
( output->len + packed_len ) );
}
output->len += packed_len; output->len += packed_len;
crc32 = ( output->buf + output->len );
output->len += sizeof ( *crc32 );
if ( output->len > output->max_len ) { if ( output->len > output->max_len ) {
fprintf ( stderr, "Output buffer overrun on pack\n" ); fprintf ( stderr, "Output buffer overrun on pack\n" );
return -1; return -1;
} }
*len32 = ( packed_len + sizeof ( *crc32 ) );
*crc32 = crc32_le ( CRCSEED, packed, packed_len );
if ( DEBUG ) {
fprintf ( stderr, "PACK [%#zx,%#zx) to [%#zx,%#zx) crc %#08x\n",
offset, ( offset + len ), start_len, output->len,
*crc32 );
}
return 0; return 0;
} }