summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Bagnall <douglas.bagnall@catalyst.net.nz>2020-12-11 16:32:25 +1300
committerKarolin Seeger <kseeger@samba.org>2021-03-22 11:53:16 +0100
commit4caf1ebc7a09d2743757da31db7e88b0321a3533 (patch)
treed89319428a1b6a7265cab72534c5d3c7a5fdff03
parentd59379853d8ea755a0281969f98aeca133201894 (diff)
downloadsamba-4caf1ebc7a09d2743757da31db7e88b0321a3533.tar.gz
CVE-2020-27840 ldb_dn: avoid head corruption in ldb_dn_explode
A DN string with lots of trailing space can cause ldb_dn_explode() to put a zero byte in the wrong place in the heap. When a DN string has a value represented with trailing spaces, like this "CN=foo ,DC=bar" the whitespace is supposed to be ignored. We keep track of this in the `t` pointer, which is NULL when we are not walking through trailing spaces, and points to the first space when we are. We are walking with the `p` pointer, writing the value to `d`, and keeping the length in `l`. "CN=foo ,DC= " ==> "foo " ^ ^ ^ t p d --l--- The value is finished when we encounter a comma or the end of the string. If `t` is not NULL at that point, we assume there are trailing spaces and wind `d and `l` back by the correct amount. Then we switch to expecting an attribute name (e.g. "CN"), until we get to an "=", which puts us back into looking for a value. Unfortunately, we forget to immediately tell `t` that we'd finished the last value, we can end up like this: "CN=foo ,DC= " ==> "" ^ ^ ^ t p d l=0 where `p` is pointing to a new value that contains only spaces, while `t` is still referring to the old value. `p` notices the value ends, and we subtract `p - t` from `d`: "CN=foo ,DC= " ==> ? "" ^ ^ ^ t p d l ~= SIZE_MAX - 8 At that point `d` wants to terminate its string with a '\0', but instead it terminates someone else's byte. This does not crash if the number of trailing spaces is small, as `d` will point into a previous value (a copy of "foo" in this example). Corrupting that value will ultimately not matter, as we will soon try to allocate a buffer `l` long, which will be greater than the available memory and the whole operation will fail properly. However, with more spaces, `d` will point into memory before the beginning of the allocated buffer, with the exact offset depending on the length of the earlier attributes and the number of spaces. What about a longer DN with more attributes? For example, "CN=foo ,DC= ,DC=example,DC=com" -- since `d` has moved out of bounds, won't we continue to use it and write more DN values into mystery memory? Fortunately not, because the aforementioned allocation of `l` bytes must happen first, and `l` is now huge. The allocation happens in a talloc_memdup(), which is by default restricted to allocating 256MB. So this allows a person who controls a string parsed by ldb_dn_explode to corrupt heap memory by placing a single zero byte at a chosen offset before the allocated buffer. An LDAP bind request can send a string DN as a username. This DN is necessarily parsed before the password is checked, so an attacker does not need proper credentials. The attacker can easily cause a denial of service and we cannot rule out more subtle attacks. The immediate solution is to reset `t` to NULL when a comma is encountered, indicating that we are no longer looking at trailing whitespace. Found with the help of Honggfuzz. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14595 Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abartlet@samba.org>
-rw-r--r--lib/ldb/common/ldb_dn.c1
-rw-r--r--selftest/knownfail.d/python-segfaults1
2 files changed, 1 insertions, 1 deletions
diff --git a/lib/ldb/common/ldb_dn.c b/lib/ldb/common/ldb_dn.c
index 83f94e3b913..047244287f5 100644
--- a/lib/ldb/common/ldb_dn.c
+++ b/lib/ldb/common/ldb_dn.c
@@ -570,6 +570,7 @@ static bool ldb_dn_explode(struct ldb_dn *dn)
/* trim back */
d -= (p - t);
l -= (p - t);
+ t = NULL;
}
in_attr = true;
diff --git a/selftest/knownfail.d/python-segfaults b/selftest/knownfail.d/python-segfaults
index 524f7dd013b..1be0566dcb1 100644
--- a/selftest/knownfail.d/python-segfaults
+++ b/selftest/knownfail.d/python-segfaults
@@ -1,2 +1 @@
samba.tests.segfault.samba.tests.segfault.SegfaultTests.test_net_replicate_init__3
-samba.tests.segfault.samba.tests.segfault.SegfaultTests.test_ldb_dn_explode_crash