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