The branch, v4-18-test has been updated via a6edfaa4985 python:safe_tarfile: Improve safe extract() via b7cad429a52 python:safe_tarfile: Implement safer extractall() via eff4e88d2cc python:safe_tarfile: Set extraction_filter for pythons providing it via 4a79ee44c31 python:tests: Adopt safe_tarfile for extraction_filter raises via d2c86925f62 s3/utils: avoid erronous NO MEMORY detection from c7e3c042fbc smbcacls/smbcquotas: check for valid UNC path
https://git.samba.org/?p=samba.git;a=shortlog;h=v4-18-test - Log ----------------------------------------------------------------- commit a6edfaa498552dcef704bda0c6fcb7b14c88bdcc Author: Andreas Schneider <a...@samba.org> Date: Tue Jun 6 15:38:12 2023 +0200 python:safe_tarfile: Improve safe extract() This also checks for symlinks and hardlinks. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15390 Signed-off-by: Andreas Schneider <a...@samba.org> Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> (cherry picked from commit 1f74f9f366d7f107a89220a4a5951bc4daf18025) Autobuild-User(v4-18-test): Jule Anger <jan...@samba.org> Autobuild-Date(v4-18-test): Mon Jun 19 10:29:13 UTC 2023 on atb-devel-224 commit b7cad429a52857ac8a1d1685c732f4c746e7c339 Author: Andreas Schneider <a...@samba.org> Date: Tue Jun 6 15:30:20 2023 +0200 python:safe_tarfile: Implement safer extractall() This also checks for symlinks and hardlinks. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15390 Signed-off-by: Andreas Schneider <a...@samba.org> Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> (cherry picked from commit 431f7698e48387413aac586c7a939a1682464681) commit eff4e88d2cc01d60a8ad03108f0d5691bde0e976 Author: Andreas Schneider <a...@samba.org> Date: Tue Jun 6 15:29:06 2023 +0200 python:safe_tarfile: Set extraction_filter for pythons providing it It should be available for Python >= 3.11.4 but also has been backported. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15390 Signed-off-by: Andreas Schneider <a...@samba.org> Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> (cherry picked from commit 8c90c66a9a409d807dad56822540509c9813425b) commit 4a79ee44c311f1a78de9fc9d2b8bc73fb4987719 Author: Andreas Schneider <a...@samba.org> Date: Tue Jun 6 16:06:57 2023 +0200 python:tests: Adopt safe_tarfile for extraction_filter raises BUG: https://bugzilla.samba.org/show_bug.cgi?id=15390 Signed-off-by: Andreas Schneider <a...@samba.org> Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> (cherry picked from commit ebaa00816259cbae5c45ebf0ba5fb260b09e4695) commit d2c86925f62012f0fe017a16ce4cef5fd47e17c3 Author: Noel Power <noel.po...@suse.com> Date: Fri Jun 2 14:27:55 2023 +0100 s3/utils: avoid erronous NO MEMORY detection since 5cc3c1b5f6b0289f91c01b20989558badc28fd61 if we don't have a realm specified either on cmdline or in conf file we try to copy (talloc_strdup) a NULL variable which triggers a NO_MEMORY error when we check the result of the copy BUG: https://bugzilla.samba.org/show_bug.cgi?id=15384 Signed-off-by: Noel Power <noel.po...@suse.com> Reviewed-by: Stefan Metzmacher <me...@samba.org> Autobuild-User(master): Stefan Metzmacher <me...@samba.org> Autobuild-Date(master): Sun Jun 4 12:42:16 UTC 2023 on atb-devel-224 (cherry picked from commit 22ab42c1007775abca0b578744d4c18a85cda627) ----------------------------------------------------------------------- Summary of changes: python/samba/safe_tarfile.py | 73 ++++++++++++++++++++++++++++++++------ python/samba/tests/safe_tarfile.py | 27 ++++++++++---- source3/utils/net_ads.c | 10 +++--- 3 files changed, 89 insertions(+), 21 deletions(-) Changeset truncated at 500 lines: diff --git a/python/samba/safe_tarfile.py b/python/samba/safe_tarfile.py index cc19770d73f..7a2b0382a79 100644 --- a/python/samba/safe_tarfile.py +++ b/python/samba/safe_tarfile.py @@ -15,6 +15,9 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. +import os +import tarfile +from pathlib import Path from tarfile import ExtractError, TarInfo, TarFile as UnsafeTarFile @@ -24,20 +27,68 @@ class TarFile(UnsafeTarFile): using '../../'. """ - def extract(self, member, path="", set_attrs=True, *, numeric_owner=False): - if isinstance(member, TarInfo): - name = member.name - else: - name = member + try: + # New in version 3.11.4 (also has been backported) + # https://docs.python.org/3/library/tarfile.html#tarfile.TarFile.extraction_filter + # https://peps.python.org/pep-0706/ + extraction_filter = staticmethod(tarfile.data_filter) + except AttributeError: + def extract(self, member, path="", set_attrs=True, *, + numeric_owner=False): + self._safetarfile_check() + super().extract(member, path, set_attrs=set_attrs, + numeric_owner=numeric_owner) - if '../' in name: - raise ExtractError(f"'../' is not allowed in path '{name}'") + def extractall(self, path, members=None, *, numeric_owner=False): + self._safetarfile_check() + super().extractall(path, members, + numeric_owner=numeric_owner) - if name.startswith('/'): - raise ExtractError(f"path '{name}' should not start with '/'") + def _safetarfile_check(self): + for tarinfo in self.__iter__(): + if self._is_traversal_attempt(tarinfo=tarinfo): + raise ExtractError( + "Attempted directory traversal for " + f"member: {tarinfo.name}") + if self._is_unsafe_symlink(tarinfo=tarinfo): + raise ExtractError( + "Attempted directory traversal via symlink for " + f"member: {tarinfo.linkname}") + if self._is_unsafe_link(tarinfo=tarinfo): + raise ExtractError( + "Attempted directory traversal via link for " + f"member: {tarinfo.linkname}") - super().extract(member, path, set_attrs=set_attrs, - numeric_owner=numeric_owner) + def _resolve_path(self, path): + return os.path.realpath(os.path.abspath(path)) + + def _is_path_in_dir(self, path, basedir): + return self._resolve_path(os.path.join(basedir, + path)).startswith(basedir) + + def _is_traversal_attempt(self, tarinfo): + if (tarinfo.name.startswith(os.sep) + or ".." + os.sep in tarinfo.name): + return True + return False + + def _is_unsafe_symlink(self, tarinfo): + if tarinfo.issym(): + symlink_file = Path( + os.path.normpath(os.path.join(os.getcwd(), + tarinfo.linkname))) + if not self._is_path_in_dir(symlink_file, os.getcwd()): + return True + return False + + def _is_unsafe_link(self, tarinfo): + if tarinfo.islnk(): + link_file = Path( + os.path.normpath(os.path.join(os.getcwd(), + tarinfo.linkname))) + if not self._is_path_in_dir(link_file, os.getcwd()): + return True + return False open = TarFile.open diff --git a/python/samba/tests/safe_tarfile.py b/python/samba/tests/safe_tarfile.py index 40aa9e17d4a..cf9b725afcb 100644 --- a/python/samba/tests/safe_tarfile.py +++ b/python/samba/tests/safe_tarfile.py @@ -43,9 +43,16 @@ class SafeTarFileTestCase(TestCaseInTempDir): stf = safe_tarfile.open(tarname) - self.assertRaises(tarfile.ExtractError, - stf.extractall, - tarname) + # We we have data_filter, we have a patched python to address + # CVE-2007-4559. + if hasattr(tarfile, "data_filter"): + self.assertRaises(tarfile.OutsideDestinationError, + stf.extractall, + tarname) + else: + self.assertRaises(tarfile.ExtractError, + stf.extractall, + tarname) self.rm_files('x', 'tar.tar') def test_slash(self): @@ -60,8 +67,16 @@ class SafeTarFileTestCase(TestCaseInTempDir): tf.close() stf = safe_tarfile.open(tarname) - self.assertRaises(tarfile.ExtractError, - stf.extractall, - tarname) + + # We we have data_filter, we have a patched python to address + # CVE-2007-4559. + if hasattr(tarfile, "data_filter"): + self.assertRaises(NotADirectoryError, + stf.extractall, + tarname) + else: + self.assertRaises(tarfile.ExtractError, + stf.extractall, + tarname) self.rm_files('x', 'tar.tar') diff --git a/source3/utils/net_ads.c b/source3/utils/net_ads.c index 9ec884394eb..ff56d7f76e2 100644 --- a/source3/utils/net_ads.c +++ b/source3/utils/net_ads.c @@ -713,10 +713,12 @@ retry: } else if (ads->auth.realm == NULL) { const char *c_realm = cli_credentials_get_realm(c->creds); - ads->auth.realm = talloc_strdup(ads, c_realm); - if (ads->auth.realm == NULL) { - TALLOC_FREE(ads); - return ADS_ERROR(LDAP_NO_MEMORY); + if (c_realm != NULL) { + ads->auth.realm = talloc_strdup(ads, c_realm); + if (ads->auth.realm == NULL) { + TALLOC_FREE(ads); + return ADS_ERROR(LDAP_NO_MEMORY); + } } } -- Samba Shared Repository