Bladeren bron

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

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 8 jaren geleden
bovenliggende
commit
c4e8c40227
3 gewijzigde bestanden met toevoegingen van 160 en 45 verwijderingen
  1. 65
    34
      src/arch/x86/prefix/libprefix.S
  2. 53
    1
      src/arch/x86/prefix/unlzma.S
  3. 42
    10
      src/util/zbin.c

+ 65
- 34
src/arch/x86/prefix/libprefix.S Bestand weergeven

@@ -341,6 +341,7 @@ zero_bytes:
341 341
  * Returns:
342 342
  *   %esi : next source physical address
343 343
  *   %edi : next destination physical address
344
+ *   CF : as returned by memcpy()-like function
344 345
  * Corrupts:
345 346
  *   None
346 347
  ****************************************************************************
@@ -356,6 +357,7 @@ process_bytes:
356 357
 	pushl	%ebp
357 358
 
358 359
 	/* Construct GDT on stack (since .prefix may not be writable) */
360
+	.equ	GDT_LEN, 0x20
359 361
 	.equ	PM_DS, 0x18	/* Flat data segment */
360 362
 	pushl	$0x00cf9300
361 363
 	pushl	$0x0000ffff
@@ -369,7 +371,7 @@ process_bytes:
369 371
 	pushw	$0xffff
370 372
 	pushl	$0		/* Base and length */
371 373
 	pushw	%ss
372
-	pushw	$0x1f
374
+	pushw	$( GDT_LEN - 1 )
373 375
 	movzwl	%sp, %ebp
374 376
 	shll	$4, 0x02(%bp)
375 377
 	addl	%ebp, 0x02(%bp)
@@ -407,7 +409,9 @@ process_bytes:
407 409
 
408 410
 	/* Return to (flat) real mode */
409 411
 	movl	%cr0, %eax
412
+	pushfw
410 413
 	andb	$0!CR0_PE, %al
414
+	popfw
411 415
 	movl	%eax, %cr0
412 416
 	lret
413 417
 2:	/* lret will ljmp to here */
@@ -433,7 +437,7 @@ process_bytes:
433 437
 
434 438
 	/* Restore GDT */
435 439
 	data32 lgdt -8(%bp)
436
-	addw	$( 8 /* saved GDT */ + ( PM_DS + 8 ) /* GDT on stack */ ), %sp
440
+	leaw	GDT_LEN(%bp), %sp
437 441
 
438 442
 	/* Restore registers and return */
439 443
 	popl	%ebp
@@ -461,6 +465,7 @@ process_bytes:
461 465
 	call	*%bx
462 466
 
463 467
 	/* Convert %ds:esi and %es:edi back to physical addresses */
468
+	pushfw
464 469
 	xorl	%eax, %eax
465 470
 	movw    %ds, %ax
466 471
 	shll	$4, %eax
@@ -469,6 +474,7 @@ process_bytes:
469 474
 	movw    %es, %ax
470 475
 	shll	$4, %eax
471 476
 	addl	%eax, %edi
477
+	popfw
472 478
 
473 479
 	/* Restore registers and return */
474 480
 	popw	%es
@@ -493,6 +499,7 @@ process_bytes:
493 499
  * Returns:
494 500
  *   %esi : next source physical address (will be a multiple of 16)
495 501
  *   %edi : next destination physical address (will be a multiple of 16)
502
+ *   CF set on failure
496 503
  * Corrupts:
497 504
  *   none
498 505
  ****************************************************************************
@@ -511,6 +518,7 @@ install_block:
511 518
 	movw	$copy_bytes, %bx
512 519
 #endif
513 520
 	call	process_bytes
521
+	jc	99f
514 522
 
515 523
 	/* Zero .bss portion */
516 524
 	negl	%ecx
@@ -522,9 +530,9 @@ install_block:
522 530
 	addl	$0xf, %esi
523 531
 	andl	$~0xf, %esi
524 532
 	addl	$0xf, %edi
525
-	andl	$~0xf, %edi
533
+	andl	$~0xf, %edi /* Will also clear CF */
526 534
 
527
-	/* Restore registers and return */
535
+99:	/* Restore registers and return */
528 536
 	popw	%bx
529 537
 	popl	%ecx
530 538
 	ret
@@ -730,6 +738,7 @@ install_prealloc:
730 738
 	movl	$_text16_early_filesz, %ecx
731 739
 	movl	$_text16_early_memsz, %edx
732 740
 	call	install_block		/* .text16.early */
741
+	jc	install_block_death
733 742
 	popl	%ecx			/* Calculate offset to next block */
734 743
 	subl	%esi, %ecx
735 744
 	negl	%ecx
@@ -748,17 +757,8 @@ install_prealloc:
748 757
 	pushw	$access_highmem
749 758
 	lret
750 759
 1:	/* Die if we could not access high memory */
751
-	jnc	3f
752
-	movw	$a20_death_message, %si
753
-	xorw	%di, %di
754
-	call	print_message
755
-2:	jmp	2b
756
-	.section ".prefix.data.a20_death_message", "aw", @progbits
757
-a20_death_message:
758
-	.asciz	"\nHigh memory inaccessible - cannot continue\n"
759
-	.size	a20_death_message, . - a20_death_message
760
-	.previous
761
-3:
760
+	jc	access_highmem_death
761
+
762 762
 #endif
763 763
 
764 764
 	/* Open payload (which may not yet be in memory) */
@@ -769,25 +769,7 @@ a20_death_message:
769 769
 	pushw	$open_payload
770 770
 	lret
771 771
 1:	/* Die if we could not access the payload */
772
-	jnc	3f
773
-	xorw	%di, %di
774
-	movl	%esi, %eax
775
-	call	print_hex_dword
776
-	call	print_space
777
-	movl	%ecx, %eax
778
-	call	print_hex_dword
779
-	movw	$payload_death_message, %si
780
-	call	print_message
781
-2:	/* Halt system */
782
-	cli
783
-	hlt
784
-	jmp	2b
785
-	.section ".prefix.data.payload_death_message", "aw", @progbits
786
-payload_death_message:
787
-	.asciz	"\nPayload inaccessible - cannot continue\n"
788
-	.size	payload_death_message, . - payload_death_message
789
-	.previous
790
-3:
772
+	jc	open_payload_death
791 773
 
792 774
 	/* Calculate physical address of payload (i.e. first source) */
793 775
 	testl	%esi, %esi
@@ -801,12 +783,14 @@ payload_death_message:
801 783
 	movl	$_text16_late_filesz, %ecx
802 784
 	movl	$_text16_late_memsz, %edx
803 785
 	call	install_block		/* .text16.late */
786
+	jc	install_block_death
804 787
 	progress "  .data16\n"
805 788
 	movzwl	%bx, %edi
806 789
 	shll	$4, %edi
807 790
 	movl	$_data16_filesz, %ecx
808 791
 	movl	$_data16_filesz, %edx	/* do not zero our temporary stack */
809 792
 	call	install_block		/* .data16 */
793
+	jc	install_block_death
810 794
 
811 795
 	/* Set up %ds for access to .data16 */
812 796
 	movw	%bx, %ds
@@ -846,6 +830,7 @@ payload_death_message:
846 830
 	movl	$_textdata_filesz, %ecx
847 831
 	movl	$_textdata_memsz, %edx
848 832
 	call	install_block
833
+	jc	install_block_death
849 834
 	popl	%edi
850 835
 
851 836
 #endif /* KEEP_IT_REAL */
@@ -960,6 +945,52 @@ close_payload:
960 945
 	.size	open_payload, . - open_payload
961 946
 	.size	close_payload, . - close_payload
962 947
 
948
+	/* Report installation failure */
949
+	.section ".prefix.install_death", "ax", @progbits
950
+install_death:
951
+	pushw	%cs
952
+	popw	%ds
953
+	xorw	%di, %di
954
+	call	print_hex_dword
955
+	call	print_space
956
+	movl	%esi, %eax
957
+	call	print_hex_dword
958
+	call	print_space
959
+	movl	%ecx, %eax
960
+	call	print_hex_dword
961
+	movw	$install_death_message, %si
962
+	call	print_message
963
+2:	/* Halt system */
964
+	cli
965
+	hlt
966
+	jmp	2b
967
+	.size	install_death, . - install_death
968
+	.section ".prefix.data.install_death_message", "aw", @progbits
969
+install_death_message:
970
+	.asciz	"\nInstallation failed - cannot continue\n"
971
+	.size	install_death_message, . - install_death_message
972
+
973
+	/* Report failure to access high memory */
974
+	.section ".prefix.install_block_death", "ax", @progbits
975
+install_block_death:
976
+	movl	$0x1b101b10, %eax
977
+	jmp	install_death
978
+	.size	install_block_death, . - install_block_death
979
+
980
+	/* Report failure to access high memory */
981
+	.section ".prefix.access_highmem_death", "ax", @progbits
982
+access_highmem_death:
983
+	movl	$0x0a200a20, %eax
984
+	jmp	install_death
985
+	.size	access_highmem_death, . - access_highmem_death
986
+
987
+	/* Report failure to open payload */
988
+	.section ".prefix.open_payload_death", "ax", @progbits
989
+open_payload_death:
990
+	xorl	%eax, %eax
991
+	jmp	install_death
992
+	.size	open_payload_death, . - open_payload_death
993
+
963 994
 /****************************************************************************
964 995
  * uninstall
965 996
  *

+ 53
- 1
src/arch/x86/prefix/unlzma.S Bestand weergeven

@@ -58,6 +58,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
58 58
 	.code32
59 59
 #endif /* CODE16 */
