Control: tags 1127782 + patch Control: tags 1127782 + pending Dear maintainer,
I've prepared an NMU for busybox (versioned as 1:1.37.0-10.1) and uploaded it to DELAYED/2. Please feel free to tell me if I should cancel it. cu Adrian
diffstat for busybox-1.37.0 busybox-1.37.0 changelog | 11 patches/0001-tar-strip-unsafe-hardlink-components-GNU-tar-does-th.patch | 193 ++++++++++ patches/0002-tar-only-strip-unsafe-components-from-hardlinks-not-.patch | 31 + patches/series | 2 4 files changed, 237 insertions(+) diff -Nru busybox-1.37.0/debian/changelog busybox-1.37.0/debian/changelog --- busybox-1.37.0/debian/changelog 2026-02-02 10:25:51.000000000 +0200 +++ busybox-1.37.0/debian/changelog 2026-03-04 19:42:01.000000000 +0200 @@ -1,3 +1,14 @@ +busybox (1:1.37.0-10.1) unstable; urgency=medium + + * Non-maintainer upload. + * CVE-2026-26157: Incomplete path sanitization in archive + extraction utilities + * CVE-2026-26158: File modification outside of the intended + extraction directory in tar + * (Closes: #1127782) + + -- Adrian Bunk <[email protected]> Wed, 04 Mar 2026 19:42:01 +0200 + busybox (1:1.37.0-10) unstable; urgency=medium * Revert "initramfs-tools/conf-hooks.d/busybox: diff -Nru busybox-1.37.0/debian/patches/0001-tar-strip-unsafe-hardlink-components-GNU-tar-does-th.patch busybox-1.37.0/debian/patches/0001-tar-strip-unsafe-hardlink-components-GNU-tar-does-th.patch --- busybox-1.37.0/debian/patches/0001-tar-strip-unsafe-hardlink-components-GNU-tar-does-th.patch 1970-01-01 02:00:00.000000000 +0200 +++ busybox-1.37.0/debian/patches/0001-tar-strip-unsafe-hardlink-components-GNU-tar-does-th.patch 2026-03-04 19:33:51.000000000 +0200 @@ -0,0 +1,193 @@ +From 0c20d6b353b058ab910dd3a0211e2b906802b105 Mon Sep 17 00:00:00 2001 +From: Denys Vlasenko <[email protected]> +Date: Thu, 29 Jan 2026 11:48:02 +0100 +Subject: tar: strip unsafe hardlink components - GNU tar does the same + +Defends against files like these (python reproducer): + +import tarfile +ti = tarfile.TarInfo("leak_hosts") +ti.type = tarfile.LNKTYPE +ti.linkname = "/etc/hosts" # or "../etc/hosts" or ".." +ti.size = 0 +with tarfile.open("/tmp/hardlink.tar", "w") as t: + t.addfile(ti) + +function old new delta +skip_unsafe_prefix - 127 +127 +get_header_tar 1752 1754 +2 +.rodata 106861 106856 -5 +unzip_main 2715 2706 -9 +strip_unsafe_prefix 102 18 -84 +------------------------------------------------------------------------------ +(add/remove: 1/0 grow/shrink: 1/3 up/down: 129/-98) Total: 31 bytes + +Signed-off-by: Denys Vlasenko <[email protected]> +--- + archival/libarchive/data_extract_all.c | 7 +++-- + archival/libarchive/get_header_tar.c | 11 ++++++-- + archival/libarchive/unsafe_prefix.c | 30 +++++++++++++++++---- + archival/libarchive/unsafe_symlink_target.c | 1 + + archival/tar.c | 2 +- + archival/unzip.c | 2 +- + include/bb_archive.h | 3 ++- + 7 files changed, 42 insertions(+), 14 deletions(-) + +diff --git a/archival/libarchive/data_extract_all.c b/archival/libarchive/data_extract_all.c +index 8a69711c1..b84b960c4 100644 +--- a/archival/libarchive/data_extract_all.c ++++ b/archival/libarchive/data_extract_all.c +@@ -66,8 +66,8 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) + } + #endif + #if ENABLE_FEATURE_PATH_TRAVERSAL_PROTECTION +- /* Strip leading "/" and up to last "/../" path component */ +- dst_name = (char *)strip_unsafe_prefix(dst_name); ++ /* Skip leading "/" and past last ".." path component */ ++ dst_name = (char *)skip_unsafe_prefix(dst_name); + #endif + // ^^^ This may be a problem if some applets do need to extract absolute names. + // (Probably will need to invent ARCHIVE_ALLOW_UNSAFE_NAME flag). +@@ -185,8 +185,7 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) + + /* To avoid a directory traversal attack via symlinks, + * do not restore symlinks with ".." components +- * or symlinks starting with "/", unless a magic +- * envvar is set. ++ * or symlinks starting with "/" + * + * For example, consider a .tar created via: + * $ tar cvf bug.tar anything.txt +diff --git a/archival/libarchive/get_header_tar.c b/archival/libarchive/get_header_tar.c +index cc6f3f0ad..1c40ecedb 100644 +--- a/archival/libarchive/get_header_tar.c ++++ b/archival/libarchive/get_header_tar.c +@@ -454,8 +454,15 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) + #endif + + /* Everything up to and including last ".." component is stripped */ +- overlapping_strcpy(file_header->name, strip_unsafe_prefix(file_header->name)); +-//TODO: do the same for file_header->link_target? ++ strip_unsafe_prefix(file_header->name); ++ if (file_header->link_target) { ++ /* GNU tar 1.34 examples: ++ * tar: Removing leading '/' from hard link targets ++ * tar: Removing leading '../' from hard link targets ++ * tar: Removing leading 'etc/../' from hard link targets ++ */ ++ strip_unsafe_prefix(file_header->link_target); ++ } + + /* Strip trailing '/' in directories */ + /* Must be done after mode is set as '/' is used to check if it's a directory */ +diff --git a/archival/libarchive/unsafe_prefix.c b/archival/libarchive/unsafe_prefix.c +index 667081195..89a371a7f 100644 +--- a/archival/libarchive/unsafe_prefix.c ++++ b/archival/libarchive/unsafe_prefix.c +@@ -5,11 +5,11 @@ + #include "libbb.h" + #include "bb_archive.h" + +-const char* FAST_FUNC strip_unsafe_prefix(const char *str) ++const char* FAST_FUNC skip_unsafe_prefix(const char *str) + { + const char *cp = str; + while (1) { +- char *cp2; ++ const char *cp2; + if (*cp == '/') { + cp++; + continue; +@@ -22,10 +22,25 @@ const char* FAST_FUNC strip_unsafe_prefix(const char *str) + cp += 3; + continue; + } +- cp2 = strstr(cp, "/../"); ++ cp2 = cp; ++ find_dotdot: ++ cp2 = strstr(cp2, "/.."); + if (!cp2) +- break; +- cp = cp2 + 4; ++ break; /* No (more) malicious components */ ++ ++ /* We found "/..something" */ ++ cp2 += 3; ++ if (*cp2 != '/') { ++ if (*cp2 == '\0') { ++ /* Trailing "/..": malicious, return "" */ ++ /* (causes harmless errors trying to create or hardlink a file named "") */ ++ return cp2; ++ } ++ /* "/..name" is not malicious, look for next "/.." */ ++ goto find_dotdot; ++ } ++ /* Found "/../": malicious, advance past it */ ++ cp = cp2 + 1; + } + if (cp != str) { + static smallint warned = 0; +@@ -37,3 +52,8 @@ const char* FAST_FUNC strip_unsafe_prefix(const char *str) + } + return cp; + } ++ ++void FAST_FUNC strip_unsafe_prefix(char *str) ++{ ++ overlapping_strcpy(str, skip_unsafe_prefix(str)); ++} +diff --git a/archival/libarchive/unsafe_symlink_target.c b/archival/libarchive/unsafe_symlink_target.c +index f8dc8033d..d764c89ab 100644 +--- a/archival/libarchive/unsafe_symlink_target.c ++++ b/archival/libarchive/unsafe_symlink_target.c +@@ -36,6 +36,7 @@ void FAST_FUNC create_links_from_list(llist_t *list) + *list->data ? "hard" : "sym", + list->data + 1, target + ); ++ /* Note: GNU tar 1.34 errors out only _after_ all links are (attempted to be) created */ + } + list = list->link; + } +diff --git a/archival/tar.c b/archival/tar.c +index d6ca6c1e0..d42dcfc26 100644 +--- a/archival/tar.c ++++ b/archival/tar.c +@@ -475,7 +475,7 @@ static int FAST_FUNC writeFileToTarball(struct recursive_state *state, + DBG("writeFileToTarball('%s')", fileName); + + /* Strip leading '/' and such (must be before memorizing hardlink's name) */ +- header_name = strip_unsafe_prefix(fileName); ++ header_name = skip_unsafe_prefix(fileName); + + if (header_name[0] == '\0') + return TRUE; +diff --git a/archival/unzip.c b/archival/unzip.c +index 71a302915..8a9a90f7d 100644 +--- a/archival/unzip.c ++++ b/archival/unzip.c +@@ -860,7 +860,7 @@ int unzip_main(int argc, char **argv) + + /* Guard against "/abspath", "/../" and similar attacks */ + // NB: UnZip 6.00 has option -: to disable this +- overlapping_strcpy(dst_fn, strip_unsafe_prefix(dst_fn)); ++ strip_unsafe_prefix(dst_fn); + + /* Filter zip entries */ + if (find_list_entry(zreject, dst_fn) +diff --git a/include/bb_archive.h b/include/bb_archive.h +index e0ef8fc4e..1dc77f31d 100644 +--- a/include/bb_archive.h ++++ b/include/bb_archive.h +@@ -202,7 +202,8 @@ char get_header_tar_xz(archive_handle_t *archive_handle) FAST_FUNC; + void seek_by_jump(int fd, off_t amount) FAST_FUNC; + void seek_by_read(int fd, off_t amount) FAST_FUNC; + +-const char *strip_unsafe_prefix(const char *str) FAST_FUNC; ++const char *skip_unsafe_prefix(const char *str) FAST_FUNC; ++void strip_unsafe_prefix(char *str) FAST_FUNC; + void create_or_remember_link(llist_t **link_placeholders, + const char *target, + const char *linkname, +-- +2.47.3 + diff -Nru busybox-1.37.0/debian/patches/0002-tar-only-strip-unsafe-components-from-hardlinks-not-.patch busybox-1.37.0/debian/patches/0002-tar-only-strip-unsafe-components-from-hardlinks-not-.patch --- busybox-1.37.0/debian/patches/0002-tar-only-strip-unsafe-components-from-hardlinks-not-.patch 1970-01-01 02:00:00.000000000 +0200 +++ busybox-1.37.0/debian/patches/0002-tar-only-strip-unsafe-components-from-hardlinks-not-.patch 2026-03-04 19:33:51.000000000 +0200 @@ -0,0 +1,31 @@ +From 038e0e4d791ea4e8a8da5e06904756142fc6b8dc Mon Sep 17 00:00:00 2001 +From: Radoslav Kolev <[email protected]> +Date: Mon, 16 Feb 2026 11:50:04 +0200 +Subject: tar: only strip unsafe components from hardlinks, not symlinks + +commit 3fb6b31c7 introduced a check for unsafe components in +tar archive hardlinks, but it was being applied to symlinks too +which broke "Symlinks and hardlinks coexist" tar test. + +Signed-off-by: Radoslav Kolev <[email protected]> +Signed-off-by: Denys Vlasenko <[email protected]> +--- + archival/libarchive/get_header_tar.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/archival/libarchive/get_header_tar.c b/archival/libarchive/get_header_tar.c +index 1c40ecedb..606d8067f 100644 +--- a/archival/libarchive/get_header_tar.c ++++ b/archival/libarchive/get_header_tar.c +@@ -455,7 +455,7 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) + + /* Everything up to and including last ".." component is stripped */ + strip_unsafe_prefix(file_header->name); +- if (file_header->link_target) { ++ if (file_header->link_target && !S_ISLNK(file_header->mode)) { + /* GNU tar 1.34 examples: + * tar: Removing leading '/' from hard link targets + * tar: Removing leading '../' from hard link targets +-- +2.47.3 + diff -Nru busybox-1.37.0/debian/patches/series busybox-1.37.0/debian/patches/series --- busybox-1.37.0/debian/patches/series 2026-02-01 19:00:00.000000000 +0200 +++ busybox-1.37.0/debian/patches/series 2026-03-04 19:41:59.000000000 +0200 @@ -26,3 +26,5 @@ archival-libarchive-sanitize-filenames-on-output-CVE-2025-46394.patch archival-libarchive-sanitize-filenames-on-output-CVE-2025-46394-2.patch netstat-sanitize-argv0-for-p-CVE-2024-58251.patch +0001-tar-strip-unsafe-hardlink-components-GNU-tar-does-th.patch +0002-tar-only-strip-unsafe-components-from-hardlinks-not-.patch

