Linux CIFS filesystem development
 help / color / mirror / Atom feed
* [PATCH v4 0/3] ksmbd: bound smb_check_perm_dacl() ACE walks by DACL size
@ 2026-08-19  3:30 nanx95726
  2026-08-19  3:30 ` [PATCH v4 1/3] ksmbd: add KUnit test for the DACL walk boundary nanx95726
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: nanx95726 @ 2026-08-19  3:30 UTC (permalink / raw)
  To: smfrench, linkinjeon, tom, senozhatsky, chenxiaosong; +Cc: linux-cifs, Hang Nan

From: Hang Nan <nanx95726@gmail.com>

Changes in v3:

- Update SMB_SERVER_KUNIT_TESTS help text.
- Moved kunit tests under fs/smb/server/tests/.

The following patch from v2 have already been merged into #ksmbd-for-next-next:
https://lore.kernel.org/linux-cifs/CAKYAXd9XHJSNfrFr+F8thNxFnXqGGcKpS1b1qR4DNuu82+j_VQ@mail.gmail.com/

Hang Nan (3):
  ksmbd: add KUnit test for the DACL walk boundary
  ksmbd: test smb_check_perm_dacl() DACL walk boundary
  ksmbd: test maximal-access DACL walk boundary

 fs/smb/server/Kconfig              |   2 +
 fs/smb/server/Makefile             |   1 +
 fs/smb/server/smbacl.c             |   2 +
 fs/smb/server/tests/Kconfig        |  15 ++
 fs/smb/server/tests/Makefile       |   4 +
 fs/smb/server/tests/smbacl_kunit.c | 301 +++++++++++++++++++++++++++++
 fs/smb/server/vfs.c                |   2 +
 7 files changed, 327 insertions(+)
 create mode 100644 fs/smb/server/tests/Kconfig
 create mode 100644 fs/smb/server/tests/Makefile
 create mode 100644 fs/smb/server/tests/smbacl_kunit.c

-- 
2.55.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH v4 1/3] ksmbd: add KUnit test for the DACL walk boundary
  2026-08-19  3:30 [PATCH v4 0/3] ksmbd: bound smb_check_perm_dacl() ACE walks by DACL size nanx95726
@ 2026-08-19  3:30 ` nanx95726
  2026-08-19  3:30 ` [PATCH v4 2/3] ksmbd: test smb_check_perm_dacl() " nanx95726
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: nanx95726 @ 2026-08-19  3:30 UTC (permalink / raw)
  To: smfrench, linkinjeon, tom, senozhatsky, chenxiaosong; +Cc: linux-cifs, Hang Nan

From: Hang Nan <nanx95726@gmail.com>

smb_check_perm_dacl() must stop walking ACEs at the DACL declared
size instead of using the enclosing security descriptor length.

Add the ksmbd KUnit test configuration and a semantic harness that
verifies a crafted access-granting ACE beyond the declared DACL size is
ignored.

Suggested-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Suggested-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Hang Nan <nanx95726@gmail.com>
Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
---
 fs/smb/server/Kconfig              |   2 +
 fs/smb/server/Makefile             |   1 +
 fs/smb/server/tests/Kconfig        |  15 +++
 fs/smb/server/tests/Makefile       |   4 +
 fs/smb/server/tests/smbacl_kunit.c | 170 +++++++++++++++++++++++++++++
 5 files changed, 192 insertions(+)
 create mode 100644 fs/smb/server/tests/Kconfig
 create mode 100644 fs/smb/server/tests/Makefile
 create mode 100644 fs/smb/server/tests/smbacl_kunit.c

diff --git a/fs/smb/server/Kconfig b/fs/smb/server/Kconfig
index 08d8b7a965a6..0d61a27990c6 100644
--- a/fs/smb/server/Kconfig
+++ b/fs/smb/server/Kconfig
@@ -72,3 +72,5 @@ config SMB_SERVER_KERBEROS5
 	bool "Support for Kerberos 5"
 	depends on SMB_SERVER
 	default y
+
+source "fs/smb/server/tests/Kconfig"
diff --git a/fs/smb/server/Makefile b/fs/smb/server/Makefile
index a3e9306055e8..9bc87695a53c 100644
--- a/fs/smb/server/Makefile
+++ b/fs/smb/server/Makefile
@@ -19,3 +19,4 @@ $(obj)/ksmbd_spnego_negtokentarg.asn1.o: $(obj)/ksmbd_spnego_negtokentarg.asn1.c
 
 ksmbd-$(CONFIG_SMB_SERVER_SMBDIRECT) += transport_rdma.o
 ksmbd-$(CONFIG_PROC_FS) += proc.o
+obj-$(CONFIG_SMB_SERVER_KUNIT_TESTS) += tests/
diff --git a/fs/smb/server/tests/Kconfig b/fs/smb/server/tests/Kconfig
new file mode 100644
index 000000000000..ad7a4e94ceaa
--- /dev/null
+++ b/fs/smb/server/tests/Kconfig
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (C) 2026 Hang Nan <nanx95726@gmail.com>
+
+config SMB_SERVER_KUNIT_TESTS
+	tristate "KUnit tests for SMB3 server helpers" if !KUNIT_ALL_TESTS
+	depends on SMB_SERVER && SMB_KUNIT_TESTS && TMPFS_XATTR
+	default SMB_KUNIT_TESTS
+	help
+	  This builds the KUnit tests for ksmbd server helpers. The tests
+	  exercise internal server functionality and help detect regressions
+	  in server-side behavior. They are intended for kernel developers
+	  and are not suitable for production systems.
+
+	  For more information on KUnit and unit tests in the kernel,
+	  please read Documentation/dev-tools/kunit/index.rst.
diff --git a/fs/smb/server/tests/Makefile b/fs/smb/server/tests/Makefile
new file mode 100644
index 000000000000..8738ab0b0667
--- /dev/null
+++ b/fs/smb/server/tests/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (C) 2026 Hang Nan <nanx95726@gmail.com>
+
+obj-$(CONFIG_SMB_SERVER_KUNIT_TESTS) += smbacl_kunit.o
diff --git a/fs/smb/server/tests/smbacl_kunit.c b/fs/smb/server/tests/smbacl_kunit.c
new file mode 100644
index 000000000000..733c2fa92030
--- /dev/null
+++ b/fs/smb/server/tests/smbacl_kunit.c
@@ -0,0 +1,170 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * KUnit tests for ksmbd security descriptor (DACL) handling.
+ *
+ * Copyright (C) 2026 Hang Nan <nanx95726@gmail.com>
+ *
+ * The tests pin the DACL declared-size boundary in smb_check_perm_dacl():
+ *
+ * - ksmbd_dacl_walk_must_stop_at_declared_size: a pure semantic harness
+ *   that models the ACE walk.  Walking to the end of the enclosing
+ *   security descriptor (the pre-fix behaviour) selects an ACE that
+ *   sits beyond struct smb_acl::size; stopping at the declared DACL
+ *   size (the fixed behaviour) rejects it.
+ */
+
+#include <kunit/test.h>
+#include <linux/slab.h>
+
+#include "../smbacl.h"
+#include "../smb_common.h"
+
+struct ksmbd_acl_walk_result {
+	bool found;
+	bool allowed;
+	const struct smb_ace *selected;
+};
+
+static const struct smb_sid test_nonmatching_sid = {
+	1, 5, {0, 0, 0, 0, 0, 5},
+	{ cpu_to_le32(21), cpu_to_le32(1), cpu_to_le32(2),
+	  cpu_to_le32(3), cpu_to_le32(9999) }
+};
+
+/*
+ * S-1-22-1-0: the SID id_to_sid(0, SIDUNIX_USER) resolves to, i.e. what
+ * smb_check_perm_dacl() looks for when called with uid == 0.
+ */
+static const struct smb_sid test_owner_sid = {
+	1, 2, {0, 0, 0, 0, 0, 22},
+	{ cpu_to_le32(1), cpu_to_le32(0) }
+};
+
+static int test_compare_sids(const struct smb_sid *a, const struct smb_sid *b)
+{
+	int i;
+
+	if (a->revision != b->revision || a->num_subauth != b->num_subauth)
+		return 1;
+	for (i = 0; i < NUM_AUTHS; i++) {
+		if (a->authority[i] != b->authority[i])
+			return 1;
+	}
+	for (i = 0; i < a->num_subauth; i++) {
+		if (a->sub_auth[i] != b->sub_auth[i])
+			return 1;
+	}
+	return 0;
+}
+
+static u16 test_ace_size(const struct smb_sid *sid)
+{
+	return offsetof(struct smb_ace, sid) + CIFS_SID_BASE_SIZE +
+	       sid->num_subauth * sizeof(__le32);
+}
+
+static u16 fill_test_ace(struct smb_ace *ace, const struct smb_sid *sid,
+			 u32 access_req)
+{
+	u16 size = test_ace_size(sid);
+
+	ace->type = ACCESS_ALLOWED_ACE_TYPE;
+	ace->flags = 0;
+	ace->size = cpu_to_le16(size);
+	ace->access_req = cpu_to_le32(access_req);
+	memcpy(&ace->sid, sid, size - offsetof(struct smb_ace, sid));
+	return size;
+}
+
+static struct ksmbd_acl_walk_result test_walk_dacl(struct smb_acl *pdacl,
+						    int walk_boundary,
+						    const struct smb_sid *target,
+						    u32 requested)
+{
+	struct ksmbd_acl_walk_result result = {};
+	struct smb_ace *ace;
+	int aces_size;
+	int i;
+
+	ace = (struct smb_ace *)((char *)pdacl + sizeof(struct smb_acl));
+	aces_size = walk_boundary - sizeof(struct smb_acl);
+	for (i = 0; i < le16_to_cpu(pdacl->num_aces); i++) {
+		u16 ace_size;
+
+		if (aces_size < offsetof(struct smb_ace, sid) + CIFS_SID_BASE_SIZE)
+			break;
+		ace_size = le16_to_cpu(ace->size);
+		if (ace_size > aces_size ||
+		    ace_size < offsetof(struct smb_ace, sid) + CIFS_SID_BASE_SIZE)
+			break;
+		aces_size -= ace_size;
+
+		if (ace->sid.num_subauth > SID_MAX_SUB_AUTHORITIES ||
+		    ace_size < offsetof(struct smb_ace, sid) + CIFS_SID_BASE_SIZE +
+			       sizeof(__le32) * ace->sid.num_subauth)
+			break;
+
+		if (!test_compare_sids(target, &ace->sid)) {
+			result.found = true;
+			result.selected = ace;
+			result.allowed = !(requested & ~le32_to_cpu(ace->access_req));
+			return result;
+		}
+
+		ace = (struct smb_ace *)((char *)ace + ace_size);
+	}
+
+	return result;
+}
+
+static void ksmbd_dacl_walk_must_stop_at_declared_size(struct kunit *test)
+{
+	struct ksmbd_acl_walk_result declared, enclosing;
+	struct smb_acl *acl;
+	struct smb_ace *ace1, *fake;
+	u16 ace1_size, fake_size;
+	u16 pdacl_size;
+	u16 acl_size;
+
+	acl = kunit_kzalloc(test, 128, GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, acl);
+
+	acl->revision = cpu_to_le16(2);
+	acl->num_aces = cpu_to_le16(2);
+
+	ace1 = (struct smb_ace *)((char *)acl + sizeof(*acl));
+	ace1_size = fill_test_ace(ace1, &test_nonmatching_sid, 0);
+	fake = (struct smb_ace *)((char *)ace1 + ace1_size);
+	fake_size = fill_test_ace(fake, &test_owner_sid, FILE_READ_DATA);
+
+	pdacl_size = sizeof(*acl) + ace1_size;
+	acl_size = pdacl_size + fake_size;
+	acl->size = cpu_to_le16(pdacl_size);
+
+	declared = test_walk_dacl(acl, pdacl_size, &test_owner_sid,
+				  FILE_READ_DATA);
+	enclosing = test_walk_dacl(acl, acl_size, &test_owner_sid,
+				   FILE_READ_DATA);
+
+	KUNIT_EXPECT_FALSE(test, declared.found);
+	KUNIT_EXPECT_FALSE(test, declared.allowed);
+
+	/* Demonstrates that the buggy acl_size boundary selects fake ACE #2. */
+	KUNIT_EXPECT_TRUE(test, enclosing.found);
+	KUNIT_EXPECT_TRUE(test, enclosing.allowed);
+}
+
+static struct kunit_case ksmbd_smbacl_test_cases[] = {
+	KUNIT_CASE(ksmbd_dacl_walk_must_stop_at_declared_size),
+	{}
+};
+
+static struct kunit_suite ksmbd_smbacl_test_suite = {
+	.name = "ksmbd-smbacl",
+	.test_cases = ksmbd_smbacl_test_cases,
+};
+
+kunit_test_suite(ksmbd_smbacl_test_suite);
+
+MODULE_DESCRIPTION("KUnit tests for ksmbd smbacl helpers");
+MODULE_LICENSE("GPL");
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH v4 2/3] ksmbd: test smb_check_perm_dacl() DACL walk boundary
  2026-08-19  3:30 [PATCH v4 0/3] ksmbd: bound smb_check_perm_dacl() ACE walks by DACL size nanx95726
  2026-08-19  3:30 ` [PATCH v4 1/3] ksmbd: add KUnit test for the DACL walk boundary nanx95726
