Fossil SCM

Harden delta processing against malicious delta inputs.

drh 2026-06-10 09:02 UTC trunk
Commit 60c7b5f4231f3725fac704631de2c7bdd8854dde9d89b0b499a754f51b45e184
1 file changed +26 -14
+26 -14
--- src/delta.c
+++ src/delta.c
@@ -186,20 +186,29 @@
186186
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
187187
-1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
188188
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, 36,
189189
-1, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
190190
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, -1, -1, -1, 63, -1,
191
+
192
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
193
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
194
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
195
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
196
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
197
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
198
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
199
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
191200
};
192201
unsigned int v = 0;
193202
int c;
194203
unsigned char *z = (unsigned char*)*pz;
195
- unsigned char *zStart = z;
196
- while( (c = zValue[0x7f&*(z++)])>=0 ){
197
- v = (v<<6) + c;
204
+ unsigned char *zEnd = z + (*pLen);
205
+ while( z<zEnd && (c = zValue[*z])>=0 ){
206
+ v = (v<<6) + c;
207
+ z++;
198208
}
199
- z--;
200
- *pLen -= z - zStart;
209
+ *pLen -= (int)(z - (unsigned char*)*pz);
201210
*pz = (char*)z;
202211
return v;
203212
}
204213
205214
/*
@@ -537,11 +546,11 @@
537546
** needed.
538547
*/
539548
int delta_output_size(const char *zDelta, int lenDelta){
540549
int size;
541550
size = getInt(&zDelta, &lenDelta);
542
- if( *zDelta!='\n' ){
551
+ if( lenDelta<=0 || *zDelta!='\n' ){
543552
/* ERROR: size integer not terminated by "\n" */
544553
return -1;
545554
}
546555
return size;
547556
}
@@ -574,28 +583,30 @@
574583
int lenDelta, /* Length of the delta */
575584
char *zOut /* Write the output into this preallocated buffer */
576585
){
577586
sqlite3_uint64 limit;
578587
sqlite3_uint64 total = 0;
588
+
579589
#ifdef FOSSIL_ENABLE_DELTA_CKSUM_TEST
580590
char *zOrigOut = zOut;
581591
#endif
582592
583593
limit = getInt(&zDelta, &lenDelta);
584
- if( *zDelta!='\n' ){
594
+ if( lenDelta<=0 || *zDelta!='\n' ){
585595
/* ERROR: size integer not terminated by "\n" */
586596
return -1;
587597
}
588
- zDelta++; lenDelta--;
589
- while( *zDelta && lenDelta>0 ){
598
+ zDelta++; lenDelta--; /* Skip the \n */
599
+ while( lenDelta>0 && zDelta[0] ){
590600
unsigned int cnt, ofst;
591601
cnt = getInt(&zDelta, &lenDelta);
602
+ if( lenDelta<=0 ) break;
592603
switch( zDelta[0] ){
593604
case '@': {
594605
zDelta++; lenDelta--;
595606
ofst = getInt(&zDelta, &lenDelta);
596
- if( lenDelta>0 && zDelta[0]!=',' ){
607
+ if( lenDelta<=0 || zDelta[0]!=',' ){
597608
/* ERROR: copy command not terminated by ',' */
598609
return -1;
599610
}
600611
zDelta++; lenDelta--;
601612
DEBUG1( printf("COPY %d from %d\n", cnt, ofst); )
@@ -618,11 +629,11 @@
618629
if( total>limit ){
619630
/* ERROR: insert command gives an output larger than predicted */
620631
return -1;
621632
}
622633
DEBUG1( printf("INSERT %d\n", cnt); )
623
- if( (int)cnt>lenDelta ){
634
+ if( (i64)cnt>(i64)lenDelta ){
624635
/* ERROR: insert count exceeds size of delta */
625636
return -1;
626637
}
627638
memcpy(zOut, zDelta, cnt);
628639
zOut += cnt;
@@ -668,23 +679,24 @@
668679
){
669680
unsigned int nInsert = 0;
670681
unsigned int nCopy = 0;
671682
672683
(void)getInt(&zDelta, &lenDelta);
673
- if( *zDelta!='\n' ){
684
+ if( lenDelta<=0 || *zDelta!='\n' ){
674685
/* ERROR: size integer not terminated by "\n" */
675686
return -1;
676687
}
677688
zDelta++; lenDelta--;
678689
while( *zDelta && lenDelta>0 ){
679690
unsigned int cnt;
680691
cnt = getInt(&zDelta, &lenDelta);
692
+ if( lenDelta<=0 ) break;
681693
switch( zDelta[0] ){
682694
case '@': {
683695
zDelta++; lenDelta--;
684696
(void)getInt(&zDelta, &lenDelta);
685
- if( lenDelta>0 && zDelta[0]!=',' ){
697
+ if( lenDelta<=0 || zDelta[0]!=',' ){
686698
/* ERROR: copy command not terminated by ',' */
687699
return -1;
688700
}
689701
zDelta++; lenDelta--;
690702
nCopy += cnt;
@@ -691,11 +703,11 @@
691703
break;
692704
}
693705
case ':': {
694706
zDelta++; lenDelta--;
695707
nInsert += cnt;
696
- if( (int)cnt>lenDelta ){
708
+ if( (i64)cnt>(i64)lenDelta ){
697709
/* ERROR: insert count exceeds size of delta */
698710
return -1;
699711
}
700712
zDelta += cnt;
701713
lenDelta -= cnt;
702714
--- src/delta.c
+++ src/delta.c
@@ -186,20 +186,29 @@
186 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
187 -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
188 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, 36,
189 -1, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
190 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, -1, -1, -1, 63, -1,
 
 
 
 
 
 
 
 
 
191 };
192 unsigned int v = 0;
193 int c;
194 unsigned char *z = (unsigned char*)*pz;
195 unsigned char *zStart = z;
196 while( (c = zValue[0x7f&*(z++)])>=0 ){
197 v = (v<<6) + c;
 
198 }
199 z--;
200 *pLen -= z - zStart;
201 *pz = (char*)z;
202 return v;
203 }
204
205 /*
@@ -537,11 +546,11 @@
537 ** needed.
538 */
539 int delta_output_size(const char *zDelta, int lenDelta){
540 int size;
541 size = getInt(&zDelta, &lenDelta);
542 if( *zDelta!='\n' ){
543 /* ERROR: size integer not terminated by "\n" */
544 return -1;
545 }
546 return size;
547 }
@@ -574,28 +583,30 @@
574 int lenDelta, /* Length of the delta */
575 char *zOut /* Write the output into this preallocated buffer */
576 ){
577 sqlite3_uint64 limit;
578 sqlite3_uint64 total = 0;
 
579 #ifdef FOSSIL_ENABLE_DELTA_CKSUM_TEST
580 char *zOrigOut = zOut;
581 #endif
582
583 limit = getInt(&zDelta, &lenDelta);
584 if( *zDelta!='\n' ){
585 /* ERROR: size integer not terminated by "\n" */
586 return -1;
587 }
588 zDelta++; lenDelta--;
589 while( *zDelta && lenDelta>0 ){
590 unsigned int cnt, ofst;
591 cnt = getInt(&zDelta, &lenDelta);
 
592 switch( zDelta[0] ){
593 case '@': {
594 zDelta++; lenDelta--;
595 ofst = getInt(&zDelta, &lenDelta);
596 if( lenDelta>0 && zDelta[0]!=',' ){
597 /* ERROR: copy command not terminated by ',' */
598 return -1;
599 }
600 zDelta++; lenDelta--;
601 DEBUG1( printf("COPY %d from %d\n", cnt, ofst); )
@@ -618,11 +629,11 @@
618 if( total>limit ){
619 /* ERROR: insert command gives an output larger than predicted */
620 return -1;
621 }
622 DEBUG1( printf("INSERT %d\n", cnt); )
623 if( (int)cnt>lenDelta ){
624 /* ERROR: insert count exceeds size of delta */
625 return -1;
626 }
627 memcpy(zOut, zDelta, cnt);
628 zOut += cnt;
@@ -668,23 +679,24 @@
668 ){
669 unsigned int nInsert = 0;
670 unsigned int nCopy = 0;
671
672 (void)getInt(&zDelta, &lenDelta);
673 if( *zDelta!='\n' ){
674 /* ERROR: size integer not terminated by "\n" */
675 return -1;
676 }
677 zDelta++; lenDelta--;
678 while( *zDelta && lenDelta>0 ){
679 unsigned int cnt;
680 cnt = getInt(&zDelta, &lenDelta);
 
681 switch( zDelta[0] ){
682 case '@': {
683 zDelta++; lenDelta--;
684 (void)getInt(&zDelta, &lenDelta);
685 if( lenDelta>0 && zDelta[0]!=',' ){
686 /* ERROR: copy command not terminated by ',' */
687 return -1;
688 }
689 zDelta++; lenDelta--;
690 nCopy += cnt;
@@ -691,11 +703,11 @@
691 break;
692 }
693 case ':': {
694 zDelta++; lenDelta--;
695 nInsert += cnt;
696 if( (int)cnt>lenDelta ){
697 /* ERROR: insert count exceeds size of delta */
698 return -1;
699 }
700 zDelta += cnt;
701 lenDelta -= cnt;
702
--- src/delta.c
+++ src/delta.c
@@ -186,20 +186,29 @@
186 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
187 -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
188 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, 36,
189 -1, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
190 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, -1, -1, -1, 63, -1,
191
192 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
193 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
194 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
195 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
196 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
197 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
198 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
199 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
200 };
201 unsigned int v = 0;
202 int c;
203 unsigned char *z = (unsigned char*)*pz;
204 unsigned char *zEnd = z + (*pLen);
205 while( z<zEnd && (c = zValue[*z])>=0 ){
206 v = (v<<6) + c;
207 z++;
208 }
209 *pLen -= (int)(z - (unsigned char*)*pz);
 
210 *pz = (char*)z;
211 return v;
212 }
213
214 /*
@@ -537,11 +546,11 @@
546 ** needed.
547 */
548 int delta_output_size(const char *zDelta, int lenDelta){
549 int size;
550 size = getInt(&zDelta, &lenDelta);
551 if( lenDelta<=0 || *zDelta!='\n' ){
552 /* ERROR: size integer not terminated by "\n" */
553 return -1;
554 }
555 return size;
556 }
@@ -574,28 +583,30 @@
583 int lenDelta, /* Length of the delta */
584 char *zOut /* Write the output into this preallocated buffer */
585 ){
586 sqlite3_uint64 limit;
587 sqlite3_uint64 total = 0;
588
589 #ifdef FOSSIL_ENABLE_DELTA_CKSUM_TEST
590 char *zOrigOut = zOut;
591 #endif
592
593 limit = getInt(&zDelta, &lenDelta);
594 if( lenDelta<=0 || *zDelta!='\n' ){
595 /* ERROR: size integer not terminated by "\n" */
596 return -1;
597 }
598 zDelta++; lenDelta--; /* Skip the \n */
599 while( lenDelta>0 && zDelta[0] ){
600 unsigned int cnt, ofst;
601 cnt = getInt(&zDelta, &lenDelta);
602 if( lenDelta<=0 ) break;
603 switch( zDelta[0] ){
604 case '@': {
605 zDelta++; lenDelta--;
606 ofst = getInt(&zDelta, &lenDelta);
607 if( lenDelta<=0 || zDelta[0]!=',' ){
608 /* ERROR: copy command not terminated by ',' */
609 return -1;
610 }
611 zDelta++; lenDelta--;
612 DEBUG1( printf("COPY %d from %d\n", cnt, ofst); )
@@ -618,11 +629,11 @@
629 if( total>limit ){
630 /* ERROR: insert command gives an output larger than predicted */
631 return -1;
632 }
633 DEBUG1( printf("INSERT %d\n", cnt); )
634 if( (i64)cnt>(i64)lenDelta ){
635 /* ERROR: insert count exceeds size of delta */
636 return -1;
637 }
638 memcpy(zOut, zDelta, cnt);
639 zOut += cnt;
@@ -668,23 +679,24 @@
679 ){
680 unsigned int nInsert = 0;
681 unsigned int nCopy = 0;
682
683 (void)getInt(&zDelta, &lenDelta);
684 if( lenDelta<=0 || *zDelta!='\n' ){
685 /* ERROR: size integer not terminated by "\n" */
686 return -1;
687 }
688 zDelta++; lenDelta--;
689 while( *zDelta && lenDelta>0 ){
690 unsigned int cnt;
691 cnt = getInt(&zDelta, &lenDelta);
692 if( lenDelta<=0 ) break;
693 switch( zDelta[0] ){
694 case '@': {
695 zDelta++; lenDelta--;
696 (void)getInt(&zDelta, &lenDelta);
697 if( lenDelta<=0 || zDelta[0]!=',' ){
698 /* ERROR: copy command not terminated by ',' */
699 return -1;
700 }
701 zDelta++; lenDelta--;
702 nCopy += cnt;
@@ -691,11 +703,11 @@
703 break;
704 }
705 case ':': {
706 zDelta++; lenDelta--;
707 nInsert += cnt;
708 if( (i64)cnt>(i64)lenDelta ){
709 /* ERROR: insert count exceeds size of delta */
710 return -1;
711 }
712 zDelta += cnt;
713 lenDelta -= cnt;
714

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button