Hello security team, I have prepared two security updates for libapache-mod-jk which is affected by CVE-2014-8111 [1] in Jessie and Wheezy. This is Debian bug #783233 [2]. I have already packaged a SVN snapshot for sid/stretch. A new upstream release, 1.2.41, has not taken place yet. I am attaching the debdiffs to this e-mail which are identical except that the targeted distributions are different. Therefor I have rebased the upstream fix which can be found here: http://svn.apache.org/r1647017 I think the issue warrants a DSA since it is remotely exploitable although the severity and impact are probably only moderate for most setups. I propose the following text: Package: libapache-mod-jk 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. For the oldstable distribution (wheezy), this problem has been fixed in version 1:1.2.37-1+deb7u1. For the stable distribution (jessie), this problem has been fixed in version 1:1.2.37-4+deb8u1. For the testing distribution (stretch), this problem has been fixed in version 1:1.2.40+svn150520-1. For the unstable distribution (sid), this problem has been fixed in version 1:1.2.40+svn150520-1. We recommend that you upgrade your libapache-mod-jk packages. Regards, Markus [1] https://security-tracker.debian.org/tracker/CVE-2014-8111 [2] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=783233
diff -Nru libapache-mod-jk-1.2.37/debian/changelog libapache-mod-jk-1.2.37/debian/changelog
--- libapache-mod-jk-1.2.37/debian/changelog 2014-11-17 14:59:11.000000000 +0100
+++ libapache-mod-jk-1.2.37/debian/changelog 2015-05-23 23:02:08.000000000 +0200
@@ -1,3 +1,21 @@
+libapache-mod-jk (1:1.2.37-4+deb8u1) jessie-security; 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 <apo@gambaru.de> Sat, 23 May 2015 01:16:37 +0200
+
libapache-mod-jk (1:1.2.37-4) unstable; urgency=medium
* Team upload.
diff -Nru libapache-mod-jk-1.2.37/debian/patches/CVE-2014-8111.patch libapache-mod-jk-1.2.37/debian/patches/CVE-2014-8111.patch
--- libapache-mod-jk-1.2.37/debian/patches/CVE-2014-8111.patch 1970-01-01 01:00:00.000000000 +0100
+++ libapache-mod-jk-1.2.37/debian/patches/CVE-2014-8111.patch 2015-05-23 23:02:08.000000000 +0200
@@ -0,0 +1,474 @@
+From: Markus Koschany <apo@gambaru.de>
+Date: Sat, 23 May 2015 00:05:21 +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 | 48 +++++++++++++++++------------
+ 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 | 64 ++++++++++++++++++++++++++++-----------
+ 8 files changed, 153 insertions(+), 42 deletions(-)
+
+diff --git a/native/apache-1.3/mod_jk.c b/native/apache-1.3/mod_jk.c
+index 81c3a58..9d6840f 100644
+--- a/native/apache-1.3/mod_jk.c
++++ b/native/apache-1.3/mod_jk.c
+@@ -2074,9 +2074,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;
+@@ -2094,6 +2096,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;
+ }
+@@ -2763,6 +2777,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) {
+@@ -2983,6 +3001,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 7c04440..26345ea 100644
+--- a/native/apache-2.0/mod_jk.c
++++ b/native/apache-2.0/mod_jk.c
+@@ -2175,9 +2175,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;
+@@ -2195,6 +2197,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;
+ }
+@@ -2987,6 +3001,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) {
+@@ -3464,6 +3482,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 aefe87e..942ee32 100644
+--- a/native/common/jk_global.h
++++ b/native/common/jk_global.h
+@@ -252,6 +252,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
+@@ -269,7 +274,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 250cdb5..8c3d44e 100644
+--- a/native/common/jk_uri_worker_map.c
++++ b/native/common/jk_uri_worker_map.c
+@@ -174,9 +174,10 @@ static void uri_worker_map_dump(jk_uri_worker_map_t *uw_map,
+ int i, off;
+ if (JK_IS_DEBUG_LEVEL(l)) {
+ jk_log(l, JK_LOG_DEBUG, "uri map dump %s: id=%d, 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->id, uw_map->index, STRNULL_FOR_NULL(uw_map->fname),
+- uw_map->reject_unsafe, uw_map->reload, uw_map->modified, uw_map->checked);
++ uw_map->reject_unsafe, 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",
+@@ -242,6 +243,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;
+@@ -681,48 +683,42 @@ void parse_rule_extensions(char *rule, rule_extension_t *extensions,
+ else if (!strncmp(param, JK_UWMAP_EXTENSION_ACTIVE, strlen(JK_UWMAP_EXTENSION_ACTIVE))) {
+ if (extensions->active)
+ jk_log(l, JK_LOG_WARNING,
+- "rule extension '%s' only allowed once",
+- JK_UWMAP_EXTENSION_ACTIVE);
++ "rule extension '" JK_UWMAP_EXTENSION_ACTIVE "' only allowed once");
+ else
+ extensions->active = param + strlen(JK_UWMAP_EXTENSION_ACTIVE);
+ }
+ else if (!strncmp(param, JK_UWMAP_EXTENSION_DISABLED, strlen(JK_UWMAP_EXTENSION_DISABLED))) {
+ if (extensions->disabled)
+ jk_log(l, JK_LOG_WARNING,
+- "rule extension '%s' only allowed once",
+- JK_UWMAP_EXTENSION_DISABLED);
++ "rule extension '" JK_UWMAP_EXTENSION_DISABLED "' only allowed once");
+ else
+ extensions->disabled = param + strlen(JK_UWMAP_EXTENSION_DISABLED);
+ }
+ else if (!strncmp(param, JK_UWMAP_EXTENSION_STOPPED, strlen(JK_UWMAP_EXTENSION_STOPPED))) {
+ if (extensions->stopped)
+ jk_log(l, JK_LOG_WARNING,
+- "rule extension '%s' only allowed once",
+- JK_UWMAP_EXTENSION_STOPPED);
++ "rule extension '" JK_UWMAP_EXTENSION_STOPPED "' only allowed once");
+ else
+ 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 (extensions->fail_on_status_str)
+ jk_log(l, JK_LOG_WARNING,
+- "rule extension '%s' only allowed once",
+- JK_UWMAP_EXTENSION_FAIL_ON_STATUS);
++ "rule extension '" JK_UWMAP_EXTENSION_FAIL_ON_STATUS "' only allowed once");
+ else
+ extensions->fail_on_status_str = param + strlen(JK_UWMAP_EXTENSION_FAIL_ON_STATUS);
+ }
+ else if (!strncmp(param, JK_UWMAP_EXTENSION_SESSION_COOKIE, strlen(JK_UWMAP_EXTENSION_SESSION_COOKIE))) {
+ if (extensions->session_cookie)
+ jk_log(l, JK_LOG_WARNING,
+- "extension '%s' in uri worker map only allowed once",
+- JK_UWMAP_EXTENSION_SESSION_COOKIE);
++ "extension '" JK_UWMAP_EXTENSION_SESSION_COOKIE "' in uri worker map only allowed once");
+ else
+ extensions->session_cookie = param + strlen(JK_UWMAP_EXTENSION_SESSION_COOKIE);
+ }
+ else if (!strncmp(param, JK_UWMAP_EXTENSION_SESSION_PATH, strlen(JK_UWMAP_EXTENSION_SESSION_PATH))) {
+ if (extensions->session_path)
+ jk_log(l, JK_LOG_WARNING,
+- "extension '%s' in uri worker map only allowed once",
+- JK_UWMAP_EXTENSION_SESSION_PATH);
++ "extension '" JK_UWMAP_EXTENSION_SESSION_PATH "' in uri worker map only allowed once");
+ else {
+ // Check if the session identifier starts with semicolon.
+ if (!strcmp(param, JK_UWMAP_EXTENSION_SESSION_PATH)) {
+@@ -1034,12 +1030,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];
+
+@@ -1069,10 +1065,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
+@@ -1100,6 +1094,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,
+@@ -1127,6 +1124,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));
+@@ -1138,6 +1141,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 1598937..16c14ff 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
+@@ -166,6 +171,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 8c5d803..4455f86 100644
+--- a/native/common/jk_util.c
++++ b/native/common/jk_util.c
+@@ -2089,6 +2089,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 2313c2c..930943c 100644
+--- a/native/common/jk_util.h
++++ b/native/common/jk_util.h
+@@ -238,6 +238,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 e949734..736ac05 100644
+--- a/native/iis/jk_isapi_plugin.c
++++ b/native/iis/jk_isapi_plugin.c
+@@ -117,23 +117,27 @@ static char HTTP_WORKER_HEADER_INDEX[RES_BUFFER_SIZE];
+ #define W3SVC_REGISTRY_KEY "SYSTEM\\CurrentControlSet\\Services\\W3SVC\\Parameters"
+ #define EXTENSION_URI_TAG "extension_uri"
+
+-#define URI_SELECT_TAG "uri_select"
+-#define URI_SELECT_PARSED_VERB "parsed"
+-#define URI_SELECT_UNPARSED_VERB "unparsed"
+-#define URI_SELECT_ESCAPED_VERB "escaped"
+-#define URI_SELECT_PROXY_VERB "proxy"
+-#define URI_REWRITE_TAG "rewrite_rule_file"
+-#define SHM_SIZE_TAG "shm_size"
+-#define WORKER_MOUNT_RELOAD_TAG "worker_mount_reload"
+-#define STRIP_SESSION_TAG "strip_session"
+-#define AUTH_COMPLETE_TAG "auth_complete"
+-#define REJECT_UNSAFE_TAG "reject_unsafe"
+-#define WATCHDOG_INTERVAL_TAG "watchdog_interval"
+-#define ENABLE_CHUNKED_ENCODING_TAG "enable_chunked_encoding"
+-#define ERROR_PAGE_TAG "error_page"
+-
+-#define LOG_ROTATION_TIME_TAG "log_rotationtime"
+-#define LOG_FILESIZE_TAG "log_filesize"
++#define URI_SELECT_TAG "uri_select"
++#define URI_SELECT_PARSED_VERB "parsed"
++#define URI_SELECT_UNPARSED_VERB "unparsed"
++#define URI_SELECT_ESCAPED_VERB "escaped"
++#define URI_SELECT_PROXY_VERB "proxy"
++#define URI_REWRITE_TAG "rewrite_rule_file"
++#define SHM_SIZE_TAG "shm_size"
++#define WORKER_MOUNT_RELOAD_TAG "worker_mount_reload"
++#define STRIP_SESSION_TAG "strip_session"
++#define AUTH_COMPLETE_TAG "auth_complete"
++#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"
++
++#define LOG_ROTATION_TIME_TAG "log_rotationtime"
++#define LOG_FILESIZE_TAG "log_filesize"
+
+ /* HTTP standard headers */
+ #define TRANSFER_ENCODING_CHUNKED_HEADER_COMPLETE "Transfer-Encoding: chunked"
+@@ -501,6 +505,7 @@ static int strip_session = 0;
+ static int use_auth_notification_flags = 1;
+ static int chunked_encoding_enabled = JK_FALSE;
+ static int reject_unsafe = 0;
++static int collapse_slashes = JK_COLLAPSE_DEFAULT;
+ static volatile int watchdog_interval = 0;
+ static HANDLE watchdog_handle = NULL;
+ static char error_page_buf[INTERNET_MAX_URL_LENGTH] = {0};
+@@ -2791,6 +2796,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;
+@@ -2920,6 +2926,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];
+@@ -3017,7 +3034,18 @@ static int read_registry_init_data(void)
+ uri_select_option = opt;
+ }
+ else {
+- goto cleanup;
++ jk_log(logger, JK_LOG_ERROR, "Invalid value '%s' for configuration item '"
++ URI_SELECT_TAG "'", 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);
+ }
+ }
+ shm_config_size = get_config_int(src, SHM_SIZE_TAG, -1);
diff -Nru libapache-mod-jk-1.2.37/debian/patches/series libapache-mod-jk-1.2.37/debian/patches/series
--- libapache-mod-jk-1.2.37/debian/patches/series 2014-11-17 14:59:11.000000000 +0100
+++ libapache-mod-jk-1.2.37/debian/patches/series 2015-05-23 23:02:08.000000000 +0200
@@ -2,3 +2,4 @@
0002-debianize-log-directory.patch
0003-upgrade-info-to-error-message.patch
0004-corrupted-worker-activation-status.patch
+CVE-2014-8111.patch
diff -Nru libapache-mod-jk-1.2.37/debian/changelog libapache-mod-jk-1.2.37/debian/changelog
--- libapache-mod-jk-1.2.37/debian/changelog 2012-06-03 23:09:48.000000000 +0200
+++ libapache-mod-jk-1.2.37/debian/changelog 2015-05-23 23:36:08.000000000 +0200
@@ -1,3 +1,20 @@
+libapache-mod-jk (1:1.2.37-1+deb7u1) wheezy-security; 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 <apo@gambaru.de> Sat, 23 May 2015 23:33:30 +0200
+
libapache-mod-jk (1:1.2.37-1) unstable; urgency=low
* New upstream release.
diff -Nru libapache-mod-jk-1.2.37/debian/patches/CVE-2014-8111.patch libapache-mod-jk-1.2.37/debian/patches/CVE-2014-8111.patch
--- libapache-mod-jk-1.2.37/debian/patches/CVE-2014-8111.patch 1970-01-01 01:00:00.000000000 +0100
+++ libapache-mod-jk-1.2.37/debian/patches/CVE-2014-8111.patch 2015-05-23 23:36:08.000000000 +0200
@@ -0,0 +1,474 @@
+From: Markus Koschany <apo@gambaru.de>
+Date: Sat, 23 May 2015 00:05:21 +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 | 48 +++++++++++++++++------------
+ 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 | 64 ++++++++++++++++++++++++++++-----------
+ 8 files changed, 153 insertions(+), 42 deletions(-)
+
+diff --git a/native/apache-1.3/mod_jk.c b/native/apache-1.3/mod_jk.c
+index 81c3a58..9d6840f 100644
+--- a/native/apache-1.3/mod_jk.c
++++ b/native/apache-1.3/mod_jk.c
+@@ -2074,9 +2074,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;
+@@ -2094,6 +2096,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;
+ }
+@@ -2763,6 +2777,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) {
+@@ -2983,6 +3001,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 7c04440..26345ea 100644
+--- a/native/apache-2.0/mod_jk.c
++++ b/native/apache-2.0/mod_jk.c
+@@ -2175,9 +2175,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;
+@@ -2195,6 +2197,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;
+ }
+@@ -2987,6 +3001,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) {
+@@ -3464,6 +3482,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 aefe87e..942ee32 100644
+--- a/native/common/jk_global.h
++++ b/native/common/jk_global.h
+@@ -252,6 +252,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
+@@ -269,7 +274,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 250cdb5..8c3d44e 100644
+--- a/native/common/jk_uri_worker_map.c
++++ b/native/common/jk_uri_worker_map.c
+@@ -174,9 +174,10 @@ static void uri_worker_map_dump(jk_uri_worker_map_t *uw_map,
+ int i, off;
+ if (JK_IS_DEBUG_LEVEL(l)) {
+ jk_log(l, JK_LOG_DEBUG, "uri map dump %s: id=%d, 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->id, uw_map->index, STRNULL_FOR_NULL(uw_map->fname),
+- uw_map->reject_unsafe, uw_map->reload, uw_map->modified, uw_map->checked);
++ uw_map->reject_unsafe, 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",
+@@ -242,6 +243,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;
+@@ -681,48 +683,42 @@ void parse_rule_extensions(char *rule, rule_extension_t *extensions,
+ else if (!strncmp(param, JK_UWMAP_EXTENSION_ACTIVE, strlen(JK_UWMAP_EXTENSION_ACTIVE))) {
+ if (extensions->active)
+ jk_log(l, JK_LOG_WARNING,
+- "rule extension '%s' only allowed once",
+- JK_UWMAP_EXTENSION_ACTIVE);
++ "rule extension '" JK_UWMAP_EXTENSION_ACTIVE "' only allowed once");
+ else
+ extensions->active = param + strlen(JK_UWMAP_EXTENSION_ACTIVE);
+ }
+ else if (!strncmp(param, JK_UWMAP_EXTENSION_DISABLED, strlen(JK_UWMAP_EXTENSION_DISABLED))) {
+ if (extensions->disabled)
+ jk_log(l, JK_LOG_WARNING,
+- "rule extension '%s' only allowed once",
+- JK_UWMAP_EXTENSION_DISABLED);
++ "rule extension '" JK_UWMAP_EXTENSION_DISABLED "' only allowed once");
+ else
+ extensions->disabled = param + strlen(JK_UWMAP_EXTENSION_DISABLED);
+ }
+ else if (!strncmp(param, JK_UWMAP_EXTENSION_STOPPED, strlen(JK_UWMAP_EXTENSION_STOPPED))) {
+ if (extensions->stopped)
+ jk_log(l, JK_LOG_WARNING,
+- "rule extension '%s' only allowed once",
+- JK_UWMAP_EXTENSION_STOPPED);
++ "rule extension '" JK_UWMAP_EXTENSION_STOPPED "' only allowed once");
+ else
+ 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 (extensions->fail_on_status_str)
+ jk_log(l, JK_LOG_WARNING,
+- "rule extension '%s' only allowed once",
+- JK_UWMAP_EXTENSION_FAIL_ON_STATUS);
++ "rule extension '" JK_UWMAP_EXTENSION_FAIL_ON_STATUS "' only allowed once");
+ else
+ extensions->fail_on_status_str = param + strlen(JK_UWMAP_EXTENSION_FAIL_ON_STATUS);
+ }
+ else if (!strncmp(param, JK_UWMAP_EXTENSION_SESSION_COOKIE, strlen(JK_UWMAP_EXTENSION_SESSION_COOKIE))) {
+ if (extensions->session_cookie)
+ jk_log(l, JK_LOG_WARNING,
+- "extension '%s' in uri worker map only allowed once",
+- JK_UWMAP_EXTENSION_SESSION_COOKIE);
++ "extension '" JK_UWMAP_EXTENSION_SESSION_COOKIE "' in uri worker map only allowed once");
+ else
+ extensions->session_cookie = param + strlen(JK_UWMAP_EXTENSION_SESSION_COOKIE);
+ }
+ else if (!strncmp(param, JK_UWMAP_EXTENSION_SESSION_PATH, strlen(JK_UWMAP_EXTENSION_SESSION_PATH))) {
+ if (extensions->session_path)
+ jk_log(l, JK_LOG_WARNING,
+- "extension '%s' in uri worker map only allowed once",
+- JK_UWMAP_EXTENSION_SESSION_PATH);
++ "extension '" JK_UWMAP_EXTENSION_SESSION_PATH "' in uri worker map only allowed once");
+ else {
+ // Check if the session identifier starts with semicolon.
+ if (!strcmp(param, JK_UWMAP_EXTENSION_SESSION_PATH)) {
+@@ -1034,12 +1030,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];
+
+@@ -1069,10 +1065,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
+@@ -1100,6 +1094,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,
+@@ -1127,6 +1124,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));
+@@ -1138,6 +1141,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 1598937..16c14ff 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
+@@ -166,6 +171,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 8c5d803..4455f86 100644
+--- a/native/common/jk_util.c
++++ b/native/common/jk_util.c
+@@ -2089,6 +2089,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 2313c2c..930943c 100644
+--- a/native/common/jk_util.h
++++ b/native/common/jk_util.h
+@@ -238,6 +238,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 e949734..736ac05 100644
+--- a/native/iis/jk_isapi_plugin.c
++++ b/native/iis/jk_isapi_plugin.c
+@@ -117,23 +117,27 @@ static char HTTP_WORKER_HEADER_INDEX[RES_BUFFER_SIZE];
+ #define W3SVC_REGISTRY_KEY "SYSTEM\\CurrentControlSet\\Services\\W3SVC\\Parameters"
+ #define EXTENSION_URI_TAG "extension_uri"
+
+-#define URI_SELECT_TAG "uri_select"
+-#define URI_SELECT_PARSED_VERB "parsed"
+-#define URI_SELECT_UNPARSED_VERB "unparsed"
+-#define URI_SELECT_ESCAPED_VERB "escaped"
+-#define URI_SELECT_PROXY_VERB "proxy"
+-#define URI_REWRITE_TAG "rewrite_rule_file"
+-#define SHM_SIZE_TAG "shm_size"
+-#define WORKER_MOUNT_RELOAD_TAG "worker_mount_reload"
+-#define STRIP_SESSION_TAG "strip_session"
+-#define AUTH_COMPLETE_TAG "auth_complete"
+-#define REJECT_UNSAFE_TAG "reject_unsafe"
+-#define WATCHDOG_INTERVAL_TAG "watchdog_interval"
+-#define ENABLE_CHUNKED_ENCODING_TAG "enable_chunked_encoding"
+-#define ERROR_PAGE_TAG "error_page"
+-
+-#define LOG_ROTATION_TIME_TAG "log_rotationtime"
+-#define LOG_FILESIZE_TAG "log_filesize"
++#define URI_SELECT_TAG "uri_select"
++#define URI_SELECT_PARSED_VERB "parsed"
++#define URI_SELECT_UNPARSED_VERB "unparsed"
++#define URI_SELECT_ESCAPED_VERB "escaped"
++#define URI_SELECT_PROXY_VERB "proxy"
++#define URI_REWRITE_TAG "rewrite_rule_file"
++#define SHM_SIZE_TAG "shm_size"
++#define WORKER_MOUNT_RELOAD_TAG "worker_mount_reload"
++#define STRIP_SESSION_TAG "strip_session"
++#define AUTH_COMPLETE_TAG "auth_complete"
++#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"
++
++#define LOG_ROTATION_TIME_TAG "log_rotationtime"
++#define LOG_FILESIZE_TAG "log_filesize"
+
+ /* HTTP standard headers */
+ #define TRANSFER_ENCODING_CHUNKED_HEADER_COMPLETE "Transfer-Encoding: chunked"
+@@ -501,6 +505,7 @@ static int strip_session = 0;
+ static int use_auth_notification_flags = 1;
+ static int chunked_encoding_enabled = JK_FALSE;
+ static int reject_unsafe = 0;
++static int collapse_slashes = JK_COLLAPSE_DEFAULT;
+ static volatile int watchdog_interval = 0;
+ static HANDLE watchdog_handle = NULL;
+ static char error_page_buf[INTERNET_MAX_URL_LENGTH] = {0};
+@@ -2791,6 +2796,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;
+@@ -2920,6 +2926,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];
+@@ -3017,7 +3034,18 @@ static int read_registry_init_data(void)
+ uri_select_option = opt;
+ }
+ else {
+- goto cleanup;
++ jk_log(logger, JK_LOG_ERROR, "Invalid value '%s' for configuration item '"
++ URI_SELECT_TAG "'", 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);
+ }
+ }
+ shm_config_size = get_config_int(src, SHM_SIZE_TAG, -1);
diff -Nru libapache-mod-jk-1.2.37/debian/patches/series libapache-mod-jk-1.2.37/debian/patches/series
--- libapache-mod-jk-1.2.37/debian/patches/series 2012-04-04 22:34:09.000000000 +0200
+++ libapache-mod-jk-1.2.37/debian/patches/series 2015-05-23 23:36:08.000000000 +0200
@@ -1,3 +1,4 @@
0001-disable-logo.patch
0002-debianize-log-directory.patch
0003-upgrade-info-to-error-message.patch
+CVE-2014-8111.patch
Attachment:
signature.asc
Description: OpenPGP digital signature