mirror of
https://github.com/samba-team/samba.git
synced 2025-12-19 12:23:49 +03:00
After recent upstream Python fixes for various path escape and symlink CVEs in tarfile, in particular this commit: commit 3612d8f51741b11f36f8fb0494d79086bac9390a Author: Łukasz Langa <lukasz@langa.pl> Date: Tue Jun 3 12:42:11 2025 +0200 gh-135034: Normalize link targets in tarfile, add `os.path.realpath(strict='allow_missing')` (#135037) Addresses CVEs 2024-12718, 2025-4138, 2025-4330, and 2025-4517. Signed-off-by: Łukasz Langa <lukasz@langa.pl> Reviewed-by: Jennifer Sutton <jennifersutton@catalyst.net.nz> Co-authored-by: Petr Viktorin <encukou@gmail.com> Co-authored-by: Seth Michael Larson <seth@python.org> Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> our ../../ test that looks for a tarfile.OutsideDestinationError now meets a NotADirectoryError in recent Python versions (this from 3.13, Fedora 42): UNEXPECTED(error): samba.tests.safe_tarfile.samba.tests.safe_tarfile.SafeTarFileTestCase.test_dots(none) REASON: Exception: Exception: Traceback (most recent call last): File "/tmp/samba-testbase/b1/samba-o3/bin/python/samba/tests/safe_tarfile.py", line 48, in test_dots self.assertRaises(tarfile.OutsideDestinationError, ~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ stf.extractall, ^^^^^^^^^^^^^^^ tarname) ^^^^^^^^ File "/usr/lib64/python3.13/unittest/case.py", line 795, in assertRaises return context.handle('assertRaises', args, kwargs) ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib64/python3.13/unittest/case.py", line 238, in handle callable_obj(*args, **kwargs) ~~~~~~~~~~~~^^^^^^^^^^^^^^^^^ File "/usr/lib64/python3.13/tarfile.py", line 2343, in extractall tarinfo, unfiltered = self._get_extract_tarinfo( ~~~~~~~~~~~~~~~~~~~~~~~~~^ member, filter_function, path) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib64/python3.13/tarfile.py", line 2432, in _get_extract_tarinfo self._handle_fatal_error(e) ~~~~~~~~~~~~~~~~~~~~~~~~^^^ File "/usr/lib64/python3.13/tarfile.py", line 2430, in _get_extract_tarinfo filtered = filter_function(unfiltered, path) File "/usr/lib64/python3.13/tarfile.py", line 842, in tar_filter new_attrs = _get_filtered_attrs(member, dest_path, False) File "/usr/lib64/python3.13/tarfile.py", line 783, in _get_filtered_attrs target_path = os.path.realpath(os.path.join(dest_path, name), strict=os.path.ALLOW_MISSING) File "<frozen posixpath>", line 457, in realpath NotADirectoryError: [Errno 20] Not a directory: '/tmp/samba-testbase/b1/samba-o3/bin/ab/tmp/tmpbn6e69ci/tar.tar' In this commit, we say that a NotADirectoryError is OK. When we started safe_tarfile we were acting in advance of upstream Python, but now they are well ahead of us. If we trust their work in recent versions and accept the error conditions they choose, we can more easily get rid of our safe_tarfile when the time is right. For the moment we still support as far back as Python 3.6 for some old enterprise distros, and it is for those that we continue to maintain safe_tarfile. In versions before 3.11 we will see tarfile.ExtractError, and the test for that is unaffected by this change. Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
83 lines
2.6 KiB
Python
83 lines
2.6 KiB
Python
# Unix SMB/CIFS implementation.
|
|
# Copyright (C) Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
import tarfile
|
|
from samba import safe_tarfile
|
|
|
|
import os
|
|
from samba.tests import TestCaseInTempDir
|
|
|
|
|
|
def filterer(prefix):
|
|
def f(info):
|
|
info.name = prefix + info.name
|
|
return info
|
|
return f
|
|
|
|
|
|
class SafeTarFileTestCase(TestCaseInTempDir):
|
|
|
|
def test_dots(self):
|
|
filename = os.path.join(self.tempdir, 'x')
|
|
tarname = os.path.join(self.tempdir, 'tar.tar')
|
|
f = open(filename, 'w')
|
|
f.write('x')
|
|
f.close()
|
|
|
|
tf = tarfile.open(tarname, 'w')
|
|
tf.add(filename, filter=filterer('../../'))
|
|
tf.close()
|
|
|
|
stf = safe_tarfile.open(tarname)
|
|
|
|
# If we have data_filter, we have a patched python to address
|
|
# CVE-2007-4559.
|
|
if hasattr(tarfile, "data_filter"):
|
|
self.assertRaises((tarfile.OutsideDestinationError,
|
|
NotADirectoryError),
|
|
stf.extractall,
|
|
tarname)
|
|
else:
|
|
self.assertRaises(tarfile.ExtractError,
|
|
stf.extractall,
|
|
tarname)
|
|
self.rm_files('x', 'tar.tar')
|
|
|
|
def test_slash(self):
|
|
filename = os.path.join(self.tempdir, 'x')
|
|
tarname = os.path.join(self.tempdir, 'tar.tar')
|
|
f = open(filename, 'w')
|
|
f.write('x')
|
|
f.close()
|
|
|
|
tf = tarfile.open(tarname, 'w')
|
|
tf.add(filename, filter=filterer('/'))
|
|
tf.close()
|
|
|
|
stf = safe_tarfile.open(tarname)
|
|
|
|
# If 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')
|