]> granicus.if.org Git - apache/commitdiff
Introduce request taint-checking concept.
authorNick Kew <niq@apache.org>
Fri, 21 Apr 2017 08:44:06 +0000 (08:44 +0000)
committerNick Kew <niq@apache.org>
Fri, 21 Apr 2017 08:44:06 +0000 (08:44 +0000)
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1792169 13f79535-47bb-0310-9956-ffa450edef68

CHANGES
include/ap_mmn.h
include/httpd.h
modules/generators/mod_status.c
modules/proxy/mod_proxy.c
server/config.c
server/util.c

diff --git a/CHANGES b/CHANGES
index 2d9f5367c356153ddc50a109f3540ff5c603a9c7..1a589ea629ce9283ae45c7e7cb03a997e744d295 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,9 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache 2.5.0
 
+  *) Introduce request taint checking framework to prevent privilege
+     hijacking through .htaccess. [Nick Kew]
+
   *) mod_proxy_wstunnel: Add "upgrade" parameter to allow upgrade to other
      protocols.  [Jean-Frederic Clere]
 
index fa75033f3a878c1a554df6f64910320bf979c78b..0967996409d1c3587834e912e984683bf2f56b17 100644 (file)
  *                         Added ap_scan_vchar_obstext()
  * 20161018.2 (2.5.0-dev)  add ap_set_conn_count()
  * 20161018.3 (2.5.0-dev)  add ap_exists_directive()
+ * 20161018.4 (2.5.0-dev)  Add taint to request_rec and ap_request_tainted()
  */
 
 #define MODULE_MAGIC_COOKIE 0x41503235UL /* "AP25" */
 #ifndef MODULE_MAGIC_NUMBER_MAJOR
 #define MODULE_MAGIC_NUMBER_MAJOR 20161018
 #endif
-#define MODULE_MAGIC_NUMBER_MINOR 3                 /* 0...n */
+#define MODULE_MAGIC_NUMBER_MINOR 4                 /* 0...n */
 
 /**
  * Determine if the server's current MODULE_MAGIC_NUMBER is at least a
index ebb2a15b4cc9006cce3f250435430f134ed300fc..1a33466aebd4d0c29b0a30282f4f5db966eab74a 100644 (file)
@@ -1074,6 +1074,11 @@ struct request_rec {
      *  TODO: 2 bit signed bitfield when this structure is compacted
      */
     int double_reverse;
+    /** Mark the request as potentially tainted.  This might become a
+     *  bitfield if we identify different taints to be flagged.
+     *  Always use ap_request_tainted() to check taint.
+     */
+    int taint;
 };
 
 /**
@@ -2153,6 +2158,17 @@ AP_DECLARE(apr_status_t) ap_timeout_parameter_parse(
  */
 AP_DECLARE(int) ap_request_has_body(request_rec *r);
 
+/** Request taint flags.  Only .htaccess defined. */
+#define AP_TAINT_HTACCESS 0x1
+/**
+ * Check whether a request is tainted by potentially-untrusted sources.
+ *
+ * @param r     the request
+ * @param flags Taint flags to check
+ * @return truth value
+ */
+AP_DECLARE(int) ap_request_tainted(request_rec *r, int flags);
+
 /**
  * Cleanup a string (mainly to be filesystem safe)
  * We only allow '_' and alphanumeric chars. Non-printable
index 12801f94ceccb79cbe3dd0b9524e8f86a3f11715..db44e98d2d96ba235dfec961bfed5be1e51def6f 100644 (file)
@@ -213,6 +213,13 @@ static int status_handler(request_rec *r)
         return DECLINED;
     }
 
+    /* A request that has passed through .htaccess has no business
+     * landing up here.
+     */
+    if (ap_request_tainted(r, AP_TAINT_HTACCESS)) {
+        return DECLINED;
+    }
+
 #ifdef HAVE_TIMES
     times_per_thread = getpid() != child_pid;
 #endif
index a0b08788cf094b9133b328d6423702fed1092be7..b8281e0b542bab5885c9f4b037264021ecfc47ee 100644 (file)
@@ -932,6 +932,14 @@ static int proxy_fixup(request_rec *r)
     if (!r->proxyreq || !r->filename || strncmp(r->filename, "proxy:", 6) != 0)
         return DECLINED;
 
+    /* A request that has passed through .htaccess has no business
+     * serving contents from so far outside its directory.
+     * Since we're going to decline it, don't waste time here.
+     */
+    if (ap_request_tainted(r, AP_TAINT_HTACCESS)) {
+        return DECLINED;
+    }
+
     /* XXX: Shouldn't we try this before we run the proxy_walk? */
     url = &r->filename[6];
 
@@ -1025,6 +1033,13 @@ static int proxy_handler(request_rec *r)
         return DECLINED;
     }
 
+    /* A request that has passed through .htaccess has no business
+     * serving contents from so far outside its directory.
+     */
+    if (ap_request_tainted(r, AP_TAINT_HTACCESS)) {
+        return DECLINED;
+    }
+
     if (!r->proxyreq) {
         /* We may have forced the proxy handler via config or .htaccess */
         if (r->handler &&
index 475c064e1d3a8e2638dbe73a990b393f0bd4142f..b4326ff775e805f8b786f519ccece9cd401e39bd 100644 (file)
@@ -2196,6 +2196,8 @@ AP_CORE_DECLARE(int) ap_parse_htaccess(ap_conf_vector_t **result,
             const char *errmsg;
             ap_directive_t *temptree = NULL;
 
+            /* Mark the request as tainted by .htaccess */
+            r->taint |= AP_TAINT_HTACCESS;
             dc = ap_create_per_dir_config(r->pool);
 
             parms.config_file = f;
index ad192562c4d6016012d485502b8e8e4b8efae081..24062ca111d4718b78140666c64c0cd2c3d01bb6 100644 (file)
@@ -2580,6 +2580,21 @@ AP_DECLARE(int) ap_request_has_body(request_rec *r)
     return has_body;
 }
 
+/**
+ * Check whether a request is tainted by exposure to something
+ * potentially untrusted.  
+ *
+ */
+AP_DECLARE(int) ap_request_tainted(request_rec *r, int flags)
+{
+    /** Potential future: a hook or callback here could serve modules
+     *  like mod_security and ironbee with more complex needs.
+     */
+    return r && ((r->taint&flags)
+                 || ap_request_tainted(r->main, flags)
+                 || ap_request_tainted(r->prev, flags));
+}
+
 AP_DECLARE_NONSTD(apr_status_t) ap_pool_cleanup_set_null(void *data_)
 {
     void **ptr = (void **)data_;