In several cases, snprintf result was used without validating its range.

When formatted string would overflow buffer or error happens, snprintf
will return either value larger than buffer size, or -1. In both cases,
if you add this value to pointer (or similar), bad things will happen.

Pattern to watch for: =.*snprintf

I have not verified if any of this is exploitable. In some cases, I was
not sure about proper error handling (watch for XXX comments).

While fixing this error, I noticed typo in Ip::Qos::Config::dumpConfigLine:
markMissMask was used instead of tosMissMask.

Patches compile-tested (however, only on linux/x86/gcc49 and in default
configuration).

Index: squid-3.5.13/src/ip/QosConfig.cc
===================================================================
--- squid-3.5.13.orig/src/ip/QosConfig.cc
+++ squid-3.5.13/src/ip/QosConfig.cc
@@ -392,7 +392,7 @@ Ip::Qos::Config::dumpConfigLine(char *en
         if (tosMiss > 0) {
             p += snprintf(p, 11, " miss=0x%02X", tosMiss);
             if (tosMissMask!=0xFFU) {
-                p += snprintf(p, 6, "/0x%02X", markMissMask);
+                p += snprintf(p, 6, "/0x%02X", tosMissMask);
             }
         }
         if (preserveMissTos == 0) {
Index: squid-3.5.13/helpers/digest_auth/file/text_backend.cc
===================================================================
--- squid-3.5.13.orig/helpers/digest_auth/file/text_backend.cc
+++ squid-3.5.13/helpers/digest_auth/file/text_backend.cc
@@ -171,7 +171,7 @@ GetPassword(RequestData * requestData)
     if (!hash)
         return NULL;
     len = snprintf(buf, sizeof(buf), "%s:%s", requestData->user, requestData->realm);
-    if (len >= static_cast<int>(sizeof(buf)))
+    if (len < 0 || len >= static_cast<int>(sizeof(buf)))
         return NULL;
     u = (user_data*)hash_lookup(hash, buf);
     if (u)
Index: squid-3.5.13/helpers/external_acl/eDirectory_userip/ext_edirectory_userip_acl.cc
===================================================================
--- squid-3.5.13.orig/helpers/external_acl/eDirectory_userip/ext_edirectory_userip_acl.cc
+++ squid-3.5.13/helpers/external_acl/eDirectory_userip/ext_edirectory_userip_acl.cc
@@ -227,7 +227,7 @@ local_printfx(const char *msg,...)
     va_start(ap, msg);
     x = vsnprintf(dbuf, sz, msg, ap);
     va_end(ap);
-    if (x > 0) {
+    if (x > 0 || x >= sz) {
         dbuf[x] = '\0';
         ++x;
         fputs(dbuf, stdout);
@@ -879,6 +879,7 @@ ConvertIP(edui_ldap_t *l, char *ip)
                     return LDAP_ERR_OOB;                        /* Out of bounds -- Invalid address */
                 memset(hexc, '\0', sizeof(hexc));
                 int hlen = snprintf(hexc, sizeof(hexc), "%02X", (int)x);
+                if (hlen < 0 || hlen >= static_cast<int>(sizeof(hexc))) hlen = 0; /* impossible */
                 strncat(l->search_ip, hexc, hlen);
             } else
                 break;                              /* reached end of octet */
@@ -1106,10 +1107,12 @@ SearchFilterLDAP(edui_ldap_t *l, char *g
         if (l->status & LDAP_IPV4_S) {
             int ln = snprintf(bufd, sizeof(bufd), "(networkAddress=8\\23\\00\\00%s)(networkAddress=9\\23\\00\\00%s))", \
                               bufc, bufc);
+            if (ln < 0 || ln >= static_cast<int>(sizeof(bufd))) return LDAP_ERR_FAILED;
             strncat(bufb, bufd, ln);
         } else if (l->status & LDAP_IPV6_S) {
             int ln = snprintf(bufd, sizeof(bufd), "(networkAddress=10\\23\\00\\00%s)(networkAddress=11\\23\\00\\00%s))", \
                               bufc, bufc);
+            if (ln < 0 || ln >= static_cast<int>(sizeof(bufd))) return LDAP_ERR_FAILED;
             strncat(bufb, bufd, ln);
         } else
             strncat(bufb, ")", 1);
@@ -1132,10 +1135,12 @@ SearchFilterLDAP(edui_ldap_t *l, char *g
         if (l->status & LDAP_IPV4_S) {
             int ln = snprintf(bufd, sizeof(bufd), "(networkAddress=8\\23\\00\\00%s)(networkAddress=9\\23\\00\\00%s))", \
                               bufc, bufc);
+            if (ln < 0 || ln >= static_cast<int>(sizeof(bufd))) return LDAP_ERR_FAILED;
             strncat(bufb, bufd, ln);
         } else if (l->status & LDAP_IPV6_S) {
             int ln = snprintf(bufd, sizeof(bufd), "(networkAddress=10\\23\\00\\00%s)(networkAddress=11\\23\\00\\00%s))", \
                               bufc, bufc);
+            if (ln < 0 || ln >= static_cast<int>(sizeof(bufd))) return LDAP_ERR_FAILED;
             strncat(bufb, bufd, ln);
         } else
             strncat(bufb, ")", 1);
@@ -1278,6 +1283,7 @@ SearchIPLDAP(edui_ldap_t *l)
                             if (c < 0)
                                 c = c + 256;
                             int hlen = snprintf(hexc, sizeof(hexc), "%02X", c);
+                            if (hlen < 0 || hlen >= static_cast<int>(sizeof(hexc))) return LDAP_ERR_FAILED;
                             if (k == 0)
                                 xstrncpy(bufb, hexc, sizeof(bufb));
                             else
@@ -1313,6 +1319,7 @@ SearchIPLDAP(edui_ldap_t *l)
                             if (c < 0)
                                 c = c + 256;
                             int hlen = snprintf(hexc, sizeof(hexc), "%02X", c);
+                            if (hlen < 0 || hlen >= static_cast<int>(sizeof(hexc))) return LDAP_ERR_FAILED;
                             if (k == 2)
                                 xstrncpy(bufb, hexc, sizeof(bufb));
                             else
@@ -1348,6 +1355,7 @@ SearchIPLDAP(edui_ldap_t *l)
                             if (c < 0)
                                 c = c + 256;
                             int hlen = snprintf(hexc, sizeof(hexc), "%02X", c);
+                            if (hlen < 0 || hlen >= static_cast<int>(sizeof(hexc))) return LDAP_ERR_FAILED;
                             if (k == 2)
                                 xstrncpy(bufb, hexc, sizeof(bufb));
                             else
Index: squid-3.5.13/src/log/File.cc
===================================================================
--- squid-3.5.13.orig/src/log/File.cc
+++ squid-3.5.13/src/log/File.cc
@@ -104,13 +104,16 @@ logfilePrintf(Logfile * lf, const char *
 
     va_start(args, fmt);
 
-    s = vsnprintf(buf, 8192, fmt, args);
+    s = vsnprintf(buf, sizeof(buf), fmt, args);
 
-    if (s > 8192) {
-        s = 8192;
+    if (s < 0) {
+        xstrncpy(buf, "snprintf error in logfilePrintf\n", sizeof(buf));
+        s = strlen(buf);
+    } else if (s >= static_cast<int>(sizeof(buf))) {
+        s = static_cast<int>(sizeof(buf));
 
         if (fmt[strlen(fmt) - 1] == '\n')
-            buf[8191] = '\n';
+            buf[sizeof(buf) - 1] = '\n';
     }
 
     logfileWrite(lf, buf, (size_t) s);
Index: squid-3.5.13/tools/cachemgr.cc
===================================================================
--- squid-3.5.13.orig/tools/cachemgr.cc
+++ squid-3.5.13/tools/cachemgr.cc
@@ -505,6 +505,7 @@ munge_other_line(const char *buf, cachem
     /* start html table */
     if (!table_line_num) {
         l += snprintf(html + l, sizeof(html) - l, "</pre><table cellpadding=\"2\" cellspacing=\"1\">\n");
+        if (l < 0 || l >= static_cast<int>(sizeof(html))) l = 0;
         next_is_header = 0;
     }
 
@@ -515,6 +516,7 @@ munge_other_line(const char *buf, cachem
 
     /* record starts */
     l += snprintf(html + l, sizeof(html) - l, "<tr>");
+    if (l < 0 || l >= static_cast<int>(sizeof(html))) l = 0;
 
     /* substitute '\t' */
     buf_copy = x = xstrdup(buf);
@@ -535,6 +537,7 @@ munge_other_line(const char *buf, cachem
                       ttag, column_span,
                       is_header ? "center" : is_number(cell) ? "right" : "left",
                       html_quote(cell), ttag);
+        if (l < 0 || l >= static_cast<int>(sizeof(html))) l = 0;
     }
 
     xfree(buf_copy);
@@ -850,6 +853,10 @@ process_request(cachemgr_request * req)
                  req->workers? req->workers : (req->processes ? req->processes: ""),
                  VERSION,
                  make_auth_header(req));
+    if (l < 0 || l >= static_cast<int>(sizeof(buf))) {
+        error_html("snprintf error");
+        return 1;
+    }
     if (write(s, buf, l) < 0) {
         fprintf(stderr,"ERROR: (%d) writing request: '%s'\n", errno, buf);
     } else {
@@ -1075,6 +1082,10 @@ make_pub_auth(cachemgr_request * req)
                                 (int) now,
                                 req->user_name ? req->user_name : "",
                                 req->passwd);
+    if (bufLen < 0 || bufLen >= static_cast<int>(sizeof(buf))) {
+        debug("cmgr: snprintf error: 0 <= %d <= %u\n", bufLen, (unsigned)sizeof(buf));
+        return;
+    }
     debug("cmgr: pre-encoded for pub: %s\n", buf);
 
     const int encodedLen = base64_encode_len(bufLen);
@@ -1176,6 +1187,11 @@ make_auth_header(const cachemgr_request
                           req->user_name ? req->user_name : "",
                           req->passwd);
 
+    if (bufLen < 0 || bufLen >= static_cast<int>(sizeof(buf))) {
+        debug("cmgr: snprintf error: 0 <= %d <= %u\n", bufLen, (unsigned)sizeof(buf));
+        return ""; // XXX review
+    }
+
     int encodedLen = base64_encode_len(bufLen);
     if (encodedLen <= 0)
         return "";
@@ -1185,7 +1201,10 @@ make_auth_header(const cachemgr_request
 
     stringLength += snprintf(buf, sizeof(buf), "Authorization: Basic %s\r\n", str64);
 
-    assert(stringLength < sizeof(buf));
+    if (!(stringLength < sizeof(buf))) { /* NDEBUG */
+        xfree(str64);
+        return ""; // XXX review
+    }
 
     snprintf(&buf[stringLength], sizeof(buf) - stringLength, "Proxy-Authorization: Basic %s\r\n", str64);
 
Index: squid-3.5.13/compat/inet_ntop.cc
===================================================================
--- squid-3.5.13.orig/compat/inet_ntop.cc
+++ squid-3.5.13/compat/inet_ntop.cc
@@ -225,7 +225,10 @@ inet_ntop6(const u_char *src, char *dst,
             tp += strlen(tp);
             break;
         }
-        tp += snprintf(tp, (tmp + sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") - tp), "%x", words[i]);
+        int rc = snprintf(tp, (tmp + sizeof(tmp) - tp), "%x", words[i]);
+        if (rc < 0 || rc >= static_cast<int>((tmp + sizeof(tmp) - tp)))
+            return (NULL);
+        tp += rc;
     }
     /* Was it a trailing run of 0x00's? */
     if (best.base != -1 && (best.base + best.len) ==
Index: squid-3.5.13/src/ip/QosConfig.cc
===================================================================
--- squid-3.5.13.orig/src/ip/QosConfig.cc
+++ squid-3.5.13/src/ip/QosConfig.cc
@@ -371,65 +371,67 @@ Ip::Qos::Config::parseConfigLine()
  * objects are part of the dump function must be self-contained.
  * which means no StoreEntry refrences. Just a basic char* buffer.
 */
+#define sanitized_snprintf(p, len, fmt, ...) \
+    min(static_cast<int>(len)-1, max(0, snprintf(p, len, fmt, ##__VA_ARGS__)))
 void
 Ip::Qos::Config::dumpConfigLine(char *entry, const char *name) const
 {
     char *p = entry;
     if (isHitTosActive()) {
 
-        p += snprintf(p, 11, "%s", name); // strlen("qos_flows ");
-        p += snprintf(p, 4, "%s", "tos");
+        p += sanitized_snprintf(p, 11, "%s", name); // strlen("qos_flows ");
+        p += sanitized_snprintf(p, 4, "%s", "tos");
 
         if (tosLocalHit > 0) {
-            p += snprintf(p, 16, " local-hit=0x%02X", tosLocalHit);
+            p += sanitized_snprintf(p, 16, " local-hit=0x%02X", tosLocalHit);
         }
         if (tosSiblingHit > 0) {
-            p += snprintf(p, 18, " sibling-hit=0x%02X", tosSiblingHit);
+            p += sanitized_snprintf(p, 18, " sibling-hit=0x%02X", tosSiblingHit);
         }
         if (tosParentHit > 0) {
-            p += snprintf(p, 17, " parent-hit=0x%02X", tosParentHit);
+            p += sanitized_snprintf(p, 17, " parent-hit=0x%02X", tosParentHit);
         }
         if (tosMiss > 0) {
-            p += snprintf(p, 11, " miss=0x%02X", tosMiss);
+            p += sanitized_snprintf(p, 11, " miss=0x%02X", tosMiss);
             if (tosMissMask!=0xFFU) {
-                p += snprintf(p, 6, "/0x%02X", tosMissMask);
+                p += sanitized_snprintf(p, 6, "/0x%02X", tosMissMask);
             }
         }
         if (preserveMissTos == 0) {
-            p += snprintf(p, 23, " disable-preserve-miss");
+            p += sanitized_snprintf(p, 23, " disable-preserve-miss");
         }
         if (preserveMissTos && preserveMissTosMask != 0) {
-            p += snprintf(p, 16, " miss-mask=0x%02X", preserveMissTosMask);
+            p += sanitized_snprintf(p, 16, " miss-mask=0x%02X", preserveMissTosMask);
         }
-        p += snprintf(p, 2, "\n");
+        p += sanitized_snprintf(p, 2, "\n");
     }
 
     if (isHitNfmarkActive()) {
-        p += snprintf(p, 11, "%s", name); // strlen("qos_flows ");
-        p += snprintf(p, 5, "%s", "mark");
+        p += sanitized_snprintf(p, 11, "%s", name); // strlen("qos_flows ");
+        p += sanitized_snprintf(p, 5, "%s", "mark");
 
         if (markLocalHit > 0) {
-            p += snprintf(p, 22, " local-hit=0x%02X", markLocalHit);
+            p += sanitized_snprintf(p, 22, " local-hit=0x%02X", markLocalHit);
         }
         if (markSiblingHit > 0) {
-            p += snprintf(p, 24, " sibling-hit=0x%02X", markSiblingHit);
+            p += sanitized_snprintf(p, 24, " sibling-hit=0x%02X", markSiblingHit);
         }
         if (markParentHit > 0) {
-            p += snprintf(p, 23, " parent-hit=0x%02X", markParentHit);
+            p += sanitized_snprintf(p, 23, " parent-hit=0x%02X", markParentHit);
         }
         if (markMiss > 0) {
-            p += snprintf(p, 17, " miss=0x%02X", markMiss);
+            p += sanitized_snprintf(p, 17, " miss=0x%02X", markMiss);
             if (markMissMask!=0xFFFFFFFFU) {
-                p += snprintf(p, 12, "/0x%02X", markMissMask);
+                p += sanitized_snprintf(p, 12, "/0x%02X", markMissMask);
             }
         }
         if (preserveMissMark == false) {
-            p += snprintf(p, 23, " disable-preserve-miss");
+            p += sanitized_snprintf(p, 23, " disable-preserve-miss");
         }
         if (preserveMissMark && preserveMissMarkMask != 0) {
-            p += snprintf(p, 22, " miss-mask=0x%02X", preserveMissMarkMask);
+            p += sanitized_snprintf(p, 22, " miss-mask=0x%02X", preserveMissMarkMask);
         }
-        p += snprintf(p, 2, "\n");
+        p += sanitized_snprintf(p, 2, "\n");
     }
 }
 
Index: squid-3.5.13/src/snmp_core.cc
===================================================================
--- squid-3.5.13.orig/src/snmp_core.cc
+++ squid-3.5.13/src/snmp_core.cc
@@ -1056,7 +1056,8 @@ snmpDebugOid(oid * Name, snint Len, MemB
         outbuf.init(16, MAX_IPSTRLEN);
 
     for (x = 0; x < Len; ++x) {
-        size_t bytes = snprintf(mbuf, sizeof(mbuf), ".%u", (unsigned int) Name[x]);
+        int bytes = snprintf(mbuf, sizeof(mbuf), ".%u", (unsigned int) Name[x]);
+        if (bytes < 0 || bytes >= static_cast<int>(sizeof(mbuf))) bytes = 0; // XXX
         outbuf.append(mbuf, bytes);
     }
     return outbuf.content();
Index: squid-3.5.13/src/url.cc
===================================================================
--- squid-3.5.13.orig/src/url.cc
+++ squid-3.5.13/src/url.cc
@@ -641,10 +641,10 @@ urlMakeAbsolute(const HttpRequest * req,
         return (urlbuf);
     }
 
-    size_t urllen;
+    int surllen;
 
     if (req->port != urlDefaultPort(req->url.getScheme())) {
-        urllen = snprintf(urlbuf, MAX_URL, "%s://%s%s%s:%d",
+        surllen = snprintf(urlbuf, MAX_URL, "%s://%s%s%s:%d",
                           req->url.getScheme().c_str(),
                           req->login,
                           *req->login ? "@" : null_string,
@@ -652,7 +652,7 @@ urlMakeAbsolute(const HttpRequest * req,
                           req->port
                          );
     } else {
-        urllen = snprintf(urlbuf, MAX_URL, "%s://%s%s%s",
+        surllen = snprintf(urlbuf, MAX_URL, "%s://%s%s%s",
                           req->url.getScheme().c_str(),
                           req->login,
                           *req->login ? "@" : null_string,
@@ -660,6 +660,11 @@ urlMakeAbsolute(const HttpRequest * req,
                          );
     }
 
+    if (surllen < 0 || surllen >= MAX_URL)
+        return NULL; // XXX review
+
+    size_t urllen = static_cast<size_t>(surllen);
+
     if (relUrl[0] == '/') {
         strncpy(&urlbuf[urllen], relUrl, MAX_URL - urllen - 1);
     } else {
_______________________________________________
squid-dev mailing list
squid-dev@lists.squid-cache.org
http://lists.squid-cache.org/listinfo/squid-dev

Reply via email to