From f534926b8914000db4c939fc7a111f0d35669b6a Mon Sep 17 00:00:00 2001 From: wk333 <13474090681@163.com> Date: Wed, 18 Jun 2025 15:10:13 +0800 Subject: [PATCH] Fix CVE-2025-4748 (cherry picked from commit 16bf5c16eb52ab906ef18036d7deac71f4bb4a36) --- CVE-2025-4748.patch | 142 ++++++++++++++++++++++++++++++++++++++++++++ erlang.spec | 6 +- 2 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 CVE-2025-4748.patch diff --git a/CVE-2025-4748.patch b/CVE-2025-4748.patch new file mode 100644 index 0000000..7b93e32 --- /dev/null +++ b/CVE-2025-4748.patch @@ -0,0 +1,142 @@ +From 10608879c81332af2d3c00db61ee173c93c1ea4e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Lukas=20Backstr=C3=B6m?= +Date: Tue, 27 May 2025 21:50:01 +0200 +Subject: [PATCH] stdlib: Properly sanatize filenames when (un)zipping + +Origin: https://github.com/erlang/otp/commit/10608879c81332af2d3c00db61ee173c93c1ea4e + +According to the Zip APPNOTE filenames "MUST NOT contain a drive or +device letter, or a leading slash.". So we strip those when zipping +and unzipping. +--- + lib/stdlib/src/zip.erl | 21 ++++++++++++++---- + lib/stdlib/test/zip_SUITE.erl | 40 ++++++++++++++++++++++++++++------- + 2 files changed, 49 insertions(+), 12 deletions(-) + +diff --git a/lib/stdlib/src/zip.erl b/lib/stdlib/src/zip.erl +index 0809dbb492b4..b75055024ca3 100644 +--- a/lib/stdlib/src/zip.erl ++++ b/lib/stdlib/src/zip.erl +@@ -833,12 +833,12 @@ get_filename({Name, _}, Type) -> + get_filename({Name, _, _}, Type) -> + get_filename(Name, Type); + get_filename(Name, regular) -> +- Name; ++ sanitize_filename(Name); + get_filename(Name, directory) -> + %% Ensure trailing slash + case lists:reverse(Name) of +- [$/ | _Rev] -> Name; +- Rev -> lists:reverse([$/ | Rev]) ++ [$/ | _Rev] -> sanitize_filename(Name); ++ Rev -> sanitize_filename(lists:reverse([$/ | Rev])) + end. + + add_cwd(_CWD, {_Name, _} = F) -> F; +@@ -1550,12 +1550,25 @@ check_dir_level([_Dir | Parts], Level) -> + get_file_name_extra(FileNameLen, ExtraLen, B, GPFlag) -> + try + <> = B, +- {binary_to_chars(BFileName, GPFlag), BExtra} ++ {sanitize_filename(binary_to_chars(BFileName, GPFlag)), BExtra} + catch + _:_ -> + throw(bad_file_header) + end. + ++sanitize_filename(Filename) -> ++ case filename:pathtype(Filename) of ++ relative -> Filename; ++ _ -> ++ %% With absolute or volumerelative, we drop the prefix and rejoin ++ %% the path to create a relative path ++ Relative = filename:join(tl(filename:split(Filename))), ++ error_logger:format("Illegal absolute path: ~ts, converting to ~ts~n", ++ [Filename, Relative]), ++ relative = filename:pathtype(Relative), ++ Relative ++ end. ++ + %% get compressed or stored data + get_z_data(?DEFLATED, In0, FileName, CompSize, Input, Output, OpO, Z) -> + ok = zlib:inflateInit(Z, -?MAX_WBITS), +diff --git a/lib/stdlib/test/zip_SUITE.erl b/lib/stdlib/test/zip_SUITE.erl +index 97e5c660dd96..1edf6c1067e7 100644 +--- a/lib/stdlib/test/zip_SUITE.erl ++++ b/lib/stdlib/test/zip_SUITE.erl +@@ -22,7 +22,7 @@ + -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, + init_per_group/2,end_per_group/2, borderline/1, atomic/1, + bad_zip/1, unzip_from_binary/1, unzip_to_binary/1, +- zip_to_binary/1, ++ zip_to_binary/1, sanitize_filenames/1, + unzip_options/1, zip_options/1, list_dir_options/1, aliases/1, + openzip_api/1, zip_api/1, open_leak/1, unzip_jar/1, + unzip_traversal_exploit/1, +@@ -40,7 +40,8 @@ all() -> + unzip_to_binary, zip_to_binary, unzip_options, + zip_options, list_dir_options, aliases, openzip_api, + zip_api, open_leak, unzip_jar, compress_control, foldl, +- unzip_traversal_exploit,fd_leak,unicode,test_zip_dir]. ++ unzip_traversal_exploit,fd_leak,unicode,test_zip_dir, ++ sanitize_filenames]. + + groups() -> + []. +@@ -90,22 +91,27 @@ borderline_test(Size, TempDir) -> + {ok, Archive} = zip:zip(Archive, [Name]), + ok = file:delete(Name), + ++ RelName = filename:join(tl(filename:split(Name))), ++ + %% Verify listing and extracting. + {ok, [#zip_comment{comment = []}, +- #zip_file{name = Name, ++ #zip_file{name = RelName, + info = Info, + offset = 0, + comp_size = _}]} = zip:list_dir(Archive), + Size = Info#file_info.size, +- {ok, [Name]} = zip:extract(Archive, [verbose]), ++ TempRelName = filename:join(TempDir, RelName), ++ {ok, [TempRelName]} = zip:extract(Archive, [verbose, {cwd, TempDir}]), + +- %% Verify contents of extracted file. +- {ok, Bin} = file:read_file(Name), +- true = match_byte_list(X0, binary_to_list(Bin)), ++ %% Verify that absolute file was not created ++ {error, enoent} = file:read_file(Name), + ++ %% Verify that relative contents of extracted file. ++ {ok, Bin} = file:read_file(TempRelName), ++ true = match_byte_list(X0, binary_to_list(Bin)), + + %% Verify that Unix zip can read it. (if we have a unix zip that is!) +- zipinfo_match(Archive, Name), ++ zipinfo_match(Archive, RelName), + + ok. + +@@ -1054,3 +1060,21 @@ run_command(Command, Args) -> + end + end)(). + ++sanitize_filenames(Config) -> ++ RootDir = proplists:get_value(priv_dir, Config), ++ TempDir = filename:join(RootDir, "borderline"), ++ ok = file:make_dir(TempDir), ++ ++ %% Create a zip archive /tmp/absolute in it ++ %% This file was created using the command below on Erlang/OTP 28.0 ++ %% 1> rr(file), {ok, {_, Bin}} = zip:zip("absolute.zip", [{"/tmp/absolute",<<>>,#file_info{ type=regular, mtime={{1970,1,1},{0,0,0}}, size=0 }}], [memory]), rp(base64:encode(Bin)). ++ AbsZip = base64:decode(<<"UEsDBBQAAAAAAAAAIewAAAAAAAAAAAAAAAANAAAAL3RtcC9hYnNvbHV0ZVBLAQIUAxQAAAAAAAAAIewAAAAAAAAAAAAAAAANAAAAAAAAAAAAAACkAQAAAAAvdG1wL2Fic29sdXRlUEsFBgAAAAABAAEAOwAAACsAAAAAAA==">>), ++ Archive = filename:join(TempDir, "absolute.zip"), ++ ok = file:write_file(Archive, AbsZip), ++ ++ TmpAbs = filename:join([TempDir, "tmp", "absolute"]), ++ {ok, [TmpAbs]} = zip:unzip(Archive, [verbose, {cwd, TempDir}]), ++ {error, enoent} = file:read_file("/tmp/absolute"), ++ {ok, <<>>} = file:read_file(TmpAbs), ++ ++ ok. +\ No newline at end of file diff --git a/erlang.spec b/erlang.spec index 556197b..b9a1836 100644 --- a/erlang.spec +++ b/erlang.spec @@ -10,7 +10,7 @@ %global __with_sources 1 Name: erlang Version: 25.3.2.6 -Release: 7 +Release: 8 Summary: General-purpose programming language and runtime environment License: Apache-2.0 URL: https://www.erlang.org @@ -42,6 +42,7 @@ Patch19: CVE-2025-32433.patch Patch20: CVE-2025-46712-pre-ssh-reduce-KEX-strict-message-verbosity.patch Patch21: CVE-2025-46712-1.patch Patch22: CVE-2025-46712-2.patch +Patch23: CVE-2025-4748.patch BuildRequires: gcc gcc-c++ flex make %if %{with doc} @@ -1764,6 +1765,9 @@ useradd -r -g epmd -d /dev/null -s /sbin/nologin \ %endif %changelog +* Wed Jun 18 2025 wangkai <13474090681@163.com> - 25.3.2.6-8 +- Fix CVE-2025-4748 + * Fri May 09 2025 yaoxin <1024769339@qq.com> - 25.3.2.6-7 - Fix CVE-2025-46712 -- Gitee