Fossil SCM
Harden delta processing against malicious delta inputs.
Commit
60c7b5f4231f3725fac704631de2c7bdd8854dde9d89b0b499a754f51b45e184
Parent
cc021ea610dddbc…
1 file changed
+26
-14
+26
-14
| --- src/delta.c | ||
| +++ src/delta.c | ||
| @@ -186,20 +186,29 @@ | ||
| 186 | 186 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, |
| 187 | 187 | -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, |
| 188 | 188 | 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, 36, |
| 189 | 189 | -1, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, |
| 190 | 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, | |
| 191 | 200 | }; |
| 192 | 201 | unsigned int v = 0; |
| 193 | 202 | int c; |
| 194 | 203 | 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++; | |
| 198 | 208 | } |
| 199 | - z--; | |
| 200 | - *pLen -= z - zStart; | |
| 209 | + *pLen -= (int)(z - (unsigned char*)*pz); | |
| 201 | 210 | *pz = (char*)z; |
| 202 | 211 | return v; |
| 203 | 212 | } |
| 204 | 213 | |
| 205 | 214 | /* |
| @@ -537,11 +546,11 @@ | ||
| 537 | 546 | ** needed. |
| 538 | 547 | */ |
| 539 | 548 | int delta_output_size(const char *zDelta, int lenDelta){ |
| 540 | 549 | int size; |
| 541 | 550 | size = getInt(&zDelta, &lenDelta); |
| 542 | - if( *zDelta!='\n' ){ | |
| 551 | + if( lenDelta<=0 || *zDelta!='\n' ){ | |
| 543 | 552 | /* ERROR: size integer not terminated by "\n" */ |
| 544 | 553 | return -1; |
| 545 | 554 | } |
| 546 | 555 | return size; |
| 547 | 556 | } |
| @@ -574,28 +583,30 @@ | ||
| 574 | 583 | int lenDelta, /* Length of the delta */ |
| 575 | 584 | char *zOut /* Write the output into this preallocated buffer */ |
| 576 | 585 | ){ |
| 577 | 586 | sqlite3_uint64 limit; |
| 578 | 587 | sqlite3_uint64 total = 0; |
| 588 | + | |
| 579 | 589 | #ifdef FOSSIL_ENABLE_DELTA_CKSUM_TEST |
| 580 | 590 | char *zOrigOut = zOut; |
| 581 | 591 | #endif |
| 582 | 592 | |
| 583 | 593 | limit = getInt(&zDelta, &lenDelta); |
| 584 | - if( *zDelta!='\n' ){ | |
| 594 | + if( lenDelta<=0 || *zDelta!='\n' ){ | |
| 585 | 595 | /* ERROR: size integer not terminated by "\n" */ |
| 586 | 596 | return -1; |
| 587 | 597 | } |
| 588 | - zDelta++; lenDelta--; | |
| 589 | - while( *zDelta && lenDelta>0 ){ | |
| 598 | + zDelta++; lenDelta--; /* Skip the \n */ | |
| 599 | + while( lenDelta>0 && zDelta[0] ){ | |
| 590 | 600 | unsigned int cnt, ofst; |
| 591 | 601 | cnt = getInt(&zDelta, &lenDelta); |
| 602 | + if( lenDelta<=0 ) break; | |
| 592 | 603 | switch( zDelta[0] ){ |
| 593 | 604 | case '@': { |
| 594 | 605 | zDelta++; lenDelta--; |
| 595 | 606 | ofst = getInt(&zDelta, &lenDelta); |
| 596 | - if( lenDelta>0 && zDelta[0]!=',' ){ | |
| 607 | + if( lenDelta<=0 || zDelta[0]!=',' ){ | |
| 597 | 608 | /* ERROR: copy command not terminated by ',' */ |
| 598 | 609 | return -1; |
| 599 | 610 | } |
| 600 | 611 | zDelta++; lenDelta--; |
| 601 | 612 | DEBUG1( printf("COPY %d from %d\n", cnt, ofst); ) |
| @@ -618,11 +629,11 @@ | ||
| 618 | 629 | if( total>limit ){ |
| 619 | 630 | /* ERROR: insert command gives an output larger than predicted */ |
| 620 | 631 | return -1; |
| 621 | 632 | } |
| 622 | 633 | DEBUG1( printf("INSERT %d\n", cnt); ) |
| 623 | - if( (int)cnt>lenDelta ){ | |
| 634 | + if( (i64)cnt>(i64)lenDelta ){ | |
| 624 | 635 | /* ERROR: insert count exceeds size of delta */ |
| 625 | 636 | return -1; |
| 626 | 637 | } |
| 627 | 638 | memcpy(zOut, zDelta, cnt); |
| 628 | 639 | zOut += cnt; |
| @@ -668,23 +679,24 @@ | ||
| 668 | 679 | ){ |
| 669 | 680 | unsigned int nInsert = 0; |
| 670 | 681 | unsigned int nCopy = 0; |
| 671 | 682 | |
| 672 | 683 | (void)getInt(&zDelta, &lenDelta); |
| 673 | - if( *zDelta!='\n' ){ | |
| 684 | + if( lenDelta<=0 || *zDelta!='\n' ){ | |
| 674 | 685 | /* ERROR: size integer not terminated by "\n" */ |
| 675 | 686 | return -1; |
| 676 | 687 | } |
| 677 | 688 | zDelta++; lenDelta--; |
| 678 | 689 | while( *zDelta && lenDelta>0 ){ |
| 679 | 690 | unsigned int cnt; |
| 680 | 691 | cnt = getInt(&zDelta, &lenDelta); |
| 692 | + if( lenDelta<=0 ) break; | |
| 681 | 693 | switch( zDelta[0] ){ |
| 682 | 694 | case '@': { |
| 683 | 695 | zDelta++; lenDelta--; |
| 684 | 696 | (void)getInt(&zDelta, &lenDelta); |
| 685 | - if( lenDelta>0 && zDelta[0]!=',' ){ | |
| 697 | + if( lenDelta<=0 || zDelta[0]!=',' ){ | |
| 686 | 698 | /* ERROR: copy command not terminated by ',' */ |
| 687 | 699 | return -1; |
| 688 | 700 | } |
| 689 | 701 | zDelta++; lenDelta--; |
| 690 | 702 | nCopy += cnt; |
| @@ -691,11 +703,11 @@ | ||
| 691 | 703 | break; |
| 692 | 704 | } |
| 693 | 705 | case ':': { |
| 694 | 706 | zDelta++; lenDelta--; |
| 695 | 707 | nInsert += cnt; |
| 696 | - if( (int)cnt>lenDelta ){ | |
| 708 | + if( (i64)cnt>(i64)lenDelta ){ | |
| 697 | 709 | /* ERROR: insert count exceeds size of delta */ |
| 698 | 710 | return -1; |
| 699 | 711 | } |
| 700 | 712 | zDelta += cnt; |
| 701 | 713 | lenDelta -= cnt; |
| 702 | 714 |
| --- 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 |