@ 2026-08-19  3:30 ` nanx95726
  2026-08-19  3:30 ` [PATCH v4 3/3] ksmbd: test maximal-access " nanx95726
  2026-08-20  0:45 ` [PATCH v4 0/3] ksmbd: bound smb_check_perm_dacl() ACE walks by DACL size Namjae Jeon
  3 siblings, 0 replies; 5+ messages in thread
From: nanx95726 @ 2026-08-19  3:30 UTC (permalink / raw)
  To: smfrench, linkinjeon, tom, senozhatsky, chenxiaosong; +Cc: linux-cifs, Hang Nan

From: Hang Nan <nanx95726@gmail.com>

Drive smb_check_perm_dacl() through ksmbd's NTACL xattr path with a
crafted descriptor whose second ACE is beyond the declared DACL size.

Verify that the out-of-boundary ACE is not selected and access remains
denied.

Suggested-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Signed-off-by: Hang Nan <nanx95726@gmail.com>
Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
---
 fs/smb/server/smbacl.c             |  2 +
 fs/smb/server/tests/smbacl_kunit.c | 90 ++++++++++++++++++++++++++++++
 fs/smb/server/vfs.c                |  2 +
 3 files changed, 94 insertions(+)

diff --git a/fs/smb/server/smbacl.c b/fs/smb/server/smbacl.c
index 8ad2e5a5cca8..5b2d46c09da7 100644
--- a/fs/smb/server/smbacl.c
+++ b/fs/smb/server/smbacl.c
@@ -7,6 +7,7 @@
  */
 
 #include <linux/fs.h>
+#include <kunit/visibility.h>
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/mnt_idmapping.h>
@@ -1652,6 +1653,7 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path,
 	kfree(pntsd);
 	return rc;
 }
+EXPORT_SYMBOL_IF_KUNIT(smb_check_perm_dacl);
 
 int set_info_sec(struct ksmbd_conn *conn, struct ksmbd_tree_connect *tcon,
 		 const struct path *path, struct smb_ntsd *pntsd, int ntsd_len,
diff --git a/fs/smb/server/tests/smbacl_kunit.c b/fs/smb/server/tests/smbacl_kunit.c
index 733c2fa92030..391b1f5d181c 100644
--- a/fs/smb/server/tests/smbacl_kunit.c
+++ b/fs/smb/server/tests/smbacl_kunit.c
@@ -11,13 +11,22 @@
  *   security descriptor (the pre-fix behaviour) selects an ACE that
  *   sits beyond struct smb_acl::size; stopping at the declared DACL
  *   size (the fixed behaviour) rejects it.
+ *
+ * - ksmbd_smb_check_perm_dacl_boundary: drives the real
+ *   smb_check_perm_dacl() with a descriptor stored through ksmbd's own
+ *   NTACL xattr path on a tmpfs file, and asserts that a post-boundary
+ *   ACE is not selected for a regular access check.
  */
 
 #include <kunit/test.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/shmem_fs.h>
 #include <linux/slab.h>
 
 #include "../smbacl.h"
 #include "../smb_common.h"
+#include "../vfs.h"
 
 struct ksmbd_acl_walk_result {
 	bool found;
@@ -154,8 +163,88 @@ static void ksmbd_dacl_walk_must_stop_at_declared_size(struct kunit *test)
 	KUNIT_EXPECT_TRUE(test, enclosing.allowed);
 }
 
+/*
+ * Build an NTSD whose DACL declares one ACE (pdacl->size) but actually
+ * contains two: the second ACE sits beyond the declared DACL boundary
+ * yet inside the enclosing security descriptor.  The trailing ACE applies
+ * to S-1-22-1-0, which smb_check_perm_dacl() looks for when uid is zero.
+ */
+static struct smb_ntsd *build_boundary_ntsd(struct kunit *test,
+					    const struct smb_sid *first_sid,
+					    u32 first_access,
+					    u32 trailing_access,
+					    int *ntsd_size)
+{
+	struct smb_ntsd *pntsd;
+	struct smb_acl *pdacl;
+	struct smb_ace *ace;
+	u16 first_size = test_ace_size(first_sid);
+	u16 trailing_size = test_ace_size(&test_owner_sid);
+
+	*ntsd_size = sizeof(struct smb_ntsd) + sizeof(struct smb_acl) +
+		     first_size + trailing_size;
+	pntsd = kunit_kzalloc(test, *ntsd_size, GFP_KERNEL);
+	if (!pntsd)
+		return NULL;
+
+	pntsd->revision = cpu_to_le16(SD_REVISION);
+	pntsd->type = cpu_to_le16(DACL_PRESENT);
+	pntsd->dacloffset = cpu_to_le32(sizeof(struct smb_ntsd));
+
+	pdacl = (struct smb_acl *)((char *)pntsd + sizeof(struct smb_ntsd));
+	pdacl->revision = cpu_to_le16(2);
+	pdacl->num_aces = cpu_to_le16(2);
+	pdacl->size = cpu_to_le16(sizeof(struct smb_acl) + first_size);
+
+	ace = (struct smb_ace *)((char *)pdacl + sizeof(struct smb_acl));
+	fill_test_ace(ace, first_sid, first_access);
+
+	ace = (struct smb_ace *)((char *)ace + first_size);
+	fill_test_ace(ace, &test_owner_sid, trailing_access);
+
+	return pntsd;
+}
+
+static void ksmbd_smb_check_perm_dacl_boundary_test(struct kunit *test)
+{
+	struct file *file;
+	struct smb_ntsd *pntsd;
+	__le32 daccess = cpu_to_le32(FILE_READ_DATA);
+	int ntsd_size, rc;
+
+	pntsd = build_boundary_ntsd(test, &test_nonmatching_sid, 0,
+				     FILE_READ_DATA, &ntsd_size);
+	KUNIT_ASSERT_NOT_NULL(test, pntsd);
+
+	file = shmem_file_setup("ksmbd-kunit-dacl", 0,
+				mk_vma_flags(VMA_NORESERVE_BIT));
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, file);
+
+	rc = ksmbd_vfs_set_sd_xattr(NULL, mnt_idmap(file->f_path.mnt),
+				    &file->f_path, pntsd, ntsd_size,
+				    false);
+	KUNIT_EXPECT_EQ(test, 0, rc);
+	if (rc)
+		goto out;
+
+	rc = smb_check_perm_dacl(NULL, &file->f_path, &daccess,
+				 cpu_to_le32(FILE_READ_DATA), 0, false);
+
+	/*
+	 * The post-boundary ACE (ACE #2, beyond pdacl->size) grants
+	 * FILE_READ_DATA to the caller's SID, but it must not be
+	 * selected: the walk stops at the declared DACL size and access
+	 * is denied.  Before the fix the walk used the enclosing
+	 * descriptor length, selected ACE #2 and returned 0.
+	 */
+	KUNIT_EXPECT_EQ(test, -EACCES, rc);
+out:
+	fput(file);
+}
+
 static struct kunit_case ksmbd_smbacl_test_cases[] = {
 	KUNIT_CASE(ksmbd_dacl_walk_must_stop_at_declared_size),
+	KUNIT_CASE(ksmbd_smb_check_perm_dacl_boundary_test),
 	{}
 };
 
@@ -168,3 +257,4 @@ kunit_test_suite(ksmbd_smbacl_test_suite);
 
 MODULE_DESCRIPTION("KUnit tests for ksmbd smbacl helpers");
 MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");
diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c
index 286536f75144..536300f9eb8f 100644
--- a/fs/smb/server/vfs.c
+++ b/fs/smb/server/vfs.c
@@ -5,6 +5,7 @@
  */
 
 #include <crypto/sha2.h>
+#include <kunit/visibility.h>
 #include <linux/kernel.h>
 #include <linux/fs.h>
 #include <linux/filelock.h>
@@ -1668,6 +1669,7 @@ int ksmbd_vfs_set_sd_xattr(struct ksmbd_conn *conn,
 	kfree(def_smb_acl);
 	return rc;
 }
+EXPORT_SYMBOL_IF_KUNIT(ksmbd_vfs_set_sd_xattr);
 
 int ksmbd_vfs_get_sd_xattr(struct ksmbd_conn *conn,
 			   struct mnt_idmap *idmap,
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH v4 3/3] ksmbd: test maximal-access DACL walk boundary
  2026-08-19  3:30 [PATCH v4 0/3] ksmbd: bound smb_check_perm_dacl() ACE walks by DACL size nanx95726
  2026-08-19  3:30 ` [PATCH v4 1/3] ksmbd: add KUnit test for the DACL walk boundary nanx95726
  2026-08-19  3:30 ` [PATCH v4 2/3] ksmbd: test smb_check_perm_dacl() " nanx95726
@ 2026-08-19  3:30 ` nanx95726
  2026-08-20  0:45 ` [PATCH v4 0/3] ksmbd: bound smb_check_perm_dacl() ACE walks by DACL size Namjae Jeon
  3 siblings, 0 replies; 5+ messages in thread
From: nanx95726 @ 2026-08-19  3:30 UTC (permalink / raw)
  To: smfrench, linkinjeon, tom, senozhatsky, chenxiaosong; +Cc: linux-cifs, Hang Nan

From: Hang Nan <nanx95726@gmail.com>

Add a maximal-access variant of the smb_check_perm_dacl() boundary
test.  The in-boundary ACE grants read access, while a trailing ACE
beyond the declared DACL size grants write access.

Verify that maximal-access calculation includes the in-boundary
permission and ignores the trailing permission.

Suggested-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Signed-off-by: Hang Nan <nanx95726@gmail.com>
Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
---
 fs/smb/server/tests/smbacl_kunit.c | 47 ++++++++++++++++++++++++++++--
 1 file changed, 44 insertions(+), 3 deletions(-)

diff --git a/fs/smb/server/tests/smbacl_kunit.c b/fs/smb/server/tests/smbacl_kunit.c
index 391b1f5d181c..33496b4d31a3 100644
--- a/fs/smb/server/tests/smbacl_kunit.c
+++ b/fs/smb/server/tests/smbacl_kunit.c
@@ -12,10 +12,11 @@
  *   sits beyond struct smb_acl::size; stopping at the declared DACL
  *   size (the fixed behaviour) rejects it.
  *
- * - ksmbd_smb_check_perm_dacl_boundary: drives the real
+ * - ksmbd_smb_check_perm_dacl_boundary and
+ *   ksmbd_smb_check_perm_dacl_maximal_boundary: drive the real
  *   smb_check_perm_dacl() with a descriptor stored through ksmbd's own
- *   NTACL xattr path on a tmpfs file, and asserts that a post-boundary
- *   ACE is not selected for a regular access check.
+ *   NTACL xattr path on a tmpfs file, and assert that a post-boundary
+ *   ACE is not selected for either a regular or maximal access check.
  */
 
 #include <kunit/test.h>
@@ -242,9 +243,49 @@ static void ksmbd_smb_check_perm_dacl_boundary_test(struct kunit *test)
 	fput(file);
 }
 
+static void
+ksmbd_smb_check_perm_dacl_maximal_boundary_test(struct kunit *test)
+{
+	struct file *file;
+	struct smb_ntsd *pntsd;
+	__le32 daccess = FILE_MAXIMAL_ACCESS_LE;
+	int ntsd_size, rc;
+
+	/*
+	 * The in-boundary ACE grants read access.  The trailing ACE grants
+	 * write access, which must not be included in the maximal access mask.
+	 */
+	pntsd = build_boundary_ntsd(test, &test_owner_sid, FILE_READ_DATA,
+				     FILE_WRITE_DATA, &ntsd_size);
+	KUNIT_ASSERT_NOT_NULL(test, pntsd);
+
+	file = shmem_file_setup("ksmbd-kunit-dacl-maximal", 0,
+				mk_vma_flags(VMA_NORESERVE_BIT));
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, file);
+
+	rc = ksmbd_vfs_set_sd_xattr(NULL, mnt_idmap(file->f_path.mnt),
+				    &file->f_path, pntsd, ntsd_size,
+				    false);
+	KUNIT_EXPECT_EQ(test, 0, rc);
+	if (rc)
+		goto out;
+
+	rc = smb_check_perm_dacl(NULL, &file->f_path, &daccess,
+				 FILE_MAXIMAL_ACCESS_LE, 0, false);
+	KUNIT_EXPECT_EQ(test, 0, rc);
+	if (rc)
+		goto out;
+
+	KUNIT_EXPECT_TRUE(test, le32_to_cpu(daccess) & FILE_READ_DATA);
+	KUNIT_EXPECT_FALSE(test, le32_to_cpu(daccess) & FILE_WRITE_DATA);
+out:
+	fput(file);
+}
+
 static struct kunit_case ksmbd_smbacl_test_cases[] = {
 	KUNIT_CASE(ksmbd_dacl_walk_must_stop_at_declared_size),
 	KUNIT_CASE(ksmbd_smb_check_perm_dacl_boundary_test),
+	KUNIT_CASE(ksmbd_smb_check_perm_dacl_maximal_boundary_test),
 	{}
 };
 
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH v4 0/3] ksmbd: bound smb_check_perm_dacl() ACE walks by DACL size
  2026-08-19  3:30 [PATCH v4 0/3] ksmbd: bound smb_check_perm_dacl() ACE walks by DACL size nanx95726
                   ` (2 preceding siblings ...)
  2026-08-19  3:30 ` [PATCH v4 3/3] ksmbd: test maximal-access " nanx95726
@ 2026-08-20  0:45 ` Namjae Jeon
  3 siblings, 0 replies; 5+ messages in thread
