]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
CVE-2026-2340: vfs_worm: Check destination WORM status in rename
authorPavel Kohout <pavel@aisle.com>
Fri, 13 Feb 2026 02:51:41 +0000 (15:51 +1300)
committerStefan Metzmacher <metze@samba.org>
Tue, 26 May 2026 12:51:32 +0000 (12:51 +0000)
vfs_worm_renameat() only checked if the source file was WORM-protected,
but not the destination. This allowed overwriting immutable files via
SMB2 rename with ReplaceIfExists=1, bypassing WORM protection.

Add destination check using FSTATAT on the destination dirfsp, as
suggested by the maintainer.

CWE-284 (Improper Access Control)

Reported-by: Pavel Kohout, Aisle Research, www.aisle.com
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15997

Signed-off-by: Pavel Kohout <pavel.kohout@aisle.com>
Reviewed-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
selftest/knownfail.d/vfs-worm [deleted file]
source3/modules/vfs_worm.c

diff --git a/selftest/knownfail.d/vfs-worm b/selftest/knownfail.d/vfs-worm
deleted file mode 100644 (file)
index f4a330c..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-^samba3.blackbox.worm.SMB3
-^samba3.blackbox.worm.NT1
index b9ca9d1e158276665e5052e2cfeee370d4d8fc2c..5effd497da2540829a063664970ffbaff7971fed 100644 (file)
@@ -218,11 +218,29 @@ static int vfs_worm_renameat(vfs_handle_struct *handle,
                             const struct smb_filename *smb_fname_dst,
                             const struct vfs_rename_how *how)
 {
+       struct stat_ex dst_st;
+       int ret;
+
        if (is_readonly(handle, smb_fname_src)) {
                errno = EACCES;
                return -1;
        }
 
+       /* Check if destination is WORM-protected (fixes CVE-2026-2340) */
+       ret = SMB_VFS_FSTATAT(handle->conn,
+                             dst_dirfsp,
+                             smb_fname_dst,
+                             &dst_st,
+                             AT_SYMLINK_NOFOLLOW);
+       if (ret == 0) {
+               struct smb_filename dst_with_stat = *smb_fname_dst;
+               dst_with_stat.st = dst_st;
+               if (is_readonly(handle, &dst_with_stat)) {
+                       errno = EACCES;
+                       return -1;
+               }
+       }
+
        return SMB_VFS_NEXT_RENAMEAT(handle,
                                     src_dirfsp,
                                     smb_fname_src,