[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

libapache-mod-jk: CVE-2014-8111



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


Reply to: