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