diff --git a/backport-0001-CVE-2025-10230.patch b/backport-0001-CVE-2025-10230.patch new file mode 100644 index 0000000000000000000000000000000000000000..2e39008c9b9ffe8acd49aa9598afcefc0c97ee94 --- /dev/null +++ b/backport-0001-CVE-2025-10230.patch @@ -0,0 +1,290 @@ +From b1b1a8235f52160cf9a02ad92b346084c48095fc Mon Sep 17 00:00:00 2001 +From: Douglas Bagnall +Date: Tue, 9 Sep 2025 13:36:16 +1200 +Subject: [PATCH 1/2] CVE-2025-10230: s4/tests: check that wins hook sanitizes + names + +An smb.conf can contain a 'wins hook' parameter, which names a script +to run when a WINS name is changed. The man page says + + The second argument is the NetBIOS name. If the name is not a + legal name then the wins hook is not called. Legal names contain + only letters, digits, hyphens, underscores and periods. + +but it turns out the legality check is not performed if the WINS +server in question is the source4 nbt one. It is not expected that +people will run this server, but they can. This is bad because the +name is passed unescaped into a shell command line, allowing command +injection. + +For this test we don't care whether the WINS server is returning an +error code, just whether it is running the wins hook. The tests show +it often runs the hook it shouldn't, though some characters are +incidentally blocked because the name has to fit in a DN before it +gets to the hook, and DNs have a few syntactic restrictions (e.g., +blocking '<', '>', and ';'). + +The source3 WINS server that is used by Samba when not run as a DC is +not affected and not here tested. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15903 + +Signed-off-by: Douglas Bagnall +Reviewed-by: Gary Lockyer + +Conflict: selftest/target/Samba4.pm context adapt +Reference: http://attachments.samba.org/attachment.cgi?id=18744 +--- + python/samba/tests/usage.py | 2 + + .../samba4.nbt.wins.wins_bad_names | 1 + + selftest/target/Samba4.pm | 1 + + source4/torture/nbt/wins.c | 136 +++++++++++++++++- + testprogs/blackbox/wins_hook_test | 15 ++ + 5 files changed, 152 insertions(+), 3 deletions(-) + create mode 100644 selftest/knownfail.d/samba4.nbt.wins.wins_bad_names + create mode 100755 testprogs/blackbox/wins_hook_test + +diff --git a/python/samba/tests/usage.py b/python/samba/tests/usage.py +index 3312bfe3746..afee5a5ebcd 100644 +--- a/python/samba/tests/usage.py ++++ b/python/samba/tests/usage.py +@@ -73,6 +73,7 @@ EXCLUDE_USAGE = { + 'lib/ldb/tests/python/api.py', + 'source4/selftest/tests.py', + 'buildtools/bin/waf', ++ 'testprogs/blackbox/wins_hook_test', + 'selftest/tap2subunit', + 'script/show_test_time', + 'source4/scripting/bin/subunitrun', +@@ -89,6 +90,7 @@ EXCLUDE_HELP = { + 'selftest/tap2subunit', + 'wintest/test-s3.py', + 'wintest/test-s4-howto.py', ++ 'testprogs/blackbox/wins_hook_test', + } + + +diff --git a/selftest/knownfail.d/samba4.nbt.wins.wins_bad_names b/selftest/knownfail.d/samba4.nbt.wins.wins_bad_names +new file mode 100644 +index 00000000000..52388ce5749 +--- /dev/null ++++ b/selftest/knownfail.d/samba4.nbt.wins.wins_bad_names +@@ -0,0 +1 @@ ++samba4.nbt.wins.wins_bad_names +diff --git a/selftest/target/Samba4.pm b/selftest/target/Samba4.pm +index e917f65fc36..110f4c5072b 100755 +--- a/selftest/target/Samba4.pm ++++ b/selftest/target/Samba4.pm +@@ -1628,6 +1628,7 @@ sub provision_ad_dc_ntvfs($$$) + ldap server require strong auth = allow_sasl_over_tls + raw NTLMv2 auth = yes + lsa over netlogon = yes ++ wins hook = $ENV{SRCDIR_ABS}/testprogs/blackbox/wins_hook_test + rpc server port = 1027 + auth event notification = true + dsdb event notification = true +diff --git a/source4/torture/nbt/wins.c b/source4/torture/nbt/wins.c +index 8c847b5ac50..7d7321752d6 100644 +--- a/source4/torture/nbt/wins.c ++++ b/source4/torture/nbt/wins.c +@@ -31,6 +31,10 @@ + #include "torture/nbt/proto.h" + #include "param/param.h" + ++/* rcode used when you don't want to check the rcode */ ++#define WINS_TEST_RCODE_WE_DONT_CARE 255 ++ ++ + #define CHECK_VALUE(tctx, v, correct) \ + torture_assert_int_equal(tctx, v, correct, "Incorrect value") + +@@ -137,7 +141,9 @@ static bool nbt_test_wins_name(struct torture_context *tctx, const char *address + address)); + + CHECK_STRING(tctx, io.out.wins_server, address); +- CHECK_VALUE(tctx, io.out.rcode, 0); ++ if (register_rcode != WINS_TEST_RCODE_WE_DONT_CARE) { ++ CHECK_VALUE(tctx, io.out.rcode, 0); ++ } + + torture_comment(tctx, "register the name correct address\n"); + name_register.in.name = *name; +@@ -185,7 +191,9 @@ static bool nbt_test_wins_name(struct torture_context *tctx, const char *address + talloc_asprintf(tctx, "Bad response from %s for name register\n", + address)); + +- CHECK_VALUE(tctx, name_register.out.rcode, 0); ++ if (register_rcode != WINS_TEST_RCODE_WE_DONT_CARE) { ++ CHECK_VALUE(tctx, name_register.out.rcode, 0); ++ } + CHECK_STRING(tctx, name_register.out.reply_addr, myaddress); + } + +@@ -203,7 +211,9 @@ static bool nbt_test_wins_name(struct torture_context *tctx, const char *address + torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "Bad response from %s for name register", address)); + + CHECK_STRING(tctx, io.out.wins_server, address); +- CHECK_VALUE(tctx, io.out.rcode, register_rcode); ++ if (register_rcode != WINS_TEST_RCODE_WE_DONT_CARE) { ++ CHECK_VALUE(tctx, io.out.rcode, register_rcode); ++ } + + if (register_rcode != NBT_RCODE_OK) { + return true; +@@ -532,6 +542,124 @@ static bool nbt_test_wins(struct torture_context *tctx) + return ret; + } + ++/* ++ * Test that the WINS server does not call 'wins hook' when the name ++ * contains dodgy characters. ++ */ ++static bool nbt_test_wins_bad_names(struct torture_context *tctx) ++{ ++ const char *address = NULL; ++ const char *wins_hook_file = NULL; ++ bool ret = true; ++ int err; ++ bool ok; ++ struct nbt_name name = {}; ++ size_t i, j; ++ FILE *fh = NULL; ++ ++ struct { ++ const char *name; ++ bool should_succeed; ++ } test_cases[] = { ++ {"NORMAL", true}, ++ {"|look|", false}, ++ {"look&true", false}, ++ {"look\\;false", false}, ++ {"&ls>foo", false}, /* already fails due to DN syntax */ ++ {"has spaces", false}, ++ {"hyphen-dot.0", true}, ++ }; ++ ++ wins_hook_file = talloc_asprintf(tctx, "%s/wins_hook_writes_here", ++ getenv("SELFTEST_TMPDIR")); ++ ++ if (!torture_nbt_get_name(tctx, &name, &address)) { ++ return false; ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(test_cases); i++) { ++ err = unlink(wins_hook_file); ++ if (err != 0 && errno != ENOENT) { ++ /* we expect ENOENT, but nothing else */ ++ torture_comment(tctx, ++ "unlink %zu of '%s' failed\n", ++ i, wins_hook_file); ++ } ++ ++ name.name = test_cases[i].name; ++ name.type = NBT_NAME_CLIENT; ++ ok = nbt_test_wins_name(tctx, address, ++ &name, ++ NBT_NODE_H, ++ true, ++ WINS_TEST_RCODE_WE_DONT_CARE ++ ); ++ if (ok == false) { ++ /* ++ * This happens when the name interferes with ++ * the DN syntax when it is put in winsdb. ++ * ++ * The wins hook will not be reached. ++ */ ++ torture_comment(tctx, "tests for '%s' failed\n", ++ name.name); ++ } ++ ++ /* ++ * poll for the file being created by the wins hook. ++ */ ++ for (j = 0; j < 10; j++) { ++ usleep(200000); ++ fh = fopen(wins_hook_file, "r"); ++ if (fh != NULL) { ++ break; ++ } ++ } ++ ++ if (fh == NULL) { ++ if (errno == ENOENT) { ++ if (test_cases[i].should_succeed) { ++ torture_comment( ++ tctx, ++ "wins hook for '%s' failed\n", ++ test_cases[i].name); ++ ret = false; ++ } ++ } else { ++ torture_comment( ++ tctx, ++ "wins hook for '%s' unexpectedly failed with %d\n", ++ test_cases[i].name, ++ errno); ++ ret = false; ++ } ++ } else { ++ char readback[17] = {0}; ++ size_t n = fread(readback, 1, 16, fh); ++ torture_comment(tctx, ++ "wins hook wrote '%s' read '%.*s'\n", ++ test_cases[i].name, ++ (int)n, readback); ++ ++ if (! test_cases[i].should_succeed) { ++ torture_comment(tctx, ++ "wins hook for '%s' should fail\n", ++ test_cases[i].name); ++ ret = false; ++ } ++ fclose(fh); ++ } ++ } ++ err = unlink(wins_hook_file); ++ if (err != 0 && errno != ENOENT) { ++ torture_comment(tctx, "final unlink of '%s' failed\n", ++ wins_hook_file); ++ } ++ torture_assert(tctx, ret, "wins hook failure\n"); ++ return ret; ++} ++ ++ + /* + test WINS operations + */ +@@ -540,6 +668,8 @@ struct torture_suite *torture_nbt_wins(TALLOC_CTX *mem_ctx) + struct torture_suite *suite = torture_suite_create(mem_ctx, "wins"); + + torture_suite_add_simple_test(suite, "wins", nbt_test_wins); ++ torture_suite_add_simple_test(suite, "wins_bad_names", ++ nbt_test_wins_bad_names); + + return suite; + } +diff --git a/testprogs/blackbox/wins_hook_test b/testprogs/blackbox/wins_hook_test +new file mode 100755 +index 00000000000..f15379c28ca +--- /dev/null ++++ b/testprogs/blackbox/wins_hook_test +@@ -0,0 +1,15 @@ ++#!/usr/bin/python3 ++ ++import os ++import sys ++ ++filename = f"{os.environ['SELFTEST_TMPDIR']}/wins_hook_writes_here" ++ ++f = open(filename, 'wb') ++ ++# Some names may truncate argv (e.g. '&'), for which we leave the file ++# empty. ++if len(sys.argv) > 2: ++ f.write(os.fsencode(sys.argv[2])) ++ ++f.close() +-- +2.43.0 diff --git a/backport-0001-CVE-2025-9640.patch b/backport-0001-CVE-2025-9640.patch new file mode 100644 index 0000000000000000000000000000000000000000..360a02354938d5d1c00f300056f02e73de610c42 --- /dev/null +++ b/backport-0001-CVE-2025-9640.patch @@ -0,0 +1,290 @@ +From d015812736ef68bdff567587749af84e47ccd383 Mon Sep 17 00:00:00 2001 +From: Andrew Walker +Date: Thu, 28 Aug 2025 19:39:34 +0000 +Subject: [PATCH 1/2] CVE-2025-9640: Add torture test for inserting hole in + stream + +This commit adds an smb torture test for inserting a hole into +an alternate data stream and then verifying that hole contains +null bytes. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15885 + +Signed-off-by: Andrew Walker +Reviewed-by: Volker Lendecke + +Conflict: source4/torture/vfs/vfs.c context adapt +Reference: http://attachments.samba.org/attachment.cgi?id=18747 +--- + source3/selftest/tests.py | 3 + + source4/torture/vfs/streams_xattr.c | 211 ++++++++++++++++++++++++++++ + source4/torture/vfs/vfs.c | 1 + + source4/torture/wscript_build | 2 +- + 4 files changed, 216 insertions(+), 1 deletion(-) + create mode 100644 source4/torture/vfs/streams_xattr.c + +diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py +index 86d660800dc..039231e67b6 100755 +--- a/source3/selftest/tests.py ++++ b/source3/selftest/tests.py +@@ -1142,6 +1142,7 @@ nbt = ["nbt.dgram"] + vfs = [ + "vfs.fruit", + "vfs.acl_xattr", ++ "vfs.streams_xattr", + "vfs.fruit_netatalk", + "vfs.fruit_file_id", + "vfs.fruit_timemachine", +@@ -1337,6 +1338,8 @@ for t in tests: + plansmbtorture4testsuite(t, "fileserver", '//$SERVER_IP/tmp -U$USERNAME%$PASSWORD') + elif t == "vfs.acl_xattr": + plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/tmp -U$USERNAME%$PASSWORD') ++ elif t == "vfs.streams_xattr": ++ plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/vfs_wo_fruit -U$USERNAME%$PASSWORD') + elif t == "smb2.compound_find": + plansmbtorture4testsuite(t, "fileserver", '//$SERVER/compound_find -U$USERNAME%$PASSWORD') + plansmbtorture4testsuite(t, "fileserver", '//$SERVER_IP/tmp -U$USERNAME%$PASSWORD') +diff --git a/source4/torture/vfs/streams_xattr.c b/source4/torture/vfs/streams_xattr.c +new file mode 100644 +index 00000000000..0eb83e092e7 +--- /dev/null ++++ b/source4/torture/vfs/streams_xattr.c +@@ -0,0 +1,211 @@ ++/* ++ Unix SMB/CIFS implementation. ++ ++ Copyright (C) Andrew Walker (2025) ++ ++ 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 . ++*/ ++ ++#include "includes.h" ++#include "lib/cmdline/cmdline.h" ++#include "libcli/smb2/smb2.h" ++#include "libcli/smb2/smb2_calls.h" ++#include "libcli/smb/smbXcli_base.h" ++#include "torture/torture.h" ++#include "torture/vfs/proto.h" ++#include "libcli/resolve/resolve.h" ++#include "torture/util.h" ++#include "torture/smb2/proto.h" ++#include "lib/param/param.h" ++ ++#define BASEDIR "smb2-testads" ++ ++ ++static bool get_stream_handle(struct torture_context *tctx, ++ struct smb2_tree *tree, ++ const char *dname, ++ const char *fname, ++ const char *sname, ++ struct smb2_handle *hdl_in) ++{ ++ bool ret = true; ++ NTSTATUS status; ++ struct smb2_handle fhandle = {{0}}; ++ struct smb2_handle dhandle = {{0}}; ++ ++ torture_comment(tctx, "Create dir\n"); ++ ++ status = torture_smb2_testdir(tree, dname, &dhandle); ++ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir\n"); ++ ++ torture_comment(tctx, "Create file\n"); ++ ++ status = torture_smb2_testfile(tree, fname, &fhandle); ++ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testfile\n"); ++ ++ status = torture_smb2_testfile(tree, sname, hdl_in); ++ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testfile\n"); ++ ++done: ++ if (!smb2_util_handle_empty(fhandle)) { ++ smb2_util_close(tree, fhandle); ++ } ++ if (!smb2_util_handle_empty(dhandle)) { ++ smb2_util_close(tree, dhandle); ++ } ++ return ret; ++} ++ ++static bool read_stream(struct torture_context *tctx, ++ TALLOC_CTX *mem_ctx, ++ struct smb2_tree *tree, ++ struct smb2_handle *stream_hdl, ++ off_t read_offset, ++ size_t read_count, ++ char **data_out, ++ size_t *data_out_sz) ++{ ++ NTSTATUS status; ++ struct smb2_read r; ++ bool ret = true; ++ ++ ZERO_STRUCT(r); ++ r.in.file.handle = *stream_hdl; ++ r.in.length = read_count; ++ r.in.offset = read_offset; ++ ++ status = smb2_read(tree, mem_ctx, &r); ++ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "stream read\n"); ++ ++ *data_out = (char *)r.out.data.data; ++ *data_out_sz = r.out.data.length; ++ ++done: ++ return ret; ++} ++ ++ ++#define WRITE_PAYLOAD "canary" ++#define ADS_LEN 1024 ++#define ADS_OFF_TAIL ADS_LEN - sizeof(WRITE_PAYLOAD) ++ ++static bool test_streams_pwrite_hole(struct torture_context *tctx, ++ struct smb2_tree *tree) ++{ ++ NTSTATUS status; ++ bool ok; ++ bool ret = true; ++ const char *dname = BASEDIR "\\testdir"; ++ const char *fname = BASEDIR "\\testdir\\testfile"; ++ const char *sname = BASEDIR "\\testdir\\testfile:test_stream"; ++ const char *canary = "canary"; ++ struct smb2_handle shandle = {{0}}; ++ TALLOC_CTX *tmp_ctx = NULL; ++ char *data = NULL; ++ size_t data_sz, i; ++ ++ ok = smb2_util_setup_dir(tctx, tree, BASEDIR); ++ torture_assert_goto(tctx, ok == true, ret, done, "Unable to setup testdir\n"); ++ ++ tmp_ctx = talloc_new(tree); ++ torture_assert_goto(tctx, tmp_ctx != NULL, ret, done, "Memory failure\n"); ++ ++ ok = get_stream_handle(tctx, tree, dname, fname, sname, &shandle); ++ if (!ok) { ++ // torture assert already set ++ goto done; ++ } ++ ++ /* ++ * We're going to write a string at the beginning at the ADS, then write the same ++ * string at a later offset, introducing a hole in the file ++ */ ++ torture_comment(tctx, "writing at varying offsets to create hole\n"); ++ status = smb2_util_write(tree, shandle, WRITE_PAYLOAD, 0, sizeof(WRITE_PAYLOAD)); ++ if (!NT_STATUS_IS_OK(status)) { ++ torture_comment(tctx, "Failed to write %zu bytes to " ++ "stream at offset 0\n", sizeof(canary)); ++ return false; ++ } ++ ++ status = smb2_util_write(tree, shandle, WRITE_PAYLOAD, ADS_OFF_TAIL, sizeof(WRITE_PAYLOAD)); ++ if (!NT_STATUS_IS_OK(status)) { ++ torture_comment(tctx, "Failed to write %zu bytes to " ++ "stream at offset 1018\n", sizeof(canary)); ++ return false; ++ } ++ ++ /* Now we'll read the stream contents */ ++ torture_comment(tctx, "Read stream data\n"); ++ ok = read_stream(tctx, tmp_ctx, tree, &shandle, 0, ADS_LEN, &data, &data_sz); ++ if (!ok) { ++ // torture assert already set ++ goto done; ++ } ++ ++ torture_assert_goto(tctx, data_sz == ADS_LEN, ret, done, "Short read on ADS\n"); ++ ++ /* Make sure our strings actually got written */ ++ if (strncmp(data, WRITE_PAYLOAD, sizeof(WRITE_PAYLOAD)) != 0) { ++ torture_result(tctx, TORTURE_FAIL, ++ "Payload write at beginning of file failed"); ++ ret = false; ++ goto done; ++ } ++ ++ if (strncmp(data + ADS_OFF_TAIL, WRITE_PAYLOAD, sizeof(WRITE_PAYLOAD)) != 0) { ++ torture_result(tctx, TORTURE_FAIL, ++ "Payload write at end of file failed"); ++ ret = false; ++ goto done; ++ } ++ ++ /* Now we'll check that the hole is full of null bytes */ ++ for (i = sizeof(WRITE_PAYLOAD); i < ADS_OFF_TAIL; i++) { ++ if (data[i] != '\0') { ++ torture_comment(tctx, "idx: %zu, got 0x%02x when expected 0x00\n", ++ i, (uint8_t)data[i]); ++ torture_result(tctx, TORTURE_FAIL, ++ "0x%08x: unexpected non-null byte in ADS read\n", ++ data[i]); ++ ret = false; ++ goto done; ++ } ++ } ++ ++done: ++ talloc_free(tmp_ctx); ++ ++ if (!smb2_util_handle_empty(shandle)) { ++ smb2_util_close(tree, shandle); ++ } ++ ++ smb2_deltree(tree, BASEDIR); ++ ++ return ret; ++} ++ ++/* ++ basic testing of vfs_streams_xattr ++*/ ++struct torture_suite *torture_vfs_streams_xattr(TALLOC_CTX *ctx) ++{ ++ struct torture_suite *suite = torture_suite_create(ctx, "streams_xattr"); ++ ++ torture_suite_add_1smb2_test(suite, "streams-pwrite-hole", test_streams_pwrite_hole); ++ ++ suite->description = talloc_strdup(suite, "vfs_streams_xattr tests"); ++ ++ return suite; ++} +diff --git a/source4/torture/vfs/vfs.c b/source4/torture/vfs/vfs.c +index 3d402eeee0d..19dbaa0775c 100644 +--- a/source4/torture/vfs/vfs.c ++++ b/source4/torture/vfs/vfs.c +@@ -115,6 +115,7 @@ NTSTATUS torture_vfs_init(TALLOC_CTX *ctx) + torture_suite_add_suite(suite, torture_vfs_fruit_timemachine(suite)); + torture_suite_add_suite(suite, torture_vfs_fruit_conversion(suite)); + torture_suite_add_suite(suite, torture_vfs_fruit_unfruit(suite)); ++ torture_suite_add_suite(suite, torture_vfs_streams_xattr(suite)); + + torture_register_suite(ctx, suite); + +diff --git a/source4/torture/wscript_build b/source4/torture/wscript_build +index b38a30c98da..cae558398a3 100644 +--- a/source4/torture/wscript_build ++++ b/source4/torture/wscript_build +@@ -301,7 +301,7 @@ bld.SAMBA_MODULE('TORTURE_NTP', + ) + + bld.SAMBA_MODULE('TORTURE_VFS', +- source='vfs/vfs.c vfs/fruit.c vfs/acl_xattr.c', ++ source='vfs/vfs.c vfs/fruit.c vfs/acl_xattr.c vfs/streams_xattr.c', + subsystem='smbtorture', + deps='LIBCLI_SMB TORTURE_UTIL smbclient-raw TORTURE_RAW', + internal_module=True, +-- +2.43.0 diff --git a/backport-0002-CVE-2025-10230.patch b/backport-0002-CVE-2025-10230.patch new file mode 100644 index 0000000000000000000000000000000000000000..ce96c59b8d93ca1017e86a4ae5cc5c98a4420fe2 --- /dev/null +++ b/backport-0002-CVE-2025-10230.patch @@ -0,0 +1,75 @@ +From cec06776e4db805e9a8d1f2428f88895f3bf79a0 Mon Sep 17 00:00:00 2001 +From: Douglas Bagnall +Date: Wed, 3 Sep 2025 14:20:24 +1200 +Subject: [PATCH 2/2] CVE-2025-10230: s4:wins: restrict names fed to shell + +If the "wins hook" smb.conf parameter is set, the WINS server will +attempt to execute that value in a shell command line when a client +asks to modify a name. The WINS system is a trusting one, and clients +can claim any NETBIOS name they wish. + +With the source3 nmbd WINS server (since the 1999 commit now called +3db52feb1f3b2c07ce0b06ad4a7099fa6efe3fc7) the wins hook will not be +run for names that contain shell metacharacters. This restriction has +not been present on the source4 nbt WINS server, which is the WINS +server that will be used in the event that an Active Directory Domain +Controller is also running WINS. + +This allowed an unauthenticated client to execute arbitrary commands +on the server. + +This commit brings the nmbd check into the nbt WINS server, so that +the wins hook will only be run for names that contain only letters, +digits, hyphens, underscores and periods. This matches the behaviour +described in the smb.conf man page. + +The source3 nmbd WINS server has another layer of protection, in that +it uses the smb_run() exec wrapper that tries to escape arguments. We +don't do that here. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15903 + +Signed-off-by: Douglas Bagnall +Reviewed-by: Gary Lockyer + +Conflict: NA +Reference: http://attachments.samba.org/attachment.cgi?id=18744 +--- + selftest/knownfail.d/samba4.nbt.wins.wins_bad_names | 1 - + source4/nbt_server/wins/wins_hook.c | 9 +++++++++ + 2 files changed, 9 insertions(+), 1 deletion(-) + delete mode 100644 selftest/knownfail.d/samba4.nbt.wins.wins_bad_names + +diff --git a/selftest/knownfail.d/samba4.nbt.wins.wins_bad_names b/selftest/knownfail.d/samba4.nbt.wins.wins_bad_names +deleted file mode 100644 +index 52388ce5749..00000000000 +--- a/selftest/knownfail.d/samba4.nbt.wins.wins_bad_names ++++ /dev/null +@@ -1 +0,0 @@ +-samba4.nbt.wins.wins_bad_names +diff --git a/source4/nbt_server/wins/wins_hook.c b/source4/nbt_server/wins/wins_hook.c +index 1af471b15bc..442141fecdd 100644 +--- a/source4/nbt_server/wins/wins_hook.c ++++ b/source4/nbt_server/wins/wins_hook.c +@@ -43,9 +43,18 @@ void wins_hook(struct winsdb_handle *h, const struct winsdb_record *rec, + int child; + char *cmd = NULL; + TALLOC_CTX *tmp_mem = NULL; ++ const char *p = NULL; + + if (!wins_hook_script || !wins_hook_script[0]) return; + ++ for (p = rec->name->name; *p; p++) { ++ if (!(isalnum((int)*p) || strchr_m("._-", *p))) { ++ DBG_ERR("not calling wins hook for invalid name %s\n", ++ rec->name->name); ++ return; ++ } ++ } ++ + tmp_mem = talloc_new(h); + if (!tmp_mem) goto failed; + +-- +2.43.0 + diff --git a/backport-0002-CVE-2025-9640.patch b/backport-0002-CVE-2025-9640.patch new file mode 100644 index 0000000000000000000000000000000000000000..bc0c723068c64ae70b7c4a88939c0c9b9ad65d68 --- /dev/null +++ b/backport-0002-CVE-2025-9640.patch @@ -0,0 +1,49 @@ +From 9e1d16698bd2a395a8be3f48811391119db6152d Mon Sep 17 00:00:00 2001 +From: Andrew Walker +Date: Thu, 28 Aug 2025 19:36:19 +0000 +Subject: [PATCH 2/2] CVE-2025-9640: s3/modules/vfs_streams_xattr fix + unitialized write + +This commit fixes a situation in which vfs_streams_xattr could +write unitialized memory into alternate data streams if the +user writes to an offset that is beyond the current end of file +to insert a hole in it. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15885 + +Signed-off-by: Andrew Walker +Reviewed-by: Volker Lendecke + +Conflict: NA +Reference: http://attachments.samba.org/attachment.cgi?id=18747 +--- + source3/modules/vfs_streams_xattr.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/source3/modules/vfs_streams_xattr.c b/source3/modules/vfs_streams_xattr.c +index 03ff6147cb0..4fb4f42baa0 100644 +--- a/source3/modules/vfs_streams_xattr.c ++++ b/source3/modules/vfs_streams_xattr.c +@@ -959,15 +959,18 @@ static ssize_t streams_xattr_pwrite(vfs_handle_struct *handle, + + if ((offset + n) > ea.value.length-1) { + uint8_t *tmp; ++ size_t new_sz = offset + n + 1; + + tmp = talloc_realloc(talloc_tos(), ea.value.data, uint8_t, +- offset + n + 1); ++ new_sz); + + if (tmp == NULL) { + TALLOC_FREE(ea.value.data); + errno = ENOMEM; + return -1; + } ++ ++ memset(tmp + ea.value.length, 0, new_sz - ea.value.length); + ea.value.data = tmp; + ea.value.length = offset + n + 1; + ea.value.data[offset+n] = 0; +-- +2.43.0 + diff --git a/samba.spec b/samba.spec index 326254e8cbafa8eede74e7ecde400a9541d60a7c..9fbc4cd4fa779e0da3db7d90eee71d4134bd150f 100644 --- a/samba.spec +++ b/samba.spec @@ -53,7 +53,7 @@ Name: samba Version: 4.19.3 -Release: 7 +Release: 8 Summary: A suite for Linux to interoperate with Windows License: GPL-3.0-or-later AND LGPL-3.0-or-later @@ -73,6 +73,10 @@ Source201: README.downgrade Patch1: remove-sensitive-info.patch Patch2: backport-0001-s4-dsdb-strcasecmp_with_ldb_val-avoids-overflow.patch +Patch3: backport-0001-CVE-2025-10230.patch +Patch4: backport-0002-CVE-2025-10230.patch +Patch5: backport-0001-CVE-2025-9640.patch +Patch6: backport-0002-CVE-2025-9640.patch BuildRequires: avahi-devel bison dbus-devel docbook-style-xsl e2fsprogs-devel flex gawk gnupg2 gnutls-devel >= 3.4.7 gpgme-devel @@ -3595,6 +3599,12 @@ fi %endif %changelog +* Fri Oct 17 2025 xinghe - 4.19.3-8 +- Type:cves +- ID:CVE-2025-10230 CVE-2025-9640 +- SUG:NA +- DESC:fix CVE-2025-10230 CVE-2025-9640 + * Tue Mar 18 2025 mahailiang - 4.19.3-7 - Type:bugfix - ID:NA