From: William A. Rowe Jr Date: Fri, 9 Aug 2002 17:00:44 +0000 (+0000) Subject: Security rollup for 2.0.40 release. Tag and roll baby. X-Git-Tag: 2.0.40~2 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e85db78eaae29d8a9fef539b7e883139d6f5c1dc;p=apache Security rollup for 2.0.40 release. Tag and roll baby. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@96327 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/CHANGES b/CHANGES index 0992e9686a..5ad91e9183 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,29 @@ Changes with Apache 2.0.40 + *) SECURITY: [CAN-2002-0661] Close a very significant security hole that + applies only to the Win32, OS2 and Netware platforms. Unix was not + affected, Cygwin may be affected. Certain URIs will bypass security + and allow users to invoke or access any file depending on the system + configuration. Without upgrading, a single .conf change will close + the vulnerability. Add the following directive in the global server + httpd.conf context before any other Alias or Redirect directives; + RedirectMatch 400 "\\\.\." + Reported by Auriemma Luigi . + [Brad Nicholes] + + *) SECURITY: Close a path-revealing exposure in multiview type + map negotiation (such as the default error documents) where the + module would report the full path of the typemapped .var file when + multiple documents or no documents could be served based on the mime + negotiation. Reported by Auriemma Luigi . + [CAN-2002-0654] [William Rowe] + + *) SECURITY: Close a path-revealing exposure in cgi/cgid when we + fail to invoke a script. The modules would report "couldn't create + child process /path-to-script/script.pl" revealing the full path + of the script. Reported by Jim Race . + [CAN-2002-0654] [Bill Stoddard] + *) Set aside the apr-iconv and apr_xlate() features for the Win32 build of 2.0.40 so development can be completed. A patch, from diff --git a/modules/mappers/mod_negotiation.c b/modules/mappers/mod_negotiation.c index 61b30e51a1..97189aa355 100644 --- a/modules/mappers/mod_negotiation.c +++ b/modules/mappers/mod_negotiation.c @@ -984,7 +984,7 @@ static int read_type_map(apr_file_t **map, negotiation_state *neg, request_rec * break; } mime_info.bytes = len; - mime_info.file_name = rr->filename; + mime_info.file_name = apr_filename_of_pathname(rr->filename); } } else { @@ -1048,15 +1048,15 @@ static int read_types_multi(negotiation_state *neg) clean_var_rec(&mime_info); - if (!(filp = strrchr(r->filename, '/'))) { - return DECLINED; /* Weird... */ + if (r->proxyreq || !r->filename + || !ap_os_is_path_absolute(neg->pool, r->filename)) { + return DECLINED; } - /* XXX this should be more general, and quit using 'specials' */ - if (strncmp(r->filename, "proxy:", 6) == 0) { + /* Only absolute paths here */ + if (!(filp = strrchr(r->filename, '/'))) { return DECLINED; } - ++filp; prefix_len = strlen(filp); @@ -2685,8 +2685,15 @@ static int do_negotiation(request_rec *r, negotiation_state *neg, * non-neighboring variant. We can have a non-neighboring * variant when processing a type map. */ - if (ap_strchr_c(variant->file_name, '/')) + if (ap_strchr(variant->file_name, '/')) + neg->is_transparent = 0; + + /* We can't be transparent, because of the behavior + * of variant typemap bodies. + */ + if (variant->body) { neg->is_transparent = 0; + } } } @@ -2818,9 +2825,6 @@ static int handle_map_file(request_rec *r) apr_bucket *e; ap_allow_standard_methods(r, REPLACE_ALLOW, M_GET, M_OPTIONS, M_POST, -1); - if ((res = ap_discard_request_body(r)) != OK) { - return res; - } /*if (r->method_number == M_OPTIONS) { * return ap_send_http_options(r); *} @@ -2841,6 +2845,9 @@ static int handle_map_file(request_rec *r) return res; } + if ((res = ap_discard_request_body(r)) != OK) { + return res; + } bb = apr_brigade_create(r->pool, c->bucket_alloc); e = apr_bucket_file_create(map, best->body, (apr_size_t)best->bytes, r->pool, diff --git a/server/util.c b/server/util.c index c86e37cdbf..f0aabab112 100644 --- a/server/util.c +++ b/server/util.c @@ -115,6 +115,16 @@ */ #define TEST_CHAR(c, f) (test_char_table[(unsigned)(c)] & (f)) +/* Win32/NetWare/OS2 need to check for both forward and back slashes + * in ap_getparents() and ap_escape_url. + */ +#ifdef CASE_BLIND_FILESYSTEM +#define IS_SLASH(s) ((s == '/') || (s == '\\')) +#else +#define IS_SLASH(s) (s == '/') +#endif + + /* * Examine a field value (such as a media-/content-type) string and return * it sans any parameters; e.g., strip off any ';charset=foo' and the like. @@ -485,7 +495,7 @@ AP_DECLARE(void) ap_getparents(char *name) } l = w = first_dot = next - name; while (name[l] != '\0') { - if (name[l] == '.' && name[l + 1] == '/' && (l == 0 || name[l - 1] == '/')) + if (name[l] == '.' && IS_SLASH(name[l + 1]) && (l == 0 || IS_SLASH(name[l - 1]))) l += 2; else name[w++] = name[l++]; @@ -494,7 +504,7 @@ AP_DECLARE(void) ap_getparents(char *name) /* b) remove trailing . path, segment */ if (w == 1 && name[0] == '.') w--; - else if (w > 1 && name[w - 1] == '.' && name[w - 2] == '/') + else if (w > 1 && name[w - 1] == '.' && IS_SLASH(name[w - 2])) w--; name[w] = '\0'; @@ -502,13 +512,13 @@ AP_DECLARE(void) ap_getparents(char *name) l = first_dot; while (name[l] != '\0') { - if (name[l] == '.' && name[l + 1] == '.' && name[l + 2] == '/' && - (l == 0 || name[l - 1] == '/')) { + if (name[l] == '.' && name[l + 1] == '.' && IS_SLASH(name[l + 2]) && + (l == 0 || IS_SLASH(name[l - 1]))) { register int m = l + 3, n; l = l - 2; if (l >= 0) { - while (l >= 0 && name[l] != '/') + while (l >= 0 && !IS_SLASH(name[l])) l--; l++; } @@ -525,10 +535,10 @@ AP_DECLARE(void) ap_getparents(char *name) /* d) remove trailing xx/.. segment. */ if (l == 2 && name[0] == '.' && name[1] == '.') name[0] = '\0'; - else if (l > 2 && name[l - 1] == '.' && name[l - 2] == '.' && name[l - 3] == '/') { + else if (l > 2 && name[l - 1] == '.' && name[l - 2] == '.' && IS_SLASH(name[l - 3])) { l = l - 4; if (l >= 0) { - while (l >= 0 && name[l] != '/') + while (l >= 0 && !IS_SLASH(name[l])) l--; l++; } @@ -1547,7 +1557,7 @@ AP_DECLARE(int) ap_unescape_url(char *url) else { *x = x2c(y + 1); y += 2; - if (*x == '/' || *x == '\0') + if (IS_SLASH(*x) || *x == '\0') badpath = 1; } }