You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by fi...@hyperreal.org on 1998/08/10 06:16:17 UTC

cvs commit: apache-1.3/src/main http_config.c http_core.c http_protocol.c

fielding    98/08/09 21:16:16

  Modified:    src      CHANGES
               src/include http_config.h http_core.h httpd.h
               src/main http_config.c http_core.c http_protocol.c
  Log:
  Fixed request limit change to be more portable.  Removed the server_rec
  variables since compile-time control of the request-line, fieldsize, and
  number of fields is sufficient.  Added a per-dir configuration directive
  LimitRequestBody for setting a maximum request message body, with the
  default of 0 meaning no limit.
  
  Revision  Changes    Path
  1.1015    +3 -2      apache-1.3/src/CHANGES
  
  Index: CHANGES
  ===================================================================
  RCS file: /home/cvs/apache-1.3/src/CHANGES,v
  retrieving revision 1.1014
  retrieving revision 1.1015
  diff -u -r1.1014 -r1.1015
  --- CHANGES	1998/08/10 00:10:18	1.1014
  +++ CHANGES	1998/08/10 04:16:11	1.1015
  @@ -3,10 +3,11 @@
     *) SECURITY: Eliminate O(n^2) space DoS attacks (and other O(n^2)
        cpu time attacks) in header parsing.  [Dean Gaudet]
   
  -  *) SECURITY: Added default limits for various aspects of reading a
  +  *) SECURITY: Added compile-time limits for various aspects of reading a
        client request to avoid some simple denial of service attacks,
        including limits on maximum request-line size, number of header
  -     fields, size of any one header field, and size of the request
  +     fields, and size of any one header field.  Also added a configurable
  +     directive LimitRequestBody for limiting the size of the request
        message body.  [Roy Fielding]
   
     *) Make status module aware of DNS and logging states, even if
  
  
  
  1.93      +1 -1      apache-1.3/src/include/http_config.h
  
  Index: http_config.h
  ===================================================================
  RCS file: /home/cvs/apache-1.3/src/include/http_config.h,v
  retrieving revision 1.92
  retrieving revision 1.93
  diff -u -r1.92 -r1.93
  --- http_config.h	1998/08/09 06:37:15	1.92
  +++ http_config.h	1998/08/10 04:16:12	1.93
  @@ -275,7 +275,7 @@
    * handle it back-compatibly, or at least signal an error).
    */
   
  -#define MODULE_MAGIC_NUMBER 19980808
  +#define MODULE_MAGIC_NUMBER 19980809
   #define STANDARD_MODULE_STUFF MODULE_MAGIC_NUMBER, -1, __FILE__, NULL, NULL
   
   /* Generic accessors for other modules to get at their own module-specific
  
  
  
  1.47      +2 -0      apache-1.3/src/include/http_core.h
  
  Index: http_core.h
  ===================================================================
  RCS file: /home/cvs/apache-1.3/src/include/http_core.h,v
  retrieving revision 1.46
  retrieving revision 1.47
  diff -u -r1.46 -r1.47
  --- http_core.h	1998/08/06 19:23:43	1.46
  +++ http_core.h	1998/08/10 04:16:13	1.47
  @@ -131,6 +131,7 @@
   API_EXPORT(char *) ap_construct_url(pool *p, const char *uri, const request_rec *r);
   API_EXPORT(const char *) ap_get_server_name(const request_rec *r);
   API_EXPORT(unsigned) ap_get_server_port(const request_rec *r);
  +API_EXPORT(unsigned long) ap_get_limit_req_body(const request_rec *r);
   API_EXPORT(void) ap_custom_response(request_rec *r, int status, char *string);
   
   /* Authentication stuff.  This is one of the places where compatibility
  @@ -236,6 +237,7 @@
   #ifdef RLIMIT_NPROC
       struct rlimit *limit_nproc;
   #endif
  +    unsigned long limit_req_body;  /* limit on bytes in request msg body */
   
       /* logging options */
       enum { srv_sig_off, srv_sig_on, srv_sig_withmail } server_signature;
  
  
  
  1.233     +18 -27    apache-1.3/src/include/httpd.h
  
  Index: httpd.h
  ===================================================================
  RCS file: /home/cvs/apache-1.3/src/include/httpd.h,v
  retrieving revision 1.232
  retrieving revision 1.233
  diff -u -r1.232 -r1.233
  --- httpd.h	1998/08/09 16:57:28	1.232
  +++ httpd.h	1998/08/10 04:16:13	1.233
  @@ -369,6 +369,24 @@
   #define DEFAULT_LISTENBACKLOG 511
   #endif
   
  +/* Limits on the size of various request items.  These limits primarily
  + * exist to prevent simple denial-of-service attacks on a server based
  + * on misuse of the protocol.  The recommended values will depend on the
  + * nature of the server resources -- CGI scripts and database backends
  + * might require large values, but most servers could get by with much
  + * smaller limits than we use below.  The request message body size can
  + * be limited by the per-dir config directive LimitRequestBody.
  + */
  +#ifndef AP_LIMIT_REQUEST_LINE
  +#define AP_LIMIT_REQUEST_LINE 8192
  +#endif /* default limit on bytes in Request-Line (Method+URI+HTTP-version) */
  +#ifndef AP_LIMIT_REQUEST_FIELDS
  +#define AP_LIMIT_REQUEST_FIELDS 100
  +#endif /* default limit on number of request header fields */
  +#ifndef AP_LIMIT_REQUEST_FIELDSIZE
  +#define AP_LIMIT_REQUEST_FIELDSIZE 8192
  +#endif /* default limit on bytes in any one header field  */
  +
   /*
    * The below defines the base string of the Server: header. Additional
    * tokens can be added via the ap_add_version_component() API call.
  @@ -541,28 +559,6 @@
   #define REQUEST_CHUNKED_DECHUNK  2
   #define REQUEST_CHUNKED_PASS     3
   
  -/* Limits on the size of various request items.  These limits primarily
  - * exist to prevent simple denial-of-service attacks on a server based
  - * on misuse of the protocol.  The recommended values will depend on the
  - * nature of the server resources -- CGI scripts and database backends
  - * might require large values, but most servers could get by with much
  - * smaller limits than we use below.  These limits can be reset on a
  - * per-server basis using the LimitRequestLine, LimitRequestFields,
  - * LimitRequestFieldSize, and LimitRequestBody configuration directives.
  - */
  -#ifndef DEFAULT_LIMIT_REQUEST_LINE
  -#define DEFAULT_LIMIT_REQUEST_LINE 8192
  -#endif /* default limit on bytes in Request-Line (Method+URI+HTTP-version) */
  -#ifndef DEFAULT_LIMIT_REQUEST_FIELDS
  -#define DEFAULT_LIMIT_REQUEST_FIELDS 100
  -#endif /* default limit on number of header fields */
  -#ifndef DEFAULT_LIMIT_REQUEST_FIELDSIZE
  -#define DEFAULT_LIMIT_REQUEST_FIELDSIZE 8192
  -#endif /* default limit on bytes in any one field  */
  -#ifndef DEFAULT_LIMIT_REQUEST_BODY
  -#define DEFAULT_LIMIT_REQUEST_BODY 33554432ul
  -#endif /* default limit on bytes in request body   */
  -
   /* Things which may vary per file-lookup WITHIN a request ---
    * e.g., state of MIME config.  Basically, the name of an object, info
    * about the object, and any other info we may ahve which may need to
  @@ -846,11 +842,6 @@
   
       uid_t server_uid;        /* effective user id when calling exec wrapper */
       gid_t server_gid;        /* effective group id when calling exec wrapper */
  -
  -    unsigned int  limit_req_line;      /* limit on bytes in Request-Line   */
  -    unsigned int  limit_req_fields;    /* limit on number of header fields */
  -    unsigned long limit_req_fieldsize; /* limit on bytes in any one field  */
  -    unsigned long limit_req_body;      /* limit on bytes in request body   */
   };
   
   /* These are more like real hosts than virtual hosts */
  
  
  
  1.121     +0 -4      apache-1.3/src/main/http_config.c
  
  Index: http_config.c
  ===================================================================
  RCS file: /home/cvs/apache-1.3/src/main/http_config.c,v
  retrieving revision 1.120
  retrieving revision 1.121
  diff -u -r1.120 -r1.121
  --- http_config.c	1998/08/09 06:37:17	1.120
  +++ http_config.c	1998/08/10 04:16:14	1.121
  @@ -1409,10 +1409,6 @@
       s->loglevel = DEFAULT_LOGLEVEL;
       s->srm_confname = RESOURCE_CONFIG_FILE;
       s->access_confname = ACCESS_CONFIG_FILE;
  -    s->limit_req_line      = DEFAULT_LIMIT_REQUEST_LINE;
  -    s->limit_req_fields    = DEFAULT_LIMIT_REQUEST_FIELDS;
  -    s->limit_req_fieldsize = DEFAULT_LIMIT_REQUEST_FIELDSIZE;
  -    s->limit_req_body      = DEFAULT_LIMIT_REQUEST_BODY;
       s->timeout = DEFAULT_TIMEOUT;
       s->keep_alive_timeout = DEFAULT_KEEPALIVE_TIMEOUT;
       s->keep_alive_max = DEFAULT_KEEPALIVE;
  
  
  
  1.219     +26 -0     apache-1.3/src/main/http_core.c
  
  Index: http_core.c
  ===================================================================
  RCS file: /home/cvs/apache-1.3/src/main/http_core.c,v
  retrieving revision 1.218
  retrieving revision 1.219
  diff -u -r1.218 -r1.219
  --- http_core.c	1998/08/08 13:26:06	1.218
  +++ http_core.c	1998/08/10 04:16:14	1.219
  @@ -708,6 +708,14 @@
       return ap_psprintf(p, "%s://%s:%u%s", ap_http_method(r), host, port, uri);
   }
   
  +API_EXPORT(unsigned long) ap_get_limit_req_body(const request_rec *r)
  +{
  +    core_dir_config *d =
  +      (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module);
  +    
  +    return d->limit_req_body;
  +}
  +
   /*****************************************************************
    *
    * Commands... this module handles almost all of the NCSA httpd.conf
  @@ -2301,6 +2309,22 @@
       return NULL;
   }
   
  +static const char *set_limit_req_body(cmd_parms *cmd, core_dir_config *conf,
  +                                      char *arg) 
  +{
  +    const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
  +    if (err != NULL) {
  +        return err;
  +    }
  +
  +    /* WTF: If strtoul is not portable, then write a replacement.
  +     *      Instead we have an idiotic define in httpd.h that prevents
  +     *      it from being used even when it is available. Sheesh.
  +     */
  +    conf->limit_req_body = (unsigned long)strtol(arg, (char **)NULL, 10);
  +    return NULL;
  +}
  +
   /* Note --- ErrorDocument will now work from .htaccess files.  
    * The AllowOverride of Fileinfo allows webmasters to turn it off
    */
  @@ -2503,6 +2527,8 @@
   #endif
   { "ServerTokens", set_serv_tokens, NULL, RSRC_CONF, TAKE1,
     "Determine tokens displayed in the Server: header - Min(imal), OS or Full" },
  +{ "LimitRequestBody", set_limit_req_body, NULL, RSRC_CONF|ACCESS_CONF|OR_ALL,
  +  TAKE1, "Limit (in bytes) on maximum size of request message body" },
   { NULL },
   };
   
  
  
  
  1.236     +35 -33    apache-1.3/src/main/http_protocol.c
  
  Index: http_protocol.c
  ===================================================================
  RCS file: /home/cvs/apache-1.3/src/main/http_protocol.c,v
  retrieving revision 1.235
  retrieving revision 1.236
  diff -u -r1.235 -r1.236
  --- http_protocol.c	1998/08/09 17:36:26	1.235
  +++ http_protocol.c	1998/08/10 04:16:15	1.236
  @@ -626,17 +626,12 @@
   
   static int read_request_line(request_rec *r)
   {
  -    char *l;
  -    const char *ll;
  +    char l[AP_LIMIT_REQUEST_LINE + 2];  /* getline needs two extra for \n\0 */
  +    const char *ll = l;
       const char *uri;
       conn_rec *conn = r->connection;
       int major = 1, minor = 0;   /* Assume HTTP/1.0 if non-"HTTP" protocol */
       int len;
  -    pool *tmp;
  -
  -    tmp = ap_make_sub_pool(r->pool);
  -    l = ap_palloc(tmp, r->server->limit_req_line);
  -    ll = l;
   
       /* Read past empty lines until we get a real request line,
        * a read error, the connection closes (EOF), or we timeout.
  @@ -653,10 +648,9 @@
        * have to block during a read.
        */
       ap_bsetflag(conn->client, B_SAFEREAD, 1);
  -    while ((len = getline(l, r->server->limit_req_line, conn->client, 0)) <= 0) {
  +    while ((len = getline(l, sizeof(l), conn->client, 0)) <= 0) {
           if ((len < 0) || ap_bgetflag(conn->client, B_EOF)) {
               ap_bsetflag(conn->client, B_SAFEREAD, 0);
  -	    ap_destroy_pool(tmp);
               return 0;
           }
       }
  @@ -696,11 +690,14 @@
   
       ap_parse_uri(r, uri);
   
  -    if (len >= r->server->limit_req_line - 1) {
  +    /* getline returns (size of max buffer - 1) if it fills up the
  +     * buffer before finding the end-of-line.  This is only going to
  +     * happen if it exceeds the configured limit for a request-line.
  +     */
  +    if (len >= sizeof(l) - 1) {
           r->status    = HTTP_REQUEST_URI_TOO_LARGE;
           r->proto_num = HTTP_VERSION(1,0);
           r->protocol  = ap_pstrdup(r->pool, "HTTP/1.0");
  -	ap_destroy_pool(tmp);
           return 0;
       }
   
  @@ -713,7 +710,6 @@
       else
   	r->proto_num = HTTP_VERSION(1,0);
   
  -    ap_destroy_pool(tmp);
       return 1;
   }
   
  @@ -742,20 +738,20 @@
   /* XXX: could use ap_overlap_tables here... which generalizes this code */
   static void get_mime_headers(request_rec *r)
   {
  +    char field[AP_LIMIT_REQUEST_FIELDSIZE + 2];  /* getline needs two extra */
       conn_rec *c = r->connection;
  -    char *copy;
  -    int len;
       char *value;
  -    unsigned int fields_read = 0;
  -    char *field;
  -    array_header *arr;
  +    char *copy;
       pool *tmp;
  +    array_header *arr;
       mime_key *new_key;
  -    unsigned order;
       mime_key *first;
       mime_key *last;
       mime_key *end;
       char *strp;
  +    unsigned order;
  +    int len;
  +    unsigned int fields_read = 0;
   
       /* The array will store the headers in a way that we can merge them
        * later in O(n*lg(n))... rather than deal with various O(n^2)
  @@ -765,8 +761,6 @@
       arr = ap_make_array(tmp, 50, sizeof(mime_key));
       order = 0;
   
  -    field = ap_palloc(tmp, r->server->limit_req_fieldsize);
  -
       /* If headers_in is non-empty (i.e. we're parsing a trailer) then
        * we have to merge.  Have I mentioned that I think this is a lame part
        * of the HTTP standard?  Anyhow, we'll cheat, and just pre-seed our
  @@ -795,22 +789,25 @@
        * Read header lines until we get the empty separator line, a read error,
        * the connection closes (EOF), reach the server limit, or we timeout.
        */
  -    while ((len = getline(field, r->server->limit_req_fieldsize,
  -			c->client, 1)) > 0) {
  +    while ((len = getline(field, sizeof(field), c->client, 1)) > 0) {
   
  -        if (++fields_read > r->server->limit_req_fields) {
  +        if (++fields_read > AP_LIMIT_REQUEST_FIELDS) {
               r->status = HTTP_BAD_REQUEST;
               ap_table_setn(r->notes, "error-notes",
                   "Number of request header fields exceeds server limit.<P>\n");
  -	    ap_destroy_pool(tmp);
  +            ap_destroy_pool(tmp);
               return;
           }
  -        if (len >= r->server->limit_req_fieldsize) { 
  +        /* getline returns (size of max buffer - 1) if it fills up the
  +         * buffer before finding the end-of-line.  This is only going to
  +         * happen if it exceeds the configured limit for a field size.
  +         */
  +        if (len >= sizeof(field) - 1) { 
               r->status = HTTP_BAD_REQUEST;
               ap_table_setn(r->notes, "error-notes", ap_pstrcat(r->pool,
                   "Size of a request header field exceeds server limit.<P>\n"
                   "<PRE>\n", field, "</PRE>\n", NULL));
  -	    ap_destroy_pool(tmp);
  +            ap_destroy_pool(tmp);
               return;
           }
           copy = ap_palloc(r->pool, len + 1);
  @@ -821,7 +818,7 @@
               ap_table_setn(r->notes, "error-notes", ap_pstrcat(r->pool,
                   "Request header field is missing colon separator.<P>\n"
                   "<PRE>\n", copy, "</PRE>\n", NULL));
  -	    ap_destroy_pool(tmp);
  +            ap_destroy_pool(tmp);
               return;
           }
   
  @@ -830,7 +827,7 @@
           while (*value == ' ' || *value == '\t')
               ++value;            /* Skip to start of value   */
   
  -	/* XXX: should strip trailing whitespace as well */
  +        /* XXX: should strip trailing whitespace as well */
   
   	/* Notice that key and val are actually in r->pool... this is a slight
   	 * optimization to handle the normal case, where we don't have twits
  @@ -1495,6 +1492,7 @@
   {
       const char *tenc = ap_table_get(r->headers_in, "Transfer-Encoding");
       const char *lenp = ap_table_get(r->headers_in, "Content-Length");
  +    unsigned long max_body;
   
       r->read_body = read_policy;
       r->read_chunked = 0;
  @@ -1534,10 +1532,12 @@
                       "%s with body is not allowed for %s", r->method, r->uri);
           return HTTP_REQUEST_ENTITY_TOO_LARGE;
       }
  -    if (r->remaining > r->server->limit_req_body) {
  +
  +    max_body = ap_get_limit_req_body(r);
  +    if (max_body && (r->remaining > max_body)) {
           ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
             "Request content-length of %s is larger than the configured "
  -          "server limit of %lu", lenp, r->server->limit_req_body);
  +          "limit of %lu", lenp, max_body);
           return HTTP_REQUEST_ENTITY_TOO_LARGE;
       }
   
  @@ -1601,6 +1601,7 @@
       int c;
       long len_read, len_to_read;
       long chunk_start = 0;
  +    unsigned long max_body;
   
       if (!r->read_chunked) {     /* Content-length read */
           len_to_read = (r->remaining > bufsiz) ? bufsiz : r->remaining;
  @@ -1630,10 +1631,11 @@
        * caller read pass, since the limit exists just to stop infinite
        * length requests and nobody cares if it goes over by one buffer.
        */
  -    if (r->read_length > r->server->limit_req_body) {
  +    max_body = ap_get_limit_req_body(r);
  +    if (max_body && (r->read_length > max_body)) {
           ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
  -          "Chunked request body is larger than the configured "
  -          "server limit of %lu", r->server->limit_req_body);
  +            "Chunked request body is larger than the configured limit of %lu",
  +            max_body);
           r->connection->keepalive = -1;
           return -1;
       }
  
  
  

Re: cvs commit: apache-1.3/src/main http_config.c http_core.c http_protocol.c

Posted by Randy Terbush <ra...@Covalent.NET>.
Rodent of Unusual Size <Ke...@Golux.Com> writes:
> fielding@hyperreal.org wrote:
> > 
> >   Log:
> >   Fixed request limit change to be more portable.  Removed the server_rec
> >   variables since compile-time control of the request-line, fieldsize, and
> >   number of fields is sufficient.
> 
> No time to really comment in detail, but I disagree with the above in
> principle.  We getting a *lot* of people using prepackaged binaries
> (RedHat, FreeBSD, ...), and making them recompile seems unfriendly.
> I'd much rather see run-time directives available for these.
> 
> Just MHO.

I would agree with this.

-Randy


Re: cvs commit: apache-1.3/src/main http_config.c http_core.c http_protocol.c

Posted by Rodent of Unusual Size <Ke...@Golux.Com>.
fielding@hyperreal.org wrote:
> 
>   Log:
>   Fixed request limit change to be more portable.  Removed the server_rec
>   variables since compile-time control of the request-line, fieldsize, and
>   number of fields is sufficient.

No time to really comment in detail, but I disagree with the above in
principle.  We getting a *lot* of people using prepackaged binaries
(RedHat, FreeBSD, ...), and making them recompile seems unfriendly.
I'd much rather see run-time directives available for these.

Just MHO.

#ken	P-)}

Ken Coar                    <http://Web.Golux.Com/coar/>
Apache Group member         <http://www.apache.org/>
"Apache Server for Dummies" <http://Web.Golux.Com/coar/ASFD/>