From: Namjae Jeon @ 2026-08-20  0:45 UTC (permalink / raw)
  To: nanx95726; +Cc: smfrench, tom, senozhatsky, chenxiaosong, linux-cifs

On Wed, Aug 19, 2026 at 12:30 PM <nanx95726@gmail.com> wrote:
>
> From: Hang Nan <nanx95726@gmail.com>
>
> Changes in v3:
>
> - Update SMB_SERVER_KUNIT_TESTS help text.
> - Moved kunit tests under fs/smb/server/tests/.
>
> The following patch from v2 have already been merged into #ksmbd-for-next-next:
> https://lore.kernel.org/linux-cifs/CAKYAXd9XHJSNfrFr+F8thNxFnXqGGcKpS1b1qR4DNuu82+j_VQ@mail.gmail.com/
>
> Hang Nan (3):
>   ksmbd: add KUnit test for the DACL walk boundary
>   ksmbd: test smb_check_perm_dacl() DACL walk boundary
>   ksmbd: test maximal-access DACL walk boundary
It’s a bit late to apply this to the 7.3 kernel. I will apply this
patchset to the 7.4 kernel.
Thanks!

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-08-20  0:46 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-19  3:30 [PATCH v4 0/3] ksmbd: bound smb_check_perm_dacl() ACE walks by DACL size nanx95726
2026-08-19  3:30 ` [PATCH v4 1/3] ksmbd: add KUnit test for the DACL walk boundary nanx95726
2026-08-19  3:30 ` [PATCH v4 2/3] ksmbd: test smb_check_perm_dacl() " nanx95726
2026-08-19  3:30 ` [PATCH v4 3/3] ksmbd: test maximal-access " nanx95726
2026-08-20  0:45 ` [PATCH v4 0/3] ksmbd: bound smb_check_perm_dacl() ACE walks by DACL size Namjae Jeon

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox