On June 18, 2026 7:44:31 PM UTC, Andrew Kloet <[email protected]> wrote:
>>Synopsis:      HTTP suffix-range requests omits file contents
>>Category:      user
>>Environment:
>       System      : OpenBSD 7.9
>       Details     : OpenBSD 7.9 (GENERIC.MP) #449: Wed May  6 13:17:25 MDT 
> 2026
>                       
> [email protected]:/usr/src/sys/arch/amd64/compile/GENERIC.MP
>
>       Architecture: OpenBSD.amd64
>       Machine     : amd64
>>Description:
>       There is a logic flaw inside httpd's parse_range_sepc when
>       processing HTTP Byte-Range Requests.
>
>       When a client issues a suffix-range request (Range: bytes=-num to
>       request the trailing num bytes of a resource) where the requested
>       count is larger than the target file size, an overflow guard caps
>       r->end to size - 1 prematurely.
>
>       Because this truncation happens before the evaluation block
>       calculates the starting byte offset (r->start = size - r->end), the
>       resulting offset math evaluates to 1 instead of 0. As a result,
>       httpd serves a 206 Partial Content response that completely omits
>       the very first byte (offset 0) of the target file.
>>How-To-Repeat:
>       # Create an 11-byte file
>       $ echo "0123456789" > /var/www/htdocs/test
>
>       # Send an HTTP request with a suffix range exceeding the file size.
>       # Note the response headers show an incorrect range and omit the
>       # leading character
>       $ curl -v -H "Range: bytes=-15" http://127.0.0.1/test
>       < HTTP/1.1 206 Partial Content
>       < Content-Range: bytes 1-10/11
>       < Content-Length: 10
>       123456789
>>Fix:
>       Decouple the suffix range processing from standard ranges within
>       parse_range_spec so that ceiling adjustments to r->end don't corrupt
>       the initial offset computation.
>
>--- a/usr.sbin/httpd/server_file.c
>+++ b/usr.sbin/httpd/server_file.c
>@@ -797,15 +797,18 @@ parse_range_spec(char *str, size_t size, struct range *r)
>       if ((start_str_len == 0) && (end_str_len == 0))
>               return (0);
> 
>-      if (end_str_len) {
>+      if (start_str_len == 0) {
>               r->end = strtonum(end_str, 0, LLONG_MAX, &errstr);
>-              if (errstr)
>+              if (errstr || r->end == 0)
>                       return (0);
> 
>-              if ((size_t)r->end >= size)
>-                      r->end = size - 1;
>-      } else
>+              if ((size_t)r->end > size)
>+                      r->start = 0;
>+              else
>+                      r->start = size - r->end;
>               r->end = size - 1;
>+              return (1);
>+      }
> 
>       if (start_str_len) {
>               r->start = strtonum(start_str, 0, LLONG_MAX, &errstr);
>@@ -814,11 +817,17 @@ parse_range_spec(char *str, size_t size, struct range *r)
> 
>               if ((size_t)r->start >= size)
>                       return (0);
>-      } else {
>-              r->start = size - r->end;
>-              r->end = size - 1;
>       }
> 
>+      if (end_str_len) {
>+              r->end = strtonum(end_str, 0, LLONG_MAX, &errstr);
>+              if (errstr)
>+                      return (0);
>+              if ((size_t)r->end >= size)
>+                      r->end = size - 1;
>+      } else
>+              r->end = size - 1;
>+
>       if (r->end < r->start)
>               return (0);

bump

Reply via email to