Fossil SCM

Check bounds and type for HTTP Content-length header. Also reject reply with two different Content-Length values. From libfossil.

danshearer 2026-10-11 22:29 UTC trunk
Commit 4df4f6c1dfa9e6af8e462572bfae90884557bd59bf3e7f528705c0d4f27ea675
1 file changed +22 -1
+22 -1
--- src/http.c
+++ src/http.c
@@ -614,12 +614,33 @@
614614
goto write_err;
615615
}
616616
if( iHttpVersion<0 ) iHttpVersion = 1;
617617
closeConnection = 0;
618618
}else if( fossil_strnicmp(zLine, "content-length:", 15)==0 ){
619
+ /* The value is one or more digits, optionally followed by
620
+ ** spaces, and fits in an int. Any other value is an error, and
621
+ ** so is a second Content-Length with a different value. */
622
+ sqlite3_int64 n = 0;
623
+ int iStart;
619624
for(i=15; fossil_isspace(zLine[i]); i++){}
620
- iLength = atoi(&zLine[i]);
625
+ for(iStart=i; fossil_isdigit(zLine[i]) && n<=0x7fffffff; i++){
626
+ n = n*10 + zLine[i] - '0';
627
+ }
628
+ if( i==iStart || n>0x7fffffff ){
629
+ fossil_warning("server sent a bad content-length: %s", zLine);
630
+ goto write_err;
631
+ }
632
+ for(; fossil_isspace(zLine[i]); i++){}
633
+ if( zLine[i]!=0 ){
634
+ fossil_warning("server sent a bad content-length: %s", zLine);
635
+ goto write_err;
636
+ }
637
+ if( iLength>=0 && iLength!=(int)n ){
638
+ fossil_warning("server sent two different content-length values");
639
+ goto write_err;
640
+ }
641
+ iLength = (int)n;
621642
}else if( fossil_strnicmp(zLine, "transfer-encoding:", 18)==0 ){
622643
/* Fossil never sends a "transfer-encoding:" request header, so we may
623644
** reject any encoding other than "chunked", including "gzip, chunked",
624645
** "superchunked", "deflate" etc. */
625646
int bOk = 0;
626647
--- src/http.c
+++ src/http.c
@@ -614,12 +614,33 @@
614 goto write_err;
615 }
616 if( iHttpVersion<0 ) iHttpVersion = 1;
617 closeConnection = 0;
618 }else if( fossil_strnicmp(zLine, "content-length:", 15)==0 ){
 
 
 
 
 
619 for(i=15; fossil_isspace(zLine[i]); i++){}
620 iLength = atoi(&zLine[i]);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
621 }else if( fossil_strnicmp(zLine, "transfer-encoding:", 18)==0 ){
622 /* Fossil never sends a "transfer-encoding:" request header, so we may
623 ** reject any encoding other than "chunked", including "gzip, chunked",
624 ** "superchunked", "deflate" etc. */
625 int bOk = 0;
626
--- src/http.c
+++ src/http.c
@@ -614,12 +614,33 @@
614 goto write_err;
615 }
616 if( iHttpVersion<0 ) iHttpVersion = 1;
617 closeConnection = 0;
618 }else if( fossil_strnicmp(zLine, "content-length:", 15)==0 ){
619 /* The value is one or more digits, optionally followed by
620 ** spaces, and fits in an int. Any other value is an error, and
621 ** so is a second Content-Length with a different value. */
622 sqlite3_int64 n = 0;
623 int iStart;
624 for(i=15; fossil_isspace(zLine[i]); i++){}
625 for(iStart=i; fossil_isdigit(zLine[i]) && n<=0x7fffffff; i++){
626 n = n*10 + zLine[i] - '0';
627 }
628 if( i==iStart || n>0x7fffffff ){
629 fossil_warning("server sent a bad content-length: %s", zLine);
630 goto write_err;
631 }
632 for(; fossil_isspace(zLine[i]); i++){}
633 if( zLine[i]!=0 ){
634 fossil_warning("server sent a bad content-length: %s", zLine);
635 goto write_err;
636 }
637 if( iLength>=0 && iLength!=(int)n ){
638 fossil_warning("server sent two different content-length values");
639 goto write_err;
640 }
641 iLength = (int)n;
642 }else if( fossil_strnicmp(zLine, "transfer-encoding:", 18)==0 ){
643 /* Fossil never sends a "transfer-encoding:" request header, so we may
644 ** reject any encoding other than "chunked", including "gzip, chunked",
645 ** "superchunked", "deflate" etc. */
646 int bOk = 0;
647

Keyboard Shortcuts

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