mirror of https://github.com/ipxe/ipxe.git
[prefix] Use CRC32 to verify each block prior to decompression
Signed-off-by: Michael Brown <mcb30@ipxe.org>pull/52/head
parent
05027a7a12
commit
c4e8c40227
|
@ -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
|
||||||
*
|
*
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue