diff --git a/CVE-2020-27840.patch b/CVE-2020-27840.patch new file mode 100644 index 0000000000000000000000000000000000000000..7fd7b7565b684d9888631be57dd3ec60424ff348 --- /dev/null +++ b/CVE-2020-27840.patch @@ -0,0 +1,257 @@ +From 44ed6c2263c2c969bec4229f99b37d8f2e09dde0 Mon Sep 17 00:00:00 2001 +From: Douglas Bagnall +Date: Thu, 11 Feb 2021 17:05:14 +1300 +Subject: [PATCH 1/3] CVE-2020-27840: pytests:segfault: add ldb.Dn validate + test + +ldb.Dn.validate wraps ldb_dn_explode. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14595 + +Signed-off-by: Douglas Bagnall +Reviewed-by: Andrew Bartlett +--- + python/samba/tests/segfault.py | 6 ++++++ + selftest/knownfail.d/python-segfaults | 1 + + 2 files changed, 7 insertions(+) + +diff --git a/python/samba/tests/segfault.py b/python/samba/tests/segfault.py +index 07e2d46d56a..70bd5b180e3 100644 +--- a/python/samba/tests/segfault.py ++++ b/python/samba/tests/segfault.py +@@ -174,3 +174,9 @@ class SegfaultTests(samba.tests.TestCase): + def test_dcerpc_idl_inline_arrays(self): + """Inline arrays were incorrectly handled.""" + dnsserver.DNS_RPC_SERVER_INFO_DOTNET().pExtensions ++ ++ @segfault_detector ++ def test_ldb_dn_explode_crash(self): ++ for i in range(106, 550, 5): ++ dn = ldb.Dn(ldb.Ldb(), "a=b%s,c= " % (' ' * i)) ++ dn.validate() +diff --git a/selftest/knownfail.d/python-segfaults b/selftest/knownfail.d/python-segfaults +index 1be0566dcb1..524f7dd013b 100644 +--- a/selftest/knownfail.d/python-segfaults ++++ b/selftest/knownfail.d/python-segfaults +@@ -1 +1,2 @@ + samba.tests.segfault.samba.tests.segfault.SegfaultTests.test_net_replicate_init__3 ++samba.tests.segfault.samba.tests.segfault.SegfaultTests.test_ldb_dn_explode_crash +-- +2.25.1 + + +From 5fbc51a2cf77ebd7ca42cd7dda58d5fd0ec5127d Mon Sep 17 00:00:00 2001 +From: Douglas Bagnall +Date: Fri, 11 Dec 2020 16:32:25 +1300 +Subject: [PATCH 2/3] 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 +Reviewed-by: Andrew Bartlett +--- + lib/ldb/common/ldb_dn.c | 1 + + selftest/knownfail.d/python-segfaults | 1 - + 2 files changed, 1 insertion(+), 1 deletion(-) + +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 +-- +2.25.1 + + +From 90f08c437ce81f2a96ce0740a93aa00e94eb5f16 Mon Sep 17 00:00:00 2001 +From: Douglas Bagnall +Date: Thu, 11 Feb 2021 16:28:43 +1300 +Subject: [PATCH 3/3] CVE-2020-27840: pytests: move Dn.validate test to ldb + +We had the test in the Samba Python segfault suite because +a) the signal catching infrastructure was there, and +b) the ldb tests lack Samba's knownfail mechanism, which allowed us to + assert the failure. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14595 + +Signed-off-by: Douglas Bagnall +Reviewed-by: Andrew Bartlett +--- + lib/ldb/tests/python/crash.py | 45 ++++++++++++++++++++++++++++++++++ + lib/ldb/wscript | 1 + + python/samba/tests/segfault.py | 6 ----- + 3 files changed, 46 insertions(+), 6 deletions(-) + create mode 100644 lib/ldb/tests/python/crash.py + +diff --git a/lib/ldb/tests/python/crash.py b/lib/ldb/tests/python/crash.py +new file mode 100644 +index 00000000000..32839814552 +--- /dev/null ++++ b/lib/ldb/tests/python/crash.py +@@ -0,0 +1,45 @@ ++#!/usr/bin/env python3 ++# ++# Tests for crashing functions ++ ++import os ++from unittest import TestCase ++import os ++import sys ++import traceback ++ ++import ldb ++ ++ ++def segfault_detector(f): ++ def wrapper(*args, **kwargs): ++ pid = os.fork() ++ if pid == 0: ++ # child, crashing? ++ try: ++ f(*args, **kwargs) ++ except Exception as e: ++ traceback.print_exc() ++ sys.stderr.flush() ++ sys.stdout.flush() ++ os._exit(0) ++ ++ # parent, waiting ++ pid2, status = os.waitpid(pid, 0) ++ if os.WIFSIGNALED(status): ++ signal = os.WTERMSIG(status) ++ raise AssertionError("Failed with signal %d" % signal) ++ ++ return wrapper ++ ++ ++class LdbDnCrashTests(TestCase): ++ @segfault_detector ++ def test_ldb_dn_explode_crash(self): ++ for i in range(106, 150): ++ dn = ldb.Dn(ldb.Ldb(), "a=b%s,c= " % (' ' * i)) ++ dn.validate() ++ ++if __name__ == '__main__': ++ import unittest ++ unittest.TestProgram() +diff --git a/lib/ldb/wscript b/lib/ldb/wscript +index edc3343e827..33265da373a 100644 +--- a/lib/ldb/wscript ++++ b/lib/ldb/wscript +@@ -614,6 +614,7 @@ def test(ctx): + os.mkdir(tmp_dir) + pyret = samba_utils.RUN_PYTHON_TESTS( + ['tests/python/api.py', ++ 'tests/python/crash.py', + 'tests/python/index.py', + 'tests/python/repack.py'], + extra_env={'SELFTEST_PREFIX': test_prefix}) +diff --git a/python/samba/tests/segfault.py b/python/samba/tests/segfault.py +index 70bd5b180e3..07e2d46d56a 100644 +--- a/python/samba/tests/segfault.py ++++ b/python/samba/tests/segfault.py +@@ -174,9 +174,3 @@ class SegfaultTests(samba.tests.TestCase): + def test_dcerpc_idl_inline_arrays(self): + """Inline arrays were incorrectly handled.""" + dnsserver.DNS_RPC_SERVER_INFO_DOTNET().pExtensions +- +- @segfault_detector +- def test_ldb_dn_explode_crash(self): +- for i in range(106, 550, 5): +- dn = ldb.Dn(ldb.Ldb(), "a=b%s,c= " % (' ' * i)) +- dn.validate() +-- +2.25.1 diff --git a/CVE-2021-20254.patch b/CVE-2021-20254.patch new file mode 100644 index 0000000000000000000000000000000000000000..974e00ad5486e7cae19f628a9584388fb881248f --- /dev/null +++ b/CVE-2021-20254.patch @@ -0,0 +1,234 @@ +From 75ad84167f5d2379557ec078d17c9a1c244402fc Mon Sep 17 00:00:00 2001 +From: Volker Lendecke +Date: Sat, 20 Feb 2021 15:50:12 +0100 +Subject: [PATCH] CVE-2021-20254 passdb: Simplify sids_to_unixids() + +Best reviewed with "git show -b", there's a "continue" statement that +changes subsequent indentation. + +Decouple lookup status of ids from ID_TYPE_NOT_SPECIFIED + +Add comments to explain the use of the three lookup +loops. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14571 + +Signed-off-by: Volker Lendecke +Reviewed-by: Jeremy Allison + +Autobuild-User(master): Karolin Seeger +Autobuild-Date(master): Thu Apr 29 09:55:51 UTC 2021 on sn-devel-184 +--- + source3/passdb/lookup_sid.c | 123 +++++++++++++++++++++++++++++------- + 1 file changed, 101 insertions(+), 22 deletions(-) + +diff --git a/source3/passdb/lookup_sid.c b/source3/passdb/lookup_sid.c +index cf80a300189..0e01467b3cb 100644 +--- a/source3/passdb/lookup_sid.c ++++ b/source3/passdb/lookup_sid.c +@@ -29,6 +29,7 @@ + #include "../libcli/security/security.h" + #include "lib/winbind_util.h" + #include "../librpc/gen_ndr/idmap.h" ++#include "lib/util/bitmap.h" + + static bool lookup_unix_user_name(const char *name, struct dom_sid *sid) + { +@@ -1266,7 +1267,9 @@ bool sids_to_unixids(const struct dom_sid *sids, uint32_t num_sids, + { + struct wbcDomainSid *wbc_sids = NULL; + struct wbcUnixId *wbc_ids = NULL; ++ struct bitmap *found = NULL; + uint32_t i, num_not_cached; ++ uint32_t wbc_ids_size = 0; + wbcErr err; + bool ret = false; + +@@ -1274,6 +1277,20 @@ bool sids_to_unixids(const struct dom_sid *sids, uint32_t num_sids, + if (wbc_sids == NULL) { + return false; + } ++ found = bitmap_talloc(wbc_sids, num_sids); ++ if (found == NULL) { ++ goto fail; ++ } ++ ++ /* ++ * We go through the requested SID array three times. ++ * First time to look for global_sid_Unix_Users ++ * and global_sid_Unix_Groups SIDS, and to look ++ * for mappings cached in the idmap_cache. ++ * ++ * Use bitmap_set() to mark an ids[] array entry as ++ * being mapped. ++ */ + + num_not_cached = 0; + +@@ -1285,17 +1302,20 @@ bool sids_to_unixids(const struct dom_sid *sids, uint32_t num_sids, + &sids[i], &rid)) { + ids[i].type = ID_TYPE_UID; + ids[i].id = rid; ++ bitmap_set(found, i); + continue; + } + if (sid_peek_check_rid(&global_sid_Unix_Groups, + &sids[i], &rid)) { + ids[i].type = ID_TYPE_GID; + ids[i].id = rid; ++ bitmap_set(found, i); + continue; + } + if (idmap_cache_find_sid2unixid(&sids[i], &ids[i], &expired) + && !expired) + { ++ bitmap_set(found, i); + continue; + } + ids[i].type = ID_TYPE_NOT_SPECIFIED; +@@ -1306,62 +1326,121 @@ bool sids_to_unixids(const struct dom_sid *sids, uint32_t num_sids, + if (num_not_cached == 0) { + goto done; + } +- wbc_ids = talloc_array(talloc_tos(), struct wbcUnixId, num_not_cached); ++ ++ /* ++ * For the ones that we couldn't map in the loop above, query winbindd ++ * via wbcSidsToUnixIds(). ++ */ ++ ++ wbc_ids_size = num_not_cached; ++ wbc_ids = talloc_array(talloc_tos(), struct wbcUnixId, wbc_ids_size); + if (wbc_ids == NULL) { + goto fail; + } +- for (i=0; i id is a union anyway */ +- ids[i].type = (enum id_type)wbc_ids[num_not_cached].type; +- ids[i].id = wbc_ids[num_not_cached].id.gid; +- break; +- } +- num_not_cached += 1; ++ if (bitmap_query(found, i)) { ++ continue; ++ } ++ ++ SMB_ASSERT(num_not_cached < wbc_ids_size); ++ ++ switch (wbc_ids[num_not_cached].type) { ++ case WBC_ID_TYPE_UID: ++ ids[i].type = ID_TYPE_UID; ++ ids[i].id = wbc_ids[num_not_cached].id.uid; ++ bitmap_set(found, i); ++ break; ++ case WBC_ID_TYPE_GID: ++ ids[i].type = ID_TYPE_GID; ++ ids[i].id = wbc_ids[num_not_cached].id.gid; ++ bitmap_set(found, i); ++ break; ++ case WBC_ID_TYPE_BOTH: ++ ids[i].type = ID_TYPE_BOTH; ++ ids[i].id = wbc_ids[num_not_cached].id.uid; ++ bitmap_set(found, i); ++ break; ++ case WBC_ID_TYPE_NOT_SPECIFIED: ++ /* ++ * wbcSidsToUnixIds() wasn't able to map this ++ * so we still need to check legacy_sid_to_XXX() ++ * below. Don't mark the bitmap entry ++ * as being found so the final loop knows ++ * to try and map this entry. ++ */ ++ ids[i].type = ID_TYPE_NOT_SPECIFIED; ++ ids[i].id = (uint32_t)-1; ++ break; ++ default: ++ /* ++ * A successful return from wbcSidsToUnixIds() ++ * cannot return anything other than the values ++ * checked for above. Ensure this is so. ++ */ ++ smb_panic(__location__); ++ break; + } ++ num_not_cached += 1; + } + ++ /* ++ * Third and final time through the SID array, ++ * try legacy_sid_to_gid()/legacy_sid_to_uid() ++ * for entries we haven't already been able to ++ * map. ++ * ++ * Use bitmap_set() to mark an ids[] array entry as ++ * being mapped. ++ */ ++ + for (i=0; i +Date: Tue, 8 Dec 2020 21:32:09 +1300 +Subject: [PATCH] CVE-2021-20277 ldb/attrib_handlers casefold: stay in bounds + +For a string that had N spaces at the beginning, we would +try to move N bytes beyond the end of the string. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14655 + +Signed-off-by: Douglas Bagnall +Reviewed-by: Andrew Bartlett + +(cherry-picked from commit for master) +--- + lib/ldb/common/attrib_handlers.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/lib/ldb/common/attrib_handlers.c b/lib/ldb/common/attrib_handlers.c +index b5212b731596..c6ef5ad477b0 100644 +--- a/lib/ldb/common/attrib_handlers.c ++++ b/lib/ldb/common/attrib_handlers.c +@@ -76,7 +76,7 @@ int ldb_handler_fold(struct ldb_context *ldb, void *mem_ctx, + + /* remove leading spaces if any */ + if (*s == ' ') { +- for (t = s; *s == ' '; s++) ; ++ for (t = s; *s == ' '; s++, l--) ; + + /* remove leading spaces by moving down the string */ + memmove(t, s, l); diff --git a/samba.spec b/samba.spec index c4e62b1ec4f277e3df47bc51cefaefe47408e79f..d1aef1a9cdf0931051ee3ddefea80552670fa179 100644 --- a/samba.spec +++ b/samba.spec @@ -49,7 +49,7 @@ Name: samba Version: 4.12.5 -Release: 4 +Release: 5 Summary: A suite for Linux to interoperate with Windows License: GPLv3+ and LGPLv3+ @@ -71,6 +71,9 @@ Patch1: 0001-CVE-2020-14383.patch Patch2: 0002-CVE-2020-14383.patch Patch3: CVE-2020-14318.patch Patch4: CVE-2020-14323.patch +Patch5: CVE-2021-20277.patch +Patch6: CVE-2020-27840.patch +Patch7: CVE-2021-20254.patch BuildRequires: avahi-devel bison cups-devel dbus-devel docbook-style-xsl e2fsprogs-devel flex gawk gnupg2 gnutls-devel >= 3.4.7 gpgme-devel BuildRequires: jansson-devel krb5-devel >= %{required_mit_krb5} libacl-devel libaio-devel libarchive-devel libattr-devel @@ -3092,6 +3095,12 @@ fi %endif %changelog +* Mon May 31 2021 gaihuiying - 4.12.5-5 +- Type:cves +- ID:CVE-2020-27840 CVE-2021-20277 CVE-2021-20254 +- SUG:NA +- DESC:fix CVE-2020-27840 CVE-2021-20277 CVE-2021-20254 + * Thu May 27 2021 lijingyuan - 4.12.5-4 - Type:bugfix - Id: