fielding    98/08/08 23:37:19

  Modified:    src      CHANGES
               src/include http_config.h httpd.h
               src/main http_config.c http_protocol.c
  Log:
  Added default 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
  message body.
  
  Bumped MMN for addition of limit_req_line, limit_req_fields,
  limit_req_fieldsize and limit_req_body variables to server_rec.
  
  Revision  Changes    Path
  1.1012    +6 -0      apache-1.3/src/CHANGES
  
  Index: CHANGES
  ===================================================================
  RCS file: /home/cvs/apache-1.3/src/CHANGES,v
  retrieving revision 1.1011
  retrieving revision 1.1012
  diff -u -r1.1011 -r1.1012
  --- CHANGES   1998/08/08 13:26:04     1.1011
  +++ CHANGES   1998/08/09 06:37:12     1.1012
  @@ -1,5 +1,11 @@
   Changes with Apache 1.3.2
   
  +  *) SECURITY: Added default 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
  +     message body.  [Roy Fielding]
  +
     *) Make status module aware of DNS and logging states, even if
        STATUS not defined.  [Jim Jagielski]
   
  
  
  
  1.92      +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.91
  retrieving revision 1.92
  diff -u -r1.91 -r1.92
  --- http_config.h     1998/08/06 17:30:23     1.91
  +++ http_config.h     1998/08/09 06:37:15     1.92
  @@ -275,7 +275,7 @@
    * handle it back-compatibly, or at least signal an error).
    */
   
  -#define MODULE_MAGIC_NUMBER 19980806
  +#define MODULE_MAGIC_NUMBER 19980808
   #define STANDARD_MODULE_STUFF MODULE_MAGIC_NUMBER, -1, __FILE__, NULL, NULL
   
   /* Generic accessors for other modules to get at their own module-specific
  
  
  
  1.231     +29 -2     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.230
  retrieving revision 1.231
  diff -u -r1.230 -r1.231
  --- httpd.h   1998/08/06 19:13:52     1.230
  +++ httpd.h   1998/08/09 06:37:16     1.231
  @@ -541,6 +541,28 @@
   #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 8190
  +#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 8190
  +#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
  @@ -821,9 +843,14 @@
   
       array_header *names;     /* Normal names for ServerAlias servers */
       array_header *wild_names;        /* Wildcarded names for ServerAlias 
servers */
  +
  +    uid_t server_uid;        /* effective user id when calling exec wrapper 
*/
  +    gid_t server_gid;        /* effective group id when calling exec wrapper 
*/
   
  -    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.120     +4 -0      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.119
  retrieving revision 1.120
  diff -u -r1.119 -r1.120
  --- http_config.c     1998/08/06 17:30:27     1.119
  +++ http_config.c     1998/08/09 06:37:17     1.120
  @@ -1409,6 +1409,10 @@
       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.230     +46 -19    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.229
  retrieving revision 1.230
  diff -u -r1.229 -r1.230
  --- http_protocol.c   1998/08/06 17:30:30     1.229
  +++ http_protocol.c   1998/08/09 06:37:17     1.230
  @@ -626,7 +626,7 @@
   
   static int read_request_line(request_rec *r)
   {
  -    char l[HUGE_STRING_LEN];
  +    char l[r->server->limit_req_line + 2];
       const char *ll = l, *uri;
       conn_rec *conn = r->connection;
       int major = 1, minor = 0;   /* Assume HTTP/1.0 if non-"HTTP" protocol */
  @@ -647,7 +647,7 @@
        * have to block during a read.
        */
       ap_bsetflag(conn->client, B_SAFEREAD, 1);
  -    while ((len = getline(l, HUGE_STRING_LEN, 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);
               return 0;
  @@ -689,7 +689,7 @@
   
       ap_parse_uri(r, uri);
   
  -    if (len == (HUGE_STRING_LEN - 1)) {
  +    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");
  @@ -711,20 +711,38 @@
   static void get_mime_headers(request_rec *r)
   {
       conn_rec *c = r->connection;
  +    char *value, *copy;
       int len;
  -    char *value;
  -    char field[MAX_STRING_LEN];
  +    unsigned int fields_read = 0;
  +    char field[r->server->limit_req_fieldsize + 2];
   
       /*
        * Read header lines until we get the empty separator line, a read error,
  -     * the connection closes (EOF), or we timeout.
  +     * the connection closes (EOF), reach the server limit, or we timeout.
        */
  -    while ((len = getline(field, MAX_STRING_LEN, c->client, 1)) > 0) {
  -        char *copy = ap_palloc(r->pool, len + 1);
  +    while ((len = getline(field, sizeof(field), c->client, 1)) > 0) {
  +
  +        if (++fields_read > r->server->limit_req_fields) {
  +            r->status = HTTP_BAD_REQUEST;
  +            ap_table_setn(r->notes, "error-notes",
  +                "Number of request header fields exceeds server 
limit.<P>\n");
  +            return;
  +        }
  +        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));
  +            return;
  +        }
  +        copy = ap_palloc(r->pool, len + 1);
           memcpy(copy, field, len + 1);
   
           if (!(value = strchr(copy, ':'))) {     /* Find the colon separator 
*/
               r->status = HTTP_BAD_REQUEST;       /* or abort the bad request 
*/
  +            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));
               return;
           }
   
  @@ -736,16 +754,6 @@
        /* XXX: should strip trailing whitespace as well */
   
           ap_table_mergen(r->headers_in, copy, value);
  -
  -     /* the header was too long; at the least we should skip extra data */
  -     if (len >= MAX_STRING_LEN - 1) { 
  -         while ((len = getline(field, MAX_STRING_LEN, c->client, 1))
  -                 >= MAX_STRING_LEN - 1) {
  -             /* soak up the extra data */
  -         }
  -         if (len <= 0) /* time to exit the larger loop as well */
  -             break;
  -     }
       }
   }
   
  @@ -1395,6 +1403,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) {
  +        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);
  +        return HTTP_REQUEST_ENTITY_TOO_LARGE;
  +    }
   
       return OK;
   }
  @@ -1480,6 +1494,19 @@
       if (bufsiz <= 0)
           return -1;              /* Cannot read chunked with a small buffer */
   
  +    /* Check to see if we have already read too much request data.
  +     * For efficiency reasons, we only check this at the top of each
  +     * 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) {
  +        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);
  +        r->connection->keepalive = -1;
  +        return -1;
  +    }
  +
       if (r->remaining == 0) {    /* Start of new chunk */
   
           chunk_start = getline(buffer, bufsiz, r->connection->client, 0);
  @@ -1593,7 +1620,7 @@
    * Since we return an error status if the request is malformed, this
    * routine should be called at the beginning of a no-body handler, e.g.,
    *
  - *    if ((retval = discard_request_body(r)) != OK)
  + *    if ((retval = ap_discard_request_body(r)) != OK)
    *        return retval;
    */
   API_EXPORT(int) ap_discard_request_body(request_rec *r)
  
  
  

Reply via email to