@@ -149,6 +149,7 @@ static dict_cache cache;
149
149
#endif
150
150
#endif
151
151
152
+ static size_t lzma_output_limit = SIZE_MAX ;
152
153
static bool allocated_probs = false;
153
154
#ifdef CONFIG_NRF_COMPRESS_LZMA_VERSION_LZMA2
154
155
static CLzma2Dec lzma_decoder ;
@@ -220,14 +221,14 @@ static int check_inst(void *inst)
220
221
#define check_inst (...) 0
221
222
#endif
222
223
223
- static int lzma_reset (void * inst );
224
+ static int lzma_reset (void * inst , const size_t * decompressed_size );
224
225
225
- static int lzma_init (void * inst )
226
+ static int lzma_init (void * inst , const size_t * decompressed_size )
226
227
{
227
228
int rc = 0 ;
228
229
229
230
#if defined(CONFIG_NRF_COMPRESS_EXTERNAL_DICTIONARY )
230
- if (inst == NULL ) {
231
+ if (inst == NULL || ext_dict != NULL ) {
231
232
return - EINVAL ;
232
233
}
233
234
@@ -244,7 +245,7 @@ static int lzma_init(void *inst)
244
245
&& !defined(CONFIG_NRF_COMPRESS_EXTERNAL_DICTIONARY )
245
246
if (lzma_dict != NULL ) {
246
247
/* Already allocated */
247
- lzma_reset (inst );
248
+ lzma_reset (inst , decompressed_size );
248
249
249
250
return rc ;
250
251
}
@@ -260,6 +261,11 @@ static int lzma_init(void *inst)
260
261
rc = - ENOMEM ;
261
262
}
262
263
#endif
264
+ if (lzma_output_limit != SIZE_MAX ) {
265
+ lzma_reset (inst , decompressed_size );
266
+ } else {
267
+ lzma_output_limit = decompressed_size != NULL ? * decompressed_size : SIZE_MAX ;
268
+ }
263
269
264
270
return rc ;
265
271
}
@@ -283,8 +289,8 @@ static int lzma_deinit(void *inst)
283
289
lzma_dict = NULL ;
284
290
}
285
291
#endif
286
-
287
- rc = lzma_reset (inst );
292
+ size_t const decompress_size = SIZE_MAX ;
293
+ rc = lzma_reset (inst , & decompress_size );
288
294
289
295
#if defined(CONFIG_NRF_COMPRESS_EXTERNAL_DICTIONARY )
290
296
ext_dict = NULL ;
@@ -293,7 +299,7 @@ static int lzma_deinit(void *inst)
293
299
return rc ;
294
300
}
295
301
296
- static int lzma_reset (void * inst )
302
+ static int lzma_reset (void * inst , const size_t * decompressed_size )
297
303
{
298
304
int rc = check_inst (inst );
299
305
@@ -330,6 +336,8 @@ static int lzma_reset(void *inst)
330
336
#endif
331
337
}
332
338
339
+ lzma_output_limit = decompressed_size != NULL ? * decompressed_size : SIZE_MAX ;
340
+
333
341
return rc ;
334
342
}
335
343
@@ -362,6 +370,15 @@ static int lzma_decompress(void *inst, const uint8_t *input, size_t input_size,
362
370
int rc ;
363
371
ELzmaStatus status ;
364
372
size_t chunk_size = input_size ;
373
+ ELzmaFinishMode finish_mode = LZMA_FINISH_ANY ;
374
+ SizeT dic_limit = MAX_LZMA_DICT_SIZE ;
375
+
376
+ #ifdef CONFIG_NRF_COMPRESS_LZMA_VERSION_LZMA2 /* For convenience */
377
+ SizeT * dic_pos = & lzma_decoder .decoder .dicPos ;
378
+ #else
379
+ SizeT * dic_pos = & lzma_decoder .dicPos ;
380
+ #endif
381
+ SizeT curr_dic_pos = * dic_pos ;
365
382
366
383
ARG_UNUSED (inst );
367
384
@@ -388,22 +405,20 @@ static int lzma_decompress(void *inst, const uint8_t *input, size_t input_size,
388
405
#endif
389
406
390
407
if (rc ) {
391
- rc = - EINVAL ;
392
- goto done ;
408
+ return - EINVAL ;
393
409
}
394
410
395
411
#ifdef CONFIG_NRF_COMPRESS_LZMA_VERSION_LZMA2
396
412
if (lzma_decoder .decoder .prop .dicSize > MAX_LZMA_DICT_SIZE ) {
397
413
#else
398
414
if (lzma_decoder .prop .dicSize > MAX_LZMA_DICT_SIZE ) {
399
415
#endif
400
- rc = - EINVAL ;
401
416
#ifdef CONFIG_NRF_COMPRESS_LZMA_VERSION_LZMA2
402
417
Lzma2Dec_FreeProbs (& lzma_decoder , & lzma_probs_allocator );
403
418
#else
404
419
LzmaDec_FreeProbs (& lzma_decoder , & lzma_probs_allocator );
405
420
#endif
406
- goto done ;
421
+ return - EINVAL ;
407
422
}
408
423
409
424
allocated_probs = true;
@@ -427,45 +442,58 @@ static int lzma_decompress(void *inst, const uint8_t *input, size_t input_size,
427
442
return 0 ;
428
443
}
429
444
445
+ if (MAX_LZMA_DICT_SIZE - curr_dic_pos >= lzma_output_limit ) {
446
+ /* Limit the output size because we are reaching
447
+ * the limit of expected decompressed data size.
448
+ */
449
+ finish_mode = LZMA_FINISH_END ;
450
+ dic_limit = lzma_output_limit + curr_dic_pos ;
451
+ }
452
+
430
453
#ifdef CONFIG_NRF_COMPRESS_LZMA_VERSION_LZMA2
431
- rc = Lzma2Dec_DecodeToDic (& lzma_decoder , MAX_LZMA_DICT_SIZE , input , & chunk_size ,
432
- ( last_part ? LZMA_FINISH_END : LZMA_FINISH_ANY ) , & status );
454
+ rc = Lzma2Dec_DecodeToDic (& lzma_decoder , dic_limit ,
455
+ input , & chunk_size , finish_mode , & status );
433
456
#else
434
- rc = LzmaDec_DecodeToDic (& lzma_decoder , MAX_LZMA_DICT_SIZE , input , & chunk_size ,
435
- ( last_part ? LZMA_FINISH_END : LZMA_FINISH_ANY ) , & status );
457
+ rc = LzmaDec_DecodeToDic (& lzma_decoder , dic_limit ,
458
+ input , & chunk_size , finish_mode , & status );
436
459
#endif
437
460
438
- if (rc ) {
439
- rc = - EINVAL ;
440
- goto done ;
461
+ if (rc || chunk_size == 0 ) {
462
+ return - EINVAL ;
441
463
}
442
464
443
465
* offset = chunk_size ;
466
+ lzma_output_limit -= (* dic_pos - curr_dic_pos );
444
467
445
- if (last_part && (status == LZMA_STATUS_FINISHED_WITH_MARK ||
446
- status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK ) &&
468
+ if (last_part && status == LZMA_STATUS_FINISHED_WITH_MARK &&
447
469
* offset < input_size ) {
448
470
/* If last block, ensure offset matches complete file size */
449
471
* offset = input_size ;
450
472
}
451
473
474
+ if (last_part && * offset == input_size ) {
475
+ /* Check status of decompression on end of input stream.
476
+ * We accept LZMA_STATUS_NEEDS_MORE_INPUT if we reached
477
+ * the output limit (and only then) because we don't enforce that
478
+ * end-of-stream marker needs to be present in the compressed data.
479
+ */
480
+ if ( status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
481
+ && status != LZMA_STATUS_FINISHED_WITH_MARK
482
+ && (status != LZMA_STATUS_NEEDS_MORE_INPUT && lzma_output_limit == 0 )) {
483
+ return - EINVAL ;
484
+ }
485
+ }
486
+
487
+ if (* dic_pos >= MAX_LZMA_DICT_SIZE || last_part ) {
452
488
#ifdef CONFIG_NRF_COMPRESS_LZMA_VERSION_LZMA2
453
- if (lzma_decoder .decoder .dicPos >= lzma_decoder .decoder .dicBufSize ||
454
- (last_part && input_size == * offset )) {
455
489
* output = lzma_decoder .decoder .dic ;
456
- * output_size = lzma_decoder .decoder .dicPos ;
457
- lzma_decoder .decoder .dicPos = 0 ;
458
- }
459
490
#else
460
- if (lzma_decoder .dicPos >= lzma_decoder .dicBufSize ||
461
- (last_part && input_size == * offset )) {
462
491
* output = lzma_decoder .dic ;
463
- * output_size = lzma_decoder .dicPos ;
464
- lzma_decoder .dicPos = 0 ;
465
- }
466
492
#endif
493
+ * output_size = * dic_pos ;
494
+ * dic_pos = 0 ;
495
+ }
467
496
468
- done :
469
497
return rc ;
470
498
}
471
499
#else
@@ -476,6 +504,9 @@ static int lzma_decompress(void *inst, const uint8_t *input, size_t input_size,
476
504
ELzmaStatus status ;
477
505
size_t chunk_size = input_size ;
478
506
CLzmaDec * decoder ;
507
+ ELzmaFinishMode finish_mode = LZMA_FINISH_ANY ;
508
+ SizeT dic_limit ;
509
+ SizeT curr_dic_pos ;
479
510
480
511
rc = check_inst (inst );
481
512
@@ -496,6 +527,7 @@ static int lzma_decompress(void *inst, const uint8_t *input, size_t input_size,
496
527
#else
497
528
decoder = & lzma_decoder ;
498
529
#endif
530
+ curr_dic_pos = decoder -> dicPos ;
499
531
500
532
if (!allocated_probs ) {
501
533
#ifdef CONFIG_NRF_COMPRESS_LZMA_VERSION_LZMA2
@@ -538,27 +570,50 @@ static int lzma_decompress(void *inst, const uint8_t *input, size_t input_size,
538
570
return 0 ;
539
571
}
540
572
573
+ if (decoder -> dicHandle -> dicBufSize - curr_dic_pos >= lzma_output_limit ) {
574
+ /* Limit the output size because we are reaching
575
+ * the limit of expected decompressed data size.
576
+ */
577
+ finish_mode = LZMA_FINISH_END ;
578
+ dic_limit = lzma_output_limit + curr_dic_pos ;
579
+ } else {
580
+ dic_limit = decoder -> dicHandle -> dicBufSize ;
581
+ }
582
+
541
583
#ifdef CONFIG_NRF_COMPRESS_LZMA_VERSION_LZMA2
542
- rc = Lzma2Dec_DecodeToDic (& lzma_decoder , decoder -> dicHandle -> dicBufSize , input , & chunk_size ,
543
- LZMA_FINISH_ANY , & status );
584
+ rc = Lzma2Dec_DecodeToDic (& lzma_decoder , dic_limit ,
585
+ input , & chunk_size , finish_mode , & status );
544
586
#else
545
- rc = LzmaDec_DecodeToDic (& lzma_decoder , decoder -> dicHandle -> dicBufSize , input , & chunk_size ,
546
- LZMA_FINISH_ANY , & status );
587
+ rc = LzmaDec_DecodeToDic (& lzma_decoder , dic_limit ,
588
+ input , & chunk_size , finish_mode , & status );
547
589
#endif
548
- if (rc ) {
590
+ if (rc || chunk_size == 0 ) {
549
591
return - EINVAL ;
550
592
}
551
593
552
594
* offset = chunk_size ;
595
+ lzma_output_limit -= (decoder -> dicPos - curr_dic_pos );
553
596
554
- if (last_part && ( status == LZMA_STATUS_FINISHED_WITH_MARK ) &&
597
+ if (last_part && status == LZMA_STATUS_FINISHED_WITH_MARK &&
555
598
* offset < input_size ) {
556
599
/* If last block, ensure offset matches complete file size. */
557
600
* offset = input_size ;
558
601
}
559
602
560
- if (decoder -> dicPos >= decoder -> dicHandle -> dicBufSize ||
561
- (last_part && input_size == * offset )) {
603
+ if (last_part && * offset == input_size ) {
604
+ /* Check status of decompression on end of input stream.
605
+ * We accept LZMA_STATUS_NEEDS_MORE_INPUT if we reached
606
+ * the output limit (and only then) because we don't enforce that
607
+ * end-of-stream marker needs to be present in the compressed data.
608
+ */
609
+ if ( status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
610
+ && status != LZMA_STATUS_FINISHED_WITH_MARK
611
+ && (status != LZMA_STATUS_NEEDS_MORE_INPUT && lzma_output_limit == 0 )) {
612
+ return - EINVAL ;
613
+ }
614
+ }
615
+
616
+ if (decoder -> dicPos >= decoder -> dicHandle -> dicBufSize || last_part ) {
562
617
#if CONFIG_NRF_COMPRESS_DICTIONARY_CACHE_SIZE > 0
563
618
if (cache .invalid ) {
564
619
rc = synchronize_cache (decoder -> dicHandle );
0 commit comments