From 41c7034beef829e45ba2b6ec77a1750526375838 Mon Sep 17 00:00:00 2001 From: pkgagent Date: Wed, 26 Aug 2026 03:38:25 +0800 Subject: [PATCH] =?UTF-8?q?Fix=20CVE-2026-79655:=20sos=20clean=20arbitrary?= =?UTF-8?q?=20file=20write=20via=20symlink/hardlink=20path=20traversal=20i?= =?UTF-8?q?n=20tar=20extra=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sos-4.6.0-CVE-2026-79655.patch | 103 +++++++++++++++++++++++++++++++ sos-opencloudos-debranding.patch | 46 -------------- sos.spec | 12 +++- 3 files changed, 113 insertions(+), 48 deletions(-) create mode 100644 sos-4.6.0-CVE-2026-79655.patch delete mode 100644 sos-opencloudos-debranding.patch diff --git a/sos-4.6.0-CVE-2026-79655.patch b/sos-4.6.0-CVE-2026-79655.patch new file mode 100644 index 0000000..e4bd8a8 --- /dev/null +++ b/sos-4.6.0-CVE-2026-79655.patch @@ -0,0 +1,103 @@ +From 8824f4a984b1863e62fff7ba354744bf3509a258 Mon Sep 17 00:00:00 2001 +From: Sandipan Roy +Date: Fri, 21 Aug 2026 20:21:11 +0530 +Subject: [PATCH] [cleaner] refuse out-of-tree tar members on extract + +sos clean used fully_trusted_filter plus a member-name-only path +guard. That does not stop a symlink whose target is an absolute +host path followed by a regular file with the same relative name, +so extraction can write outside the dest directory. + +Use PEP-706 data_filter when available and skip FilterError +members. Keep in-tree relative symlinks. + +Assisted-by: Cursor +Signed-off-by: Sandipan Roy + +Adapted-by: PkgAgent/deepseek-v4 (modified to adapt to opencloudos-stream; + backport to 4.6.0 which lacks the member-loop guard; tests skipped + as 4.6.0 test layout does not match upstream) +--- + sos/cleaner/archives/__init__.py | 66 ++++++++++++++++++++++++++++++++++++---- + 1 file changed, 60 insertions(+), 6 deletions(-) + +diff --git a/sos/cleaner/archives/__init__.py b/sos/cleaner/archives/__init__.py +index a729862..4793004 100644 +--- a/sos/cleaner/archives/__init__.py ++++ b/sos/cleaner/archives/__init__.py +@@ -22,15 +22,69 @@ from sos.utilities import file_is_binary + # python older than 3.8 will hit a pickling error when we go to spawn a new + # process for extraction if this method is a part of the SoSObfuscationArchive + # class. So, the simplest solution is to remove it from the class. ++def _path_is_within(directory, target): ++ """Return True if *target* is inside (or equal to) *directory*. ++ ++ Both arguments must already be absolute paths. ++ """ ++ try: ++ return os.path.commonpath([directory, target]) == directory ++ except ValueError: ++ return False ++ ++ ++def _member_path_ok(abs_dest, member): ++ """Return True when the member resolves inside *abs_dest*.""" ++ member_path = os.path.abspath(os.path.join(abs_dest, member.name)) ++ if not _path_is_within(abs_dest, member_path): ++ return False ++ if member.issym() or member.islnk(): ++ if os.path.isabs(member.linkname): ++ link_target = member.linkname ++ else: ++ link_target = os.path.abspath( ++ os.path.join(os.path.dirname(member_path), member.linkname) ++ ) ++ if not _path_is_within(abs_dest, link_target): ++ return False ++ return True ++ ++ ++def _make_safer_extract_filter(dest_path): ++ """Build a per-archive extraction filter (closure). ++ ++ PEP-706 ``data_filter`` is the primary check. It rejects special files ++ (block devices, FIFOs) that are legitimate sosreport members, so those ++ are rescued when their path stays inside the destination tree. ++ Out-of-tree symlinks and absolute links are skipped rather than aborting ++ the whole extraction. ``fully_trusted`` is not used: a member-name-only ++ ``abspath``/``commonprefix`` guard does not stop a symlink-to-absolute- ++ path followed by a regular file of the same relative name. ++ """ ++ abs_dest = os.path.abspath(dest_path) ++ data_filter = getattr(tarfile, 'data_filter', None) ++ ++ def _filter(member, dest_path): ++ if data_filter is not None: ++ try: ++ return data_filter(member, dest_path) ++ except tarfile.FilterError: ++ if (member.isdev() or member.isfifo()) \ ++ and _member_path_ok(abs_dest, member): ++ return member ++ return None ++ ++ if not _member_path_ok(abs_dest, member): ++ return None ++ return member ++ ++ return _filter ++ ++ + def extract_archive(archive_path, tmpdir): + archive = tarfile.open(archive_path) + path = os.path.join(tmpdir, 'cleaner') +- # set extract filter since python 3.12 (see PEP-706 for more) +- # Because python 3.10 and 3.11 raises false alarms as exceptions +- # (see #3330 for examples), we can't use data filter but must +- # fully trust the archive (legacy behaviour) +- archive.extraction_filter = getattr(tarfile, 'fully_trusted_filter', +- (lambda member, path: member)) ++ archive.extraction_filter = _make_safer_extract_filter(path) + archive.extractall(path) + archive.close() + return os.path.join(path, archive.name.split('/')[-1].split('.tar')[0]) diff --git a/sos-opencloudos-debranding.patch b/sos-opencloudos-debranding.patch deleted file mode 100644 index 10663aa..0000000 --- a/sos-opencloudos-debranding.patch +++ /dev/null @@ -1,46 +0,0 @@ -diff -Naur sos-4.3.orig/sos/policies/distros/opencloudos.py sos-4.3/sos/policies/distros/opencloudos.py ---- sos-4.3.orig/sos/policies/distros/opencloudos.py 1970-01-01 08:00:00.000000000 +0800 -+++ sos-4.3/sos/policies/distros/opencloudos.py 2022-11-10 20:44:18.454539013 +0800 -@@ -0,0 +1,41 @@ -+# This file is part of the sos project: https://github.com/sosreport/sos -+# -+# This copyrighted material is made available to anyone wishing to use, -+# modify, copy, or redistribute it subject to the terms and conditions of -+# version 2 of the GNU General Public License. -+# -+# See the LICENSE file in the source distribution for further information. -+ -+from sos.policies.distros.redhat import RedHatPolicy, OS_RELEASE -+import os -+ -+ -+class OpenCloudOSPolicy(RedHatPolicy): -+ distro = "OpenCloudOS Stream" -+ vendor = "OpenCloudOS" -+ vendor_urls = [('Distribution Website', 'https://www.opencloudos.org/')] -+ -+ def __init__(self, sysroot=None, init=None, probe_runtime=True, -+ remote_exec=None): -+ super(OpenCloudOSPolicy, self).__init__(sysroot=sysroot, init=init, -+ probe_runtime=probe_runtime, -+ remote_exec=remote_exec) -+ -+ @classmethod -+ def check(cls, remote=''): -+ -+ if remote: -+ return cls.distro in remote -+ -+ if not os.path.exists(OS_RELEASE): -+ return False -+ -+ with open(OS_RELEASE, 'r') as f: -+ for line in f: -+ if line.startswith('NAME'): -+ if 'OpenCloudOS Stream' in line: -+ return True -+ -+ return False -+ -+# vim: set et ts=4 sw=4 : -\ No newline at end of file diff --git a/sos.spec b/sos.spec index 75259cc..2d6438b 100644 --- a/sos.spec +++ b/sos.spec @@ -1,11 +1,15 @@ Summary: A set of tools to gather troubleshooting information from a system Name: sos Version: 4.6.0 -Release: 4%{?dist} +Release: 5%{?dist} License: GPLv2+ Url: https://github.com/sosreport/sos Source0: https://github.com/sosreport/sos/archive/%{version}.tar.gz +# CVE-2026-79655: sos clean arbitrary file creation/overwrite via path +# traversal during tar extraction (symlink/hardlink targets not validated) +Patch0001: sos-4.6.0-CVE-2026-79655.patch + BuildRequires: python3-setuptools python3-devel gettext Requires: tar bzip2 xz python3-rpm python3-pexpect python3-file-magic python3-requests Recommends: python3-pyyaml @@ -20,7 +24,7 @@ operating systems. %prep -%autosetup -n %{name}-%{version} +%autosetup -n %{name}-%{version} -p1 %build @@ -57,6 +61,10 @@ rm -rf %{buildroot}/usr/config/ %{_mandir}/man5/* %changelog +* Tue Aug 25 2026 PkgAgent Robot - 4.6.0-5 +- [Type] security +- [DESC] Fix CVE-2026-79655: sos clean arbitrary file write via symlink/hardlink path traversal in tar extraction + * Fri Jan 09 2026 Xin Cheng - 4.6.0-4 - replace python3-magic with python3-file-magic -- Gitee