60 60
 
61
+#define CRCPOLY 0xedb88320
62
+#define CRCSEED 0xffffffff
63
+
61 64
 /****************************************************************************
62 65
  * Debugging
63 66
  ****************************************************************************
@@ -862,6 +865,44 @@ bcj_filter:
862 865
 	ret
863 866
 	.size	bcj_filter, . - bcj_filter
864 867
 
868
+/****************************************************************************
869
+ * Verify CRC32
870
+ *
871
+ * Parameters:
872
+ *   %ds:%esi : Start of compressed input data
873
+ *   %edx : Length of compressed input data (including CRC)
874
+ * Returns:
875
+ *   CF clear if CRC32 is zero
876
+ *   All other registers are preserved
877
+ * Corrupts:
878
+ *   %eax
879
+ *   %ebx
880
+ *   %ecx
881
+ *   %edx
882
+ *   %esi
883
+ ****************************************************************************
884
+ */
885
+verify_crc32:
886
+	/* Calculate CRC */
887
+	addl	%esi, %edx
888
+	movl	$CRCSEED, %ebx
889
+1:	ADDR32 lodsb
890
+	xorb	%al, %bl
891
+	movw	$8, %cx
892
+2:	rcrl	%ebx
893
+	jnc	3f
894
+	xorl	$CRCPOLY, %ebx
895
+3:	ADDR16 loop 2b
896
+	cmpl	%esi, %edx
897
+	jne	1b
898
+	/* Set CF if result is nonzero */
899
+	testl	%ebx, %ebx
900
+	jz	1f
901
+	stc
902
+1:	/* Return */
903
+	ret
904
+	.size	verify_crc32, . - verify_crc32
905
+
865 906
 /****************************************************************************
866 907
  * decompress (real-mode or 16/32-bit protected-mode near call)
867 908
  *
@@ -873,6 +914,7 @@ bcj_filter:
873 914
  * Returns:
874 915
  *   %ds:%esi - End of compressed input data
875 916
  *   %es:%edi - End of decompressed output data
917
+ *   CF set if CRC32 was incorrect
876 918
  *   All other registers are preserved
877 919
  *
878 920
  * NOTE: It would be possible to build a smaller version of the
@@ -888,6 +930,13 @@ decompress:
888 930
 	pushl	%ecx
889 931
 	pushl	%edx
890 932
 	pushl	%ebp
933
+	/* Verify CRC32 */
934
+	ADDR32 lodsl
935
+	movl	%eax, %edx
936
+	pushl	%esi
937
+	call	verify_crc32
938
+	popl	%esi
939
+	jc	99f
891 940
 	/* Allocate parameter block */
892 941
 	subl	$sizeof__lzma_dec, %esp
893 942
 	movl	%esp, %ebp
@@ -928,8 +977,11 @@ decompress:
928 977
 	movl	out_start(%ebp), %esi
929 978
 	call	bcj_filter
930 979
 	popl	%esi
931
-	/* Restore registers and return */
980
+	/* Skip CRC */
981
+	ADDR32 lodsl
982
+	/* Free parameter block (and clear CF) */
932 983
 	addl	$sizeof__lzma_dec, %esp
984
+99:	/* Restore registers and return */
933 985
 	popl	%ebp
934 986
 	popl	%edx
935 987
 	popl	%ecx

+ 42
- 10
src/util/zbin.c Bestand weergeven

@@ -144,6 +144,7 @@ static int read_zinfo_file ( const char *filename,
144 144
 
145 145
 static int alloc_output_file ( size_t max_len, struct output_file *output ) {
146 146
 	output->len = 0;
147
+	output->hdr_len = 0;
147 148
 	output->max_len = ( max_len );
148 149
 	output->buf = malloc ( max_len );
149 150
 	if ( ! output->buf ) {
@@ -241,19 +242,41 @@ static void bcj_filter ( void *data, size_t len ) {
241 242
 	};
242 243
 }
243 244
 
245
+#define CRCPOLY 0xedb88320
246
+#define CRCSEED 0xffffffff
247
+
248
+static uint32_t crc32_le ( uint32_t crc, const void *data, size_t len ) {
249
+	const uint8_t *src = data;
250
+	uint32_t mult;
251
+	unsigned int i;
252
+
253
+	while ( len-- ) {
254
+		crc ^= *(src++);
255
+		for ( i = 0 ; i < 8 ; i++ ) {
256
+			mult = ( ( crc & 1 ) ? CRCPOLY : 0 );
257
+			crc = ( ( crc >> 1 ) ^ mult );
258
+		}
259
+	}
260
+	return crc;
261
+}
262
+
244 263
 static int process_zinfo_pack ( struct input_file *input,
245 264
 				struct output_file *output,
246 265
 				union zinfo_record *zinfo ) {
247 266
 	struct zinfo_pack *pack = &zinfo->pack;
248 267
 	size_t offset = pack->offset;
249 268
 	size_t len = pack->len;
269
+	size_t start_len;
250 270
 	size_t packed_len = 0;
251
-	size_t remaining = ( output->max_len - output->len );
271
+	size_t remaining;
252 272
 	lzma_options_lzma options;
253 273
 	const lzma_filter filters[] = {
254 274
 		{ .id = LZMA_FILTER_LZMA1, .options = &options },
255 275
 		{ .id = LZMA_VLI_UNKNOWN }
256 276
 	};
277
+	void *packed;
278
+	uint32_t *len32;
279
+	uint32_t *crc32;
257 280
 
258 281
 	if ( ( offset + len ) > input->len ) {
259 282
 		fprintf ( stderr, "Input buffer overrun on pack\n" );
@@ -261,6 +284,9 @@ static int process_zinfo_pack ( struct input_file *input,
261 284
 	}
262 285
 
263 286
 	output->len = align ( output->len, pack->align );
287
+	start_len = output->len;
288
+	len32 = ( output->buf + output->len );
289
+	output->len += sizeof ( *len32 );
264 290
 	if ( output->len > output->max_len ) {
265 291
 		fprintf ( stderr, "Output buffer overrun on pack\n" );
266 292
 		return -1;
@@ -268,28 +294,34 @@ static int process_zinfo_pack ( struct input_file *input,
268 294
 
269 295
 	bcj_filter ( ( input->buf + offset ), len );
270 296
 
297
+	packed = ( output->buf + output->len );
298
+	remaining = ( output->max_len - output->len );
271 299
 	lzma_lzma_preset ( &options, LZMA_PRESET );
272 300
 	options.lc = LZMA_LC;
273 301
 	options.lp = LZMA_LP;
274 302
 	options.pb = LZMA_PB;
275 303
 	if ( lzma_raw_buffer_encode ( filters, NULL, ( input->buf + offset ),
276
-				      len, ( output->buf + output->len ),
277
-				      &packed_len, remaining ) != LZMA_OK ) {
304
+				      len, packed, &packed_len,
305
+				      remaining ) != LZMA_OK ) {
278 306
 		fprintf ( stderr, "Compression failure\n" );
279 307
 		return -1;
280 308
 	}
281
-
282
-	if ( DEBUG ) {
283
-		fprintf ( stderr, "PACK [%#zx,%#zx) to [%#zx,%#zx)\n",
284
-			  offset, ( offset + len ), output->len,
285
-			  ( output->len + packed_len ) );
286
-	}
287
-
288 309
 	output->len += packed_len;
310
+
311
+	crc32 = ( output->buf + output->len );
312
+	output->len += sizeof ( *crc32 );
289 313
 	if ( output->len > output->max_len ) {
290 314
 		fprintf ( stderr, "Output buffer overrun on pack\n" );
291 315
 		return -1;
292 316
 	}
317
+	*len32 = ( packed_len + sizeof ( *crc32 ) );
318
+	*crc32 = crc32_le ( CRCSEED, packed, packed_len );
319
+
320
+	if ( DEBUG ) {
321
+		fprintf ( stderr, "PACK [%#zx,%#zx) to [%#zx,%#zx) crc %#08x\n",
322
+			  offset, ( offset + len ), start_len, output->len,
323
+			  *crc32 );
324
+	}
293 325
 
294 326
 	return 0;
295 327
 }

Laden…
Annuleren
Opslaan