Fossil SCM
Fix an integer overflow vulnerability. Shorten all source code lines to be no more than 80 characters. Do not select the "chunked" transfer encoding, if the last token of the transfer-encoding is some keyword that has "chunked" as a suffix, ex: "superchunked".
Commit
82723bf87c0da0c0a2fd214d5f13a24b4a0c38ca17933729c3118f334f7e035e
Parent
109a5e1a0432c0d…
1 file changed
+14
-11
+14
-11
| --- src/http.c | ||
| +++ src/http.c | ||
| @@ -611,11 +611,12 @@ | ||
| 611 | 611 | iLength = atoi(&zLine[i]); |
| 612 | 612 | }else if( fossil_strnicmp(zLine, "transfer-encoding:", 18)==0 ){ |
| 613 | 613 | /* RFC 7230: "chunked" must be the final transfer-coding so only |
| 614 | 614 | ** match when it appears at the end of the line. */ |
| 615 | 615 | if( sqlite3_strlike("%chunked", &zLine[18], 0)==0 ){ |
| 616 | - isChunked = 1; | |
| 616 | + size_t nx = strlen(&zLine[18]); | |
| 617 | + if( !fossil_isalnum(zLine[nx+11]) ) isChunked = 1; | |
| 617 | 618 | } |
| 618 | 619 | }else if( fossil_strnicmp(zLine, "connection:", 11)==0 ){ |
| 619 | 620 | if( sqlite3_strlike("%close%", &zLine[11], 0)==0 ){ |
| 620 | 621 | closeConnection = 1; |
| 621 | 622 | }else if( sqlite3_strlike("%keep-alive%", &zLine[11], 0)==0 ){ |
| @@ -750,15 +751,15 @@ | ||
| 750 | 751 | ** chunk is a hex length on its own line (optionally followed by a |
| 751 | 752 | ** ";extension" that is ignored), then that many payload bytes, then a |
| 752 | 753 | ** bare CRLF. A zero-length chunk terminates the body, after which any |
| 753 | 754 | ** trailer header lines are read and discarded up to the blank line. */ |
| 754 | 755 | char *zChunk; |
| 755 | - int sawTerminator = 0; /* True once the 0-length chunk is seen */ | |
| 756 | + int sawTerminator = 0; /* True once the 0-length chunk is seen */ | |
| 756 | 757 | while( (zChunk = transport_receive_line(&g.url))!=0 && zChunk[0]!=0 ){ |
| 757 | - sqlite3_int64 nChunk; /* Size of this chunk in bytes (wide, unclamped) */ | |
| 758 | - unsigned int nPrior; /* Bytes already in pReply (matches blob nUsed) */ | |
| 759 | - char *zEnd = 0; /* End of the hex digits actually parsed */ | |
| 758 | + i64 nChunk; /* Size of this chunk in bytes (wide, unclamped) */ | |
| 759 | + i64 nPrior; /* Bytes already in pReply (matches blob nUsed) */ | |
| 760 | + char *zEnd = 0; /* End of the hex digits actually parsed */ | |
| 760 | 761 | while( fossil_isspace(zChunk[0]) ) zChunk++; |
| 761 | 762 | nChunk = strtoll(zChunk, &zEnd, 16); |
| 762 | 763 | if( zEnd==zChunk ){ |
| 763 | 764 | /* No hex digit consumed: a blank or malformed chunk-size line, which |
| 764 | 765 | ** is the symptom of a connection that closed mid-stream. Treat it as |
| @@ -779,23 +780,25 @@ | ||
| 779 | 780 | } |
| 780 | 781 | nPrior = blob_size(pReply); |
| 781 | 782 | /* Reserve space without advancing nUsed, so that on error |
| 782 | 783 | ** the blob's reported size equals the bytes actually |
| 783 | 784 | ** received rather the claimed chunk length */ |
| 784 | - blob_reserve(pReply, nPrior+(unsigned int)nChunk); | |
| 785 | + blob_reserve(pReply, (u64)(nPrior+nChunk)); | |
| 785 | 786 | { |
| 786 | 787 | unsigned int nRemaining = (unsigned int)nChunk; |
| 787 | - /* transport_receive() may return short; loop until the chunk is full. */ | |
| 788 | + /* transport_receive() may return short; loop until the chunk is | |
| 789 | + ** full. */ | |
| 788 | 790 | while( nRemaining>0 ){ |
| 789 | - int nGot = transport_receive(&g.url, &pReply->aData[nPrior], nRemaining); | |
| 791 | + int nGot; | |
| 792 | + nGot = transport_receive(&g.url, &pReply->aData[nPrior], nRemaining); | |
| 790 | 793 | if( nGot<=0 ){ |
| 791 | 794 | fossil_warning("chunked reply truncated"); |
| 792 | 795 | goto write_err; |
| 793 | 796 | } |
| 794 | - nPrior += (unsigned int)nGot; | |
| 795 | - nRemaining -= (unsigned int)nGot; | |
| 796 | - pReply->nUsed = nPrior; | |
| 797 | + nPrior += nGot; | |
| 798 | + nRemaining -= nGot; | |
| 799 | + pReply->nUsed = (unsigned int)nPrior; | |
| 797 | 800 | } |
| 798 | 801 | } |
| 799 | 802 | transport_receive_line(&g.url); /* CRLF that follows the chunk data */ |
| 800 | 803 | } |
| 801 | 804 | if( !sawTerminator ){ |
| 802 | 805 |
| --- src/http.c | |
| +++ src/http.c | |
| @@ -611,11 +611,12 @@ | |
| 611 | iLength = atoi(&zLine[i]); |
| 612 | }else if( fossil_strnicmp(zLine, "transfer-encoding:", 18)==0 ){ |
| 613 | /* RFC 7230: "chunked" must be the final transfer-coding so only |
| 614 | ** match when it appears at the end of the line. */ |
| 615 | if( sqlite3_strlike("%chunked", &zLine[18], 0)==0 ){ |
| 616 | isChunked = 1; |
| 617 | } |
| 618 | }else if( fossil_strnicmp(zLine, "connection:", 11)==0 ){ |
| 619 | if( sqlite3_strlike("%close%", &zLine[11], 0)==0 ){ |
| 620 | closeConnection = 1; |
| 621 | }else if( sqlite3_strlike("%keep-alive%", &zLine[11], 0)==0 ){ |
| @@ -750,15 +751,15 @@ | |
| 750 | ** chunk is a hex length on its own line (optionally followed by a |
| 751 | ** ";extension" that is ignored), then that many payload bytes, then a |
| 752 | ** bare CRLF. A zero-length chunk terminates the body, after which any |
| 753 | ** trailer header lines are read and discarded up to the blank line. */ |
| 754 | char *zChunk; |
| 755 | int sawTerminator = 0; /* True once the 0-length chunk is seen */ |
| 756 | while( (zChunk = transport_receive_line(&g.url))!=0 && zChunk[0]!=0 ){ |
| 757 | sqlite3_int64 nChunk; /* Size of this chunk in bytes (wide, unclamped) */ |
| 758 | unsigned int nPrior; /* Bytes already in pReply (matches blob nUsed) */ |
| 759 | char *zEnd = 0; /* End of the hex digits actually parsed */ |
| 760 | while( fossil_isspace(zChunk[0]) ) zChunk++; |
| 761 | nChunk = strtoll(zChunk, &zEnd, 16); |
| 762 | if( zEnd==zChunk ){ |
| 763 | /* No hex digit consumed: a blank or malformed chunk-size line, which |
| 764 | ** is the symptom of a connection that closed mid-stream. Treat it as |
| @@ -779,23 +780,25 @@ | |
| 779 | } |
| 780 | nPrior = blob_size(pReply); |
| 781 | /* Reserve space without advancing nUsed, so that on error |
| 782 | ** the blob's reported size equals the bytes actually |
| 783 | ** received rather the claimed chunk length */ |
| 784 | blob_reserve(pReply, nPrior+(unsigned int)nChunk); |
| 785 | { |
| 786 | unsigned int nRemaining = (unsigned int)nChunk; |
| 787 | /* transport_receive() may return short; loop until the chunk is full. */ |
| 788 | while( nRemaining>0 ){ |
| 789 | int nGot = transport_receive(&g.url, &pReply->aData[nPrior], nRemaining); |
| 790 | if( nGot<=0 ){ |
| 791 | fossil_warning("chunked reply truncated"); |
| 792 | goto write_err; |
| 793 | } |
| 794 | nPrior += (unsigned int)nGot; |
| 795 | nRemaining -= (unsigned int)nGot; |
| 796 | pReply->nUsed = nPrior; |
| 797 | } |
| 798 | } |
| 799 | transport_receive_line(&g.url); /* CRLF that follows the chunk data */ |
| 800 | } |
| 801 | if( !sawTerminator ){ |
| 802 |
| --- src/http.c | |
| +++ src/http.c | |
| @@ -611,11 +611,12 @@ | |
| 611 | iLength = atoi(&zLine[i]); |
| 612 | }else if( fossil_strnicmp(zLine, "transfer-encoding:", 18)==0 ){ |
| 613 | /* RFC 7230: "chunked" must be the final transfer-coding so only |
| 614 | ** match when it appears at the end of the line. */ |
| 615 | if( sqlite3_strlike("%chunked", &zLine[18], 0)==0 ){ |
| 616 | size_t nx = strlen(&zLine[18]); |
| 617 | if( !fossil_isalnum(zLine[nx+11]) ) isChunked = 1; |
| 618 | } |
| 619 | }else if( fossil_strnicmp(zLine, "connection:", 11)==0 ){ |
| 620 | if( sqlite3_strlike("%close%", &zLine[11], 0)==0 ){ |
| 621 | closeConnection = 1; |
| 622 | }else if( sqlite3_strlike("%keep-alive%", &zLine[11], 0)==0 ){ |
| @@ -750,15 +751,15 @@ | |
| 751 | ** chunk is a hex length on its own line (optionally followed by a |
| 752 | ** ";extension" that is ignored), then that many payload bytes, then a |
| 753 | ** bare CRLF. A zero-length chunk terminates the body, after which any |
| 754 | ** trailer header lines are read and discarded up to the blank line. */ |
| 755 | char *zChunk; |
| 756 | int sawTerminator = 0; /* True once the 0-length chunk is seen */ |
| 757 | while( (zChunk = transport_receive_line(&g.url))!=0 && zChunk[0]!=0 ){ |
| 758 | i64 nChunk; /* Size of this chunk in bytes (wide, unclamped) */ |
| 759 | i64 nPrior; /* Bytes already in pReply (matches blob nUsed) */ |
| 760 | char *zEnd = 0; /* End of the hex digits actually parsed */ |
| 761 | while( fossil_isspace(zChunk[0]) ) zChunk++; |
| 762 | nChunk = strtoll(zChunk, &zEnd, 16); |
| 763 | if( zEnd==zChunk ){ |
| 764 | /* No hex digit consumed: a blank or malformed chunk-size line, which |
| 765 | ** is the symptom of a connection that closed mid-stream. Treat it as |
| @@ -779,23 +780,25 @@ | |
| 780 | } |
| 781 | nPrior = blob_size(pReply); |
| 782 | /* Reserve space without advancing nUsed, so that on error |
| 783 | ** the blob's reported size equals the bytes actually |
| 784 | ** received rather the claimed chunk length */ |
| 785 | blob_reserve(pReply, (u64)(nPrior+nChunk)); |
| 786 | { |
| 787 | unsigned int nRemaining = (unsigned int)nChunk; |
| 788 | /* transport_receive() may return short; loop until the chunk is |
| 789 | ** full. */ |
| 790 | while( nRemaining>0 ){ |
| 791 | int nGot; |
| 792 | nGot = transport_receive(&g.url, &pReply->aData[nPrior], nRemaining); |
| 793 | if( nGot<=0 ){ |
| 794 | fossil_warning("chunked reply truncated"); |
| 795 | goto write_err; |
| 796 | } |
| 797 | nPrior += nGot; |
| 798 | nRemaining -= nGot; |
| 799 | pReply->nUsed = (unsigned int)nPrior; |
| 800 | } |
| 801 | } |
| 802 | transport_receive_line(&g.url); /* CRLF that follows the chunk data */ |
| 803 | } |
| 804 | if( !sawTerminator ){ |
| 805 |