On 26.05.2015 19:21, Markus Koschany wrote: > On 26.05.2015 17:23, Raphael Hertzog wrote: >> Hello dear maintainer(s), >> >> the Debian LTS team would like to fix the security issues which are >> currently open in the Squeeze version of libapache-mod-jk: >> https://security-tracker.debian.org/tracker/CVE-2014-8111 >> >> Would you like to take care of this yourself? We are still understaffed so >> any help is always highly appreciated. > > Yes, I will take care of that. Uploads for Wheezy and Jessie are still > pending. Help with testing is appreciated. For interested users of > libapache2-mod-jk, you can already find updated amd64 packages for > Wheezy and Jessie here: > > wheezy: https://people.debian.org/~carnil/tmp/libapache-mod-jk/wheezy/ > jessie: https://people.debian.org/~carnil/tmp/libapache-mod-jk/jessie/ >
Hi, please find attached the debdiff and fix for libapache-mod-jk in squeeze. Feedback and testing are appreciated. Regards, Markus
diff -Nru libapache-mod-jk-1.2.30/debian/changelog libapache-mod-jk-1.2.30/debian/changelog --- libapache-mod-jk-1.2.30/debian/changelog 2011-02-15 06:17:24.000000000 +0100 +++ libapache-mod-jk-1.2.30/debian/changelog 2015-05-30 14:54:26.000000000 +0200 @@ -1,3 +1,20 @@ +libapache-mod-jk (1:1.2.30-1squeeze2) squeeze-lts; urgency=high + + * Team upload. + * Add CVE-2014-8111.patch. (Closes: #783233) + It was discovered that a JkUnmount rule for a subtree of a previous JkMount + rule could be ignored. This could allow a remote attacker to potentially + access a private artifact in a tree that would otherwise not be accessible + to them. + - Add option to control handling of multiple adjacent slashes in mount and + unmount. New default is collapsing the slashes only in unmount. Before + this change, adjacent slashes were never collapsed, so most mounts and + unmounts didn't match for URLs with multiple adjacent slashes. + - Configuration is done via new JkOption for Apache (values + "CollapseSlashesAll", "CollapseSlashesNone" or "CollapseSlashesUnmount"). + + -- Markus Koschany <a...@gambaru.de> Sat, 30 May 2015 14:54:17 +0200 + libapache-mod-jk (1:1.2.30-1squeeze1) stable; urgency=medium * Team upload. diff -Nru libapache-mod-jk-1.2.30/debian/patches/CVE-2014-8111.patch libapache-mod-jk-1.2.30/debian/patches/CVE-2014-8111.patch --- libapache-mod-jk-1.2.30/debian/patches/CVE-2014-8111.patch 1970-01-01 01:00:00.000000000 +0100 +++ libapache-mod-jk-1.2.30/debian/patches/CVE-2014-8111.patch 2015-05-30 14:53:23.000000000 +0200 @@ -0,0 +1,418 @@ +From: Markus Koschany <a...@gambaru.de> +Date: Sat, 30 May 2015 00:41:23 +0200 +Subject: CVE-2014-8111 + +It was discovered that a JkUnmount rule for a subtree of a previous JkMount +rule could be ignored. This could allow a remote attacker to potentially access +a private artifact in a tree that would otherwise not be accessible to them. + +Forwarded: https://svn.apache.org/viewvc?view=revision&revision=r1647017 +--- + native/apache-1.3/mod_jk.c | 24 +++++++++++++++++++++-- + native/apache-2.0/mod_jk.c | 24 +++++++++++++++++++++-- + native/common/jk_global.h | 7 ++++++- + native/common/jk_uri_worker_map.c | 41 +++++++++++++++++++++++++-------------- + native/common/jk_uri_worker_map.h | 7 +++++++ + native/common/jk_util.c | 19 ++++++++++++++++++ + native/common/jk_util.h | 2 ++ + native/iis/jk_isapi_plugin.c | 27 ++++++++++++++++++++++++++ + 8 files changed, 131 insertions(+), 20 deletions(-) + +diff --git a/native/apache-1.3/mod_jk.c b/native/apache-1.3/mod_jk.c +index 228161e..698d248 100644 +--- a/native/apache-1.3/mod_jk.c ++++ b/native/apache-1.3/mod_jk.c +@@ -1930,9 +1930,11 @@ const char *jk_set_options(cmd_parms * cmd, void *dummy, const char *line) + + mask = 0; + +- if (action == '-' && !strncasecmp(w, "ForwardURI", strlen("ForwardURI"))) ++ if (action == '-' && ++ (!strncasecmp(w, "ForwardURI", strlen("ForwardURI")) || ++ !strncasecmp(w, "CollapseSlashes", strlen("CollapseSlashes")))) + return ap_pstrcat(cmd->pool, "JkOptions: Illegal option '-", w, +- "': ForwardURI* options can not be disabled", NULL); ++ "': option can not be disabled", NULL); + + if (!strcasecmp(w, "ForwardURICompat")) { + opt = JK_OPT_FWDURICOMPAT; +@@ -1950,6 +1952,18 @@ const char *jk_set_options(cmd_parms * cmd, void *dummy, const char *line) + opt = JK_OPT_FWDURIPROXY; + mask = JK_OPT_FWDURIMASK; + } ++ else if (!strcasecmp(w, "CollapseSlashesAll")) { ++ opt = JK_OPT_COLLAPSEALL; ++ mask = JK_OPT_COLLAPSEMASK; ++ } ++ else if (!strcasecmp(w, "CollapseSlashesNone")) { ++ opt = JK_OPT_COLLAPSENONE; ++ mask = JK_OPT_COLLAPSEMASK; ++ } ++ else if (!strcasecmp(w, "CollapseSlashesUnmount")) { ++ opt = JK_OPT_COLLAPSEUNMOUNT; ++ mask = JK_OPT_COLLAPSEMASK; ++ } + else if (!strcasecmp(w, "ForwardDirectories")) { + opt = JK_OPT_FWDDIRS; + } +@@ -2580,6 +2594,10 @@ static void *merge_jk_config(ap_pool * p, void *basev, void *overridesv) + overrides->options |= (base->options & ~base->exclude_options) & ~JK_OPT_FWDURIMASK; + else + overrides->options |= (base->options & ~base->exclude_options); ++ if (overrides->options & JK_OPT_COLLAPSEMASK) ++ overrides->options |= (base->options & ~base->exclude_options) & ~JK_OPT_COLLAPSEMASK; ++ else ++ overrides->options |= (base->options & ~base->exclude_options); + + if (base->envvars) { + if (overrides->envvars && overrides->envvars_has_own) { +@@ -2799,6 +2817,8 @@ static void jk_init(server_rec * s, ap_pool * p) + uri_worker_map_switch(sconf->uw_map, sconf->log); + uri_worker_map_load(sconf->uw_map, sconf->log); + } ++ if (conf->options & JK_OPT_COLLAPSEMASK) ++ sconf->uw_map->collapse_slashes = conf->options & JK_OPT_COLLAPSEMASK; + } + else { + if (sconf->mountcopy == JK_TRUE) { +diff --git a/native/apache-2.0/mod_jk.c b/native/apache-2.0/mod_jk.c +index e1f5e0c..871692f 100644 +--- a/native/apache-2.0/mod_jk.c ++++ b/native/apache-2.0/mod_jk.c +@@ -2028,9 +2028,11 @@ static const char *jk_set_options(cmd_parms * cmd, void *dummy, + + mask = 0; + +- if (action == '-' && !strncasecmp(w, "ForwardURI", strlen("ForwardURI"))) ++ if (action == '-' && ++ (!strncasecmp(w, "ForwardURI", strlen("ForwardURI")) || ++ !strncasecmp(w, "CollapseSlashes", strlen("CollapseSlashes")))) + return apr_pstrcat(cmd->pool, "JkOptions: Illegal option '-", w, +- "': ForwardURI* options can not be disabled", NULL); ++ "': option can not be disabled", NULL); + + if (!strcasecmp(w, "ForwardURICompat")) { + opt = JK_OPT_FWDURICOMPAT; +@@ -2048,6 +2050,18 @@ static const char *jk_set_options(cmd_parms * cmd, void *dummy, + opt = JK_OPT_FWDURIPROXY; + mask = JK_OPT_FWDURIMASK; + } ++ else if (!strcasecmp(w, "CollapseSlashesAll")) { ++ opt = JK_OPT_COLLAPSEALL; ++ mask = JK_OPT_COLLAPSEMASK; ++ } ++ else if (!strcasecmp(w, "CollapseSlashesNone")) { ++ opt = JK_OPT_COLLAPSENONE; ++ mask = JK_OPT_COLLAPSEMASK; ++ } ++ else if (!strcasecmp(w, "CollapseSlashesUnmount")) { ++ opt = JK_OPT_COLLAPSEUNMOUNT; ++ mask = JK_OPT_COLLAPSEMASK; ++ } + else if (!strcasecmp(w, "ForwardDirectories")) { + opt = JK_OPT_FWDDIRS; + } +@@ -2812,6 +2826,10 @@ static void *merge_jk_config(apr_pool_t * p, void *basev, void *overridesv) + overrides->options |= (base->options & ~base->exclude_options) & ~JK_OPT_FWDURIMASK; + else + overrides->options |= (base->options & ~base->exclude_options); ++ if (overrides->options & JK_OPT_COLLAPSEMASK) ++ overrides->options |= (base->options & ~base->exclude_options) & ~JK_OPT_COLLAPSEMASK; ++ else ++ overrides->options |= (base->options & ~base->exclude_options); + + if (base->envvars) { + if (overrides->envvars && overrides->envvars_has_own) { +@@ -3287,6 +3305,8 @@ static int jk_post_config(apr_pool_t * pconf, + uri_worker_map_switch(sconf->uw_map, sconf->log); + uri_worker_map_load(sconf->uw_map, sconf->log); + } ++ if (conf->options & JK_OPT_COLLAPSEMASK) ++ sconf->uw_map->collapse_slashes = conf->options & JK_OPT_COLLAPSEMASK; + } + else { + if (sconf->mountcopy == JK_TRUE) { +diff --git a/native/common/jk_global.h b/native/common/jk_global.h +index 0749a56..23105e7 100644 +--- a/native/common/jk_global.h ++++ b/native/common/jk_global.h +@@ -246,6 +246,11 @@ extern "C" + + #define JK_OPT_FWDURIMASK 0x0007 + ++#define JK_OPT_COLLAPSEMASK 0x7000 ++#define JK_OPT_COLLAPSEALL 0x1000 ++#define JK_OPT_COLLAPSENONE 0x2000 ++#define JK_OPT_COLLAPSEUNMOUNT 0x4000 ++ + #define JK_OPT_FWDURICOMPAT 0x0001 + #define JK_OPT_FWDURICOMPATUNPARSED 0x0002 + #define JK_OPT_FWDURIESCAPED 0x0003 +@@ -263,7 +268,7 @@ extern "C" + #define JK_OPT_FWDKEYSIZE 0x0200 + #define JK_OPT_REJECTUNSAFE 0x0400 + +-#define JK_OPT_DEFAULT (JK_OPT_FWDURIDEFAULT | JK_OPT_FWDKEYSIZE) ++#define JK_OPT_DEFAULT (JK_OPT_FWDURIDEFAULT | JK_OPT_FWDKEYSIZE | JK_OPT_COLLAPSEUNMOUNT) + + /* Check for EBCDIC systems */ + +diff --git a/native/common/jk_uri_worker_map.c b/native/common/jk_uri_worker_map.c +index d652f76..cbed24c 100644 +--- a/native/common/jk_uri_worker_map.c ++++ b/native/common/jk_uri_worker_map.c +@@ -169,9 +169,9 @@ static void uri_worker_map_dump(jk_uri_worker_map_t *uw_map, + uri_worker_record_t *uwr = NULL; + char buf[32]; + jk_log(l, JK_LOG_DEBUG, "uri map dump %s: index=%d file='%s' reject_unsafe=%d " +- "reload=%d modified=%d checked=%d", ++ "collapse_slashes=%d reload=%d modified=%d checked=%d", + reason, uw_map->index, STRNULL_FOR_NULL(uw_map->fname), uw_map->reject_unsafe, +- uw_map->reload, uw_map->modified, uw_map->checked); ++ uw_map->collapse_slashes, uw_map->reload, uw_map->modified, uw_map->checked); + for(i=0;i<=1;i++) { + jk_log(l, JK_LOG_DEBUG, "generation %d: size=%d nosize=%d capacity=%d", + i, uw_map->size[i], uw_map->nosize[i], uw_map->capacity[i], uw_map->maps[i]); +@@ -231,6 +231,7 @@ int uri_worker_map_alloc(jk_uri_worker_map_t **uw_map_p, + uw_map->index = 0; + uw_map->fname = NULL; + uw_map->reject_unsafe = 0; ++ uw_map->collapse_slashes = JK_COLLAPSE_DEFAULT; + uw_map->reload = JK_URIMAP_DEF_RELOAD; + uw_map->modified = 0; + uw_map->checked = 0; +@@ -667,32 +668,28 @@ int uri_worker_map_add(jk_uri_worker_map_t *uw_map, + else if (!strncmp(param, JK_UWMAP_EXTENSION_ACTIVE, strlen(JK_UWMAP_EXTENSION_ACTIVE))) { + if (uwr->extensions.active) + jk_log(l, JK_LOG_WARNING, +- "extension '%s' in uri worker map only allowed once", +- JK_UWMAP_EXTENSION_ACTIVE); ++ "rule extension '" JK_UWMAP_EXTENSION_ACTIVE "' only allowed once"); + else + uwr->extensions.active = param + strlen(JK_UWMAP_EXTENSION_ACTIVE); + } + else if (!strncmp(param, JK_UWMAP_EXTENSION_DISABLED, strlen(JK_UWMAP_EXTENSION_DISABLED))) { + if (uwr->extensions.disabled) + jk_log(l, JK_LOG_WARNING, +- "extension '%s' in uri worker map only allowed once", +- JK_UWMAP_EXTENSION_DISABLED); ++ "rule extension '" JK_UWMAP_EXTENSION_DISABLED "' only allowed once"); + else + uwr->extensions.disabled = param + strlen(JK_UWMAP_EXTENSION_DISABLED); + } + else if (!strncmp(param, JK_UWMAP_EXTENSION_STOPPED, strlen(JK_UWMAP_EXTENSION_STOPPED))) { + if (uwr->extensions.stopped) + jk_log(l, JK_LOG_WARNING, +- "extension '%s' in uri worker map only allowed once", +- JK_UWMAP_EXTENSION_STOPPED); ++ "rule extension '" JK_UWMAP_EXTENSION_STOPPED "' only allowed once"); + else + uwr->extensions.stopped = param + strlen(JK_UWMAP_EXTENSION_STOPPED); + } + else if (!strncmp(param, JK_UWMAP_EXTENSION_FAIL_ON_STATUS, strlen(JK_UWMAP_EXTENSION_FAIL_ON_STATUS))) { + if (uwr->extensions.fail_on_status_str) + jk_log(l, JK_LOG_WARNING, +- "extension '%s' in uri worker map only allowed once", +- JK_UWMAP_EXTENSION_FAIL_ON_STATUS); ++ "rule extension '" JK_UWMAP_EXTENSION_FAIL_ON_STATUS "' only allowed once"); + else + uwr->extensions.fail_on_status_str = param + strlen(JK_UWMAP_EXTENSION_FAIL_ON_STATUS); + } +@@ -939,12 +936,12 @@ static int is_nomatch(jk_uri_worker_map_t *uw_map, + const char *map_uri_to_worker_ext(jk_uri_worker_map_t *uw_map, + const char *uri, const char *vhost, + rule_extension_t **extensions, +- int *index, +- jk_logger_t *l) ++ int *index, jk_logger_t *l) + { + unsigned int i; + unsigned int vhost_len; + int reject_unsafe; ++ int collapse_slashes; + int rv = -1; + char url[JK_MAX_URI_LEN+1]; + +@@ -974,10 +971,8 @@ const char *map_uri_to_worker_ext(jk_uri_worker_map_t *uw_map, + return NULL; + } + } +- /* Make the copy of the provided uri and strip +- * everything after the first ';' char. +- */ + reject_unsafe = uw_map->reject_unsafe; ++ collapse_slashes = uw_map->collapse_slashes; + vhost_len = 0; + /* + * In case we got a vhost, we prepend a slash +@@ -1005,6 +1000,9 @@ const char *map_uri_to_worker_ext(jk_uri_worker_map_t *uw_map, + } + vhost_len += off; + } ++ /* Make the copy of the provided uri and strip ++ * everything after the first ';' char. ++ */ + for (i = 0; i < strlen(uri); i++) { + if (i == JK_MAX_URI_LEN) { + jk_log(l, JK_LOG_WARNING, +@@ -1032,6 +1030,12 @@ const char *map_uri_to_worker_ext(jk_uri_worker_map_t *uw_map, + jk_log(l, JK_LOG_DEBUG, "Found session identifier '%s' in url '%s'", + url_rewrite, uri); + } ++ if (collapse_slashes == JK_COLLAPSE_ALL) { ++ /* Remove multiple slashes ++ * No need to copy url, because it is local and ++ * the unchanged url is no longer needed */ ++ jk_no2slash(url); ++ } + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, "Attempting to map URI '%s' from %d maps", + url, IND_THIS(uw_map->size)); +@@ -1043,6 +1047,13 @@ const char *map_uri_to_worker_ext(jk_uri_worker_map_t *uw_map, + + /* In case we found a match, check for the unmounts. */ + if (rv >= 0 && IND_THIS(uw_map->nosize)) { ++ if (collapse_slashes == JK_COLLAPSE_UNMOUNT) { ++ /* Remove multiple slashes when looking for ++ * unmount to prevent trivial unmount bypass attack. ++ * No need to copy url, because it is local and ++ * the unchanged url is no longer needed */ ++ jk_no2slash(url); ++ } + /* Again first including vhost. */ + int rc = is_nomatch(uw_map, url, rv, l); + /* If no unmount was find, try without vhost. */ +diff --git a/native/common/jk_uri_worker_map.h b/native/common/jk_uri_worker_map.h +index 30091dc..d609fcd 100644 +--- a/native/common/jk_uri_worker_map.h ++++ b/native/common/jk_uri_worker_map.h +@@ -58,6 +58,11 @@ extern "C" + #define MATCH_TYPE_STOPPED 0x4000 + */ + ++#define JK_COLLAPSE_ALL 0x0001 ++#define JK_COLLAPSE_NONE 0x0002 ++#define JK_COLLAPSE_UNMOUNT 0x0003 ++#define JK_COLLAPSE_DEFAULT JK_COLLAPSE_UNMOUNT ++ + #define SOURCE_TYPE_WORKERDEF 0x0001 + #define SOURCE_TYPE_JKMOUNT 0x0002 + #define SOURCE_TYPE_URIMAP 0x0003 +@@ -152,6 +157,8 @@ struct jk_uri_worker_map + JK_CRIT_SEC cs; + /* should we forward potentially unsafe URLs */ + int reject_unsafe; ++ /* how to handle multiple adjacent slashes in URLs */ ++ int collapse_slashes; + /* uriworkermap filename */ + const char *fname; + /* uriworkermap reload check interval */ +diff --git a/native/common/jk_util.c b/native/common/jk_util.c +index 1d6d75a..9405157 100644 +--- a/native/common/jk_util.c ++++ b/native/common/jk_util.c +@@ -2124,6 +2124,25 @@ int jk_wildchar_match(const char *str, const char *exp, int icase) + return (str[x] != '\0'); + } + ++void jk_no2slash(char *name) ++{ ++ char *d, *s; ++ ++ s = d = name; ++ ++ while (*s) { ++ if ((*d++ = *s) == '/') { ++ do { ++ ++s; ++ } while (*s == '/'); ++ } ++ else { ++ ++s; ++ } ++ } ++ *d = '\0'; ++} ++ + #ifdef _MT_CODE_PTHREAD + jk_pthread_t jk_gettid() + { +diff --git a/native/common/jk_util.h b/native/common/jk_util.h +index b76d028..c65ed99 100644 +--- a/native/common/jk_util.h ++++ b/native/common/jk_util.h +@@ -233,6 +233,8 @@ int is_http_status_fail(unsigned int http_status_fail_num, + + int jk_wildchar_match(const char *str, const char *exp, int icase); + ++void jk_no2slash(char *name); ++ + #define TC32_BRIDGE_TYPE 32 + #define TC33_BRIDGE_TYPE 33 + #define TC40_BRIDGE_TYPE 40 +diff --git a/native/iis/jk_isapi_plugin.c b/native/iis/jk_isapi_plugin.c +index 1fa0fcb..4299c95 100644 +--- a/native/iis/jk_isapi_plugin.c ++++ b/native/iis/jk_isapi_plugin.c +@@ -124,6 +124,10 @@ static char HTTP_WORKER_HEADER_INDEX[MAX_PATH]; + #define AUTH_COMPLETE_TAG ("auth_complete") + #endif + #define REJECT_UNSAFE_TAG ("reject_unsafe") ++#define COLLAPSE_SLASHES_TAG ("collapse_slashes") ++#define COLLAPSE_SLASHES_ALL_VERB ("all") ++#define COLLAPSE_SLASHES_NONE_VERB ("none") ++#define COLLAPSE_SLASHES_UNMOUNT_VERB ("unmount") + #define WATCHDOG_INTERVAL_TAG ("watchdog_interval") + #define ENABLE_CHUNKED_ENCODING_TAG ("enable_chunked_encoding") + #define ERROR_PAGE_TAG ("error_page") +@@ -499,6 +503,7 @@ static int use_auth_notification_flags = 1; + #endif + static int chunked_encoding_enabled = JK_FALSE; + static int reject_unsafe = 0; ++static int collapse_slashes = JK_COLLAPSE_DEFAULT; + static int watchdog_interval = 0; + static HANDLE watchdog_handle = NULL; + static char error_page_buf[INTERNET_MAX_URL_LENGTH] = {0}; +@@ -2503,6 +2508,7 @@ static int init_jk(char *serverName) + uw_map->reject_unsafe = 1; + else + uw_map->reject_unsafe = 0; ++ uw_map->collapse_slashes = collapse_slashes; + uw_map->reload = worker_mount_reload; + if (worker_mount_file[0]) { + uw_map->fname = worker_mount_file; +@@ -2608,6 +2614,17 @@ int parse_uri_select(const char *uri_select) + return -1; + } + ++int parse_collapse_slashes(const char *collapse_slashes) ++{ ++ if (!strcasecmp(collapse_slashes, COLLAPSE_SLASHES_ALL_VERB)) ++ return JK_OPT_COLLAPSEALL; ++ if (!strcasecmp(collapse_slashes, COLLAPSE_SLASHES_NONE_VERB)) ++ return JK_OPT_COLLAPSENONE; ++ if (!strcasecmp(collapse_slashes, COLLAPSE_SLASHES_UNMOUNT_VERB)) ++ return JK_OPT_COLLAPSEUNMOUNT; ++ return -1; ++} ++ + static int read_registry_init_data(void) + { + char tmpbuf[MAX_PATH]; +@@ -2640,6 +2657,16 @@ static int read_registry_init_data(void) + if (get_config_parameter(src, JK_LOG_LEVEL_TAG, tmpbuf, sizeof(tmpbuf))) { + log_level = jk_parse_log_level(tmpbuf); + } ++ if (get_config_parameter(src, COLLAPSE_SLASHES_TAG, tmpbuf, sizeof(tmpbuf))) { ++ int opt = parse_collapse_slashes(tmpbuf); ++ if (opt >= 0) { ++ collapse_slashes = opt; ++ } ++ else { ++ jk_log(logger, JK_LOG_ERROR, "Invalid value '%s' for configuration item '" ++ COLLAPSE_SLASHES_TAG "'", tmpbuf); ++ } ++ + ok = ok && get_config_parameter(src, EXTENSION_URI_TAG, extension_uri, sizeof(extension_uri)); + ok = ok && get_config_parameter(src, JK_WORKER_FILE_TAG, worker_file, sizeof(worker_file)); + ok = ok && get_config_parameter(src, JK_MOUNT_FILE_TAG, worker_mount_file, sizeof(worker_mount_file)); diff -Nru libapache-mod-jk-1.2.30/debian/patches/series libapache-mod-jk-1.2.30/debian/patches/series --- libapache-mod-jk-1.2.30/debian/patches/series 2011-02-10 23:27:28.000000000 +0100 +++ libapache-mod-jk-1.2.30/debian/patches/series 2015-05-30 14:51:53.000000000 +0200 @@ -3,3 +3,4 @@ 0003-upgrade-info-to-error-message.patch 0004-update-config.guess-and-config.sub.patch 0005-disable-sock_cloexec-flag.patch +CVE-2014-8111.patch
signature.asc
Description: OpenPGP digital signature