Hi

Inspired by a talk at FOSDEM this weekend [1], I tried building
Varnish with -fsanitize=address enabled.

This exposed a few buffer overflow situations, mainly in varnishtest.
Patches w/ fixes attached.

This was done with ASan's leak checker disabled, since varnishtest has
intentional memory leaks and I haven't yet investigated if specific
allocations can be annotated to make ASan disregard individual leaks.

In addition, there is a use-after-free situation in current master
related to ESI (not present in 4.1.1). I'm about to file a bug for
that one.

In order to build varnish w/ -fsanitize=address, you can do
    ./autogen.des  --without-jemalloc CFLAGS="-fno-omit-frame-pointer
-fsanitize=address"
    export ASAN_OPTIONS=detect_leaks=0
followed by the regular make/make check/etc.

This requires clang >= 3.1 or gcc >= 4.8. Disabling jemalloc is
required as ASan only works with the system allocator.

Note the third patch attached may be a false positive, but I think it
could be an issue on platforms where memcmp does 64 bit word
comparisons at a time.

Regards,
Dag


[1]: 
https://fosdem.org/2016/schedule/event/csafecode/attachments/slides/1131/export/events/attachments/csafecode/slides/1131/fosdem_gentoo_asan.pdf

-- 
Dag Haavi Finstad
Software Developer | Varnish Software
Mobile: +47 476 64 134
We Make Websites Fly!
From 189d0f2bd5ebf183614b4888be31627b48617d58 Mon Sep 17 00:00:00 2001
From: Dag Haavi Finstad <[email protected]>
Date: Mon, 1 Feb 2016 18:25:03 +0100
Subject: [PATCH 1/3] Fix a buffer overflow in vtc.c:macro_get

Spotted by AddressSanitizer.
---
 bin/varnishtest/vtc.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/bin/varnishtest/vtc.c b/bin/varnishtest/vtc.c
index 33b56e1..92a2591 100644
--- a/bin/varnishtest/vtc.c
+++ b/bin/varnishtest/vtc.c
@@ -159,9 +159,10 @@ macro_get(const char *b, const char *e)
 	}
 
 	AZ(pthread_mutex_lock(&macro_mtx));
-	VTAILQ_FOREACH(m, &macro_list, list)
-		if (!memcmp(b, m->name, l) && m->name[l] == '\0')
+	VTAILQ_FOREACH(m, &macro_list, list) {
+		if (strlen(m->name) == l && !memcmp(b, m->name, l))
 			break;
+	}
 	if (m != NULL)
 		retval = strdup(m->val);
 	AZ(pthread_mutex_unlock(&macro_mtx));
-- 
2.7.0.rc3

From f52bc6a6c6ac9c5a6b299827a1951a3bae3685cc Mon Sep 17 00:00:00 2001
From: Dag Haavi Finstad <[email protected]>
Date: Mon, 1 Feb 2016 19:29:14 +0100
Subject: [PATCH 2/3] Fix a buffer overflow in vtc_http.c:cmd_var_resolve

Spotted by AddressSanitizer.
---
 bin/varnishtest/vtc_http.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/bin/varnishtest/vtc_http.c b/bin/varnishtest/vtc_http.c
index 0440542..6df2cae 100644
--- a/bin/varnishtest/vtc_http.c
+++ b/bin/varnishtest/vtc_http.c
@@ -223,10 +223,10 @@ cmd_var_resolve(struct http *hp, char *spec)
 		return(hp->bodylen);
 	if (!strcmp(spec, "resp.body"))
 		return(hp->body != NULL ? hp->body : spec);
-	if (!memcmp(spec, "req.http.", 9)) {
+	if (strlen(spec) > 9 && !memcmp(spec, "req.http.", 9)) {
 		hh = hp->req;
 		hdr = spec + 9;
-	} else if (!memcmp(spec, "resp.http.", 10)) {
+	} else if (strlen(spec) > 10 && !memcmp(spec, "resp.http.", 10)) {
 		hh = hp->resp;
 		hdr = spec + 10;
 	} else
-- 
2.7.0.rc3

From dfab2fc1512c8ed7dd3989fd9f0fa87400e13532 Mon Sep 17 00:00:00 2001
From: Dag Haavi Finstad <[email protected]>
Date: Mon, 1 Feb 2016 19:32:20 +0100
Subject: [PATCH 3/3] Test lengths of both ban strings, to avoid a potential
 buffer overflow.

For memcmp() implementation that do 64 bit word comparisons at the time,
this could lead to a buffer overflow read.

Spotted by AddressSanitizer
---
 bin/varnishd/cache/cache_ban.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/bin/varnishd/cache/cache_ban.c b/bin/varnishd/cache/cache_ban.c
index 2b71d94..cc7141c 100644
--- a/bin/varnishd/cache/cache_ban.c
+++ b/bin/varnishd/cache/cache_ban.c
@@ -139,15 +139,15 @@ ban_len(const uint8_t *banspec)
 int
 ban_equal(const uint8_t *bs1, const uint8_t *bs2)
 {
-	unsigned u;
+	unsigned u, v;
 
 	/*
 	 * Compare two ban-strings.
-	 * The memcmp() is safe because the first field we compare is the
-	 * length and that is part of the fixed header structure.
 	 */
 	u = vbe32dec(bs1 + BANS_LENGTH);
-	return (!memcmp(bs1 + BANS_LENGTH, bs2 + BANS_LENGTH, u - BANS_LENGTH));
+	v = vbe32dec(bs2 + BANS_LENGTH);
+	return (u == v &&
+	    !memcmp(bs1 + BANS_LENGTH, bs2 + BANS_LENGTH, u - BANS_LENGTH));
 }
 
 void
-- 
2.7.0.rc3

_______________________________________________
varnish-dev mailing list
[email protected]
https://www.varnish-cache.org/lists/mailman/listinfo/varnish-dev

Reply via email to