From: Sachin Sant <sachinp@linux.ibm.com>
To: ltp@lists.linux.it
Subject: [LTP] [PATCH v8 2/8] fs/acl: Add ACL mask interaction tests
Date: Sat, 13 Jun 2026 14:35:37 +0530 [thread overview]
Message-ID: <20260613090543.78643-3-sachinp@linux.ibm.com> (raw)
In-Reply-To: <20260613090543.78643-1-sachinp@linux.ibm.com>
Add acl_mask01 test to verify that ACL_MASK correctly restricts
permissions for ACL_USER, ACL_GROUP, and ACL_GROUP_OBJ entries.
Test validates:
- ACL_USER permissions restricted by mask
- ACL_GROUP permissions restricted by mask
- ACL_GROUP_OBJ permissions restricted by mask
Each test verifies that:
- With mask set to rwx, access is granted
- With mask cleared (---), access is denied with EACCES
The test uses direct xattr manipulation via acl_lib.h helpers and
arbitrary UIDs without requiring actual user creation, testing only
the kernel ACL implementation
Suggested-by: Cyril Hrubis <chrubis@suse.cz>
Signed-off-by: Sachin Sant <sachinp@linux.ibm.com>
---
V8 changes:
- No change
V7 changes:
- No change
V6 changes:
- Adds proper portability guards for systems without xattr support
- Removed error checking for acl_add_entry() into library functions
- v5 link https://lore.kernel.org/ltp/20260608092200.92827-1-sachinp@linux.ibm.com/T/#t
V5 changes:
- Switch to kernel only test validation to remove dependency on libacl
and useradd/del commands.
- v3 link https://lore.kernel.org/ltp/20260604065417.25924-1-sachinp@linux.ibm.com/T/#t
V4 changes:
- No change
V3 changes:
- Updated copyright header as per LTP format.
- v1 link https://lore.kernel.org/ltp/20260602121958.27494-1-sachinp@linux.ibm.com/T/#t
V2 changes:
- No change
V1 changes:
- Use HAVE_LIBACL guards in .c code
- Report TCONF when libacl is not available
- rfc link https://lore.kernel.org/ltp/477836fd-80c8-4168-bfe6-00b374bb2534@linux.ibm.com/T/#t
---
runtest/fs | 1 +
testcases/kernel/fs/acl/.gitignore | 1 +
testcases/kernel/fs/acl/acl_mask01.c | 273 +++++++++++++++++++++++++++
3 files changed, 275 insertions(+)
create mode 100644 testcases/kernel/fs/acl/acl_mask01.c
diff --git a/runtest/fs b/runtest/fs
index 2a878744b..69ecb8647 100644
--- a/runtest/fs
+++ b/runtest/fs
@@ -90,3 +90,4 @@ squashfs01 squashfs01
# Run the acl tests
acl_user_obj01 acl_user_obj01
+acl_mask01 acl_mask01
diff --git a/testcases/kernel/fs/acl/.gitignore b/testcases/kernel/fs/acl/.gitignore
index d9c46db11..bfcdee93d 100644
--- a/testcases/kernel/fs/acl/.gitignore
+++ b/testcases/kernel/fs/acl/.gitignore
@@ -1 +1,2 @@
/acl_user_obj01
+/acl_mask01
diff --git a/testcases/kernel/fs/acl/acl_mask01.c b/testcases/kernel/fs/acl/acl_mask01.c
new file mode 100644
index 000000000..caaec5e57
--- /dev/null
+++ b/testcases/kernel/fs/acl/acl_mask01.c
@@ -0,0 +1,273 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2026 IBM
+ *
+ * Original shell test by Kai Zhao (ltcd3@cn.ibm.com)
+ * Converted to C by Sachin Sant <sachinp@linux.ibm.com>
+ */
+
+/*\
+ * Test ACL mask interaction with named users and groups using direct xattr
+ * manipulation.
+ *
+ * Verify that ACL_MASK correctly restricts permissions for:
+ * - ACL_USER (named user) entries
+ * - ACL_GROUP (named group) entries
+ * - ACL_GROUP_OBJ (group owner) entries
+ *
+ * The mask acts as an upper bound on permissions for these entry types.
+ * Even if an entry grants full permissions, the mask can restrict them.
+ * ACL_USER_OBJ and ACL_OTHER are not affected by the mask.
+ *
+ * This test uses arbitrary UIDs without creating actual users, testing
+ * only the kernel ACL implementation.
+ *
+ * [Algorithm]
+ *
+ * For each entry type (ACL_USER, ACL_GROUP, ACL_GROUP_OBJ):
+ * - Set up ACL with full permissions for the entry
+ * - Set mask to allow full permissions (rwx)
+ * - Verify access is granted
+ * - Clear mask permissions (---)
+ * - Verify access is denied despite entry having full permissions
+ */
+
+#include "acl_lib.h"
+
+#ifdef HAVE_SYS_XATTR_H
+
+#define TEST_UID 1000
+#define TEST_GID 1000
+#define USER2_UID 2000
+#define USER2_GID 2000
+#define USER3_UID 3000
+#define USER3_GID 3000
+
+/*
+ * Test ACL_USER permissions with mask.
+ * Named user permissions should be restricted by ACL_MASK.
+ */
+static void test_acl_user_with_mask(void)
+{
+ struct acl *acl;
+
+ tst_res(TINFO, "Testing ACL_USER with mask");
+ reset_test_path();
+
+ SAFE_CHOWN(TESTDIR, TEST_UID, TEST_GID);
+ SAFE_CHMOD(TESTDIR, 0550);
+
+ acl = acl_init();
+
+ acl_add_entry(acl, ACL_USER_OBJ,
+ ACL_READ | ACL_WRITE | ACL_EXECUTE, 0);
+ acl_add_entry(acl, ACL_USER,
+ ACL_READ | ACL_WRITE | ACL_EXECUTE, USER3_UID);
+ acl_add_entry(acl, ACL_GROUP_OBJ, 0, 0);
+ acl_add_entry(acl, ACL_MASK,
+ ACL_READ | ACL_WRITE | ACL_EXECUTE, 0);
+ acl_add_entry(acl, ACL_OTHER, 0, 0);
+
+ if (acl_set_file(TESTDIR, ACL_TYPE_ACCESS, acl) < 0) {
+ if (errno == EOPNOTSUPP) {
+ acl_free(acl);
+ tst_brk(TCONF | TERRNO, "ACL not supported");
+ }
+ acl_free(acl);
+ tst_brk(TBROK | TERRNO, "ACL setup failed");
+ }
+
+ acl_free(acl);
+
+ try_create_as(USER3_UID, USER3_GID, 0644, 0);
+
+ cleanup_testfile();
+
+ /* Clear mask permissions */
+ acl = acl_get_file(TESTDIR, ACL_TYPE_ACCESS);
+ if (!acl)
+ tst_brk(TBROK | TERRNO, "acl_get_file failed");
+
+ if (acl_set_mask_perms(acl, 0) < 0) {
+ acl_free(acl);
+ tst_brk(TBROK | TERRNO, "acl_set_mask_perms failed");
+ }
+
+ if (acl_set_file(TESTDIR, ACL_TYPE_ACCESS, acl) < 0) {
+ acl_free(acl);
+ tst_brk(TBROK | TERRNO, "acl_set_file failed");
+ }
+
+ acl_free(acl);
+
+ try_create_as(USER3_UID, USER3_GID, 0644, EACCES);
+}
+
+/*
+ * Test ACL_GROUP permissions with mask.
+ * Named group permissions should be restricted by ACL_MASK.
+ */
+static void test_acl_group_with_mask(void)
+{
+ struct acl *acl;
+
+ tst_res(TINFO, "Testing ACL_GROUP with mask");
+ reset_test_path();
+
+ SAFE_CHOWN(TESTDIR, TEST_UID, TEST_GID);
+ SAFE_CHMOD(TESTDIR, 0550);
+
+ acl = acl_init();
+
+ acl_add_entry(acl, ACL_USER_OBJ,
+ ACL_READ | ACL_WRITE | ACL_EXECUTE, 0);
+ acl_add_entry(acl, ACL_GROUP_OBJ, 0, 0);
+ acl_add_entry(acl, ACL_GROUP,
+ ACL_READ | ACL_WRITE | ACL_EXECUTE, USER2_GID);
+ acl_add_entry(acl, ACL_MASK,
+ ACL_READ | ACL_WRITE | ACL_EXECUTE, 0);
+ acl_add_entry(acl, ACL_OTHER, 0, 0);
+
+ if (acl_set_file(TESTDIR, ACL_TYPE_ACCESS, acl) < 0) {
+ if (errno == EOPNOTSUPP) {
+ acl_free(acl);
+ tst_brk(TCONF | TERRNO, "ACL not supported");
+ }
+ acl_free(acl);
+ tst_brk(TBROK | TERRNO, "ACL setup failed");
+ }
+
+ acl_free(acl);
+
+ try_create_as(USER2_UID, USER2_GID, 0644, 0);
+
+ cleanup_testfile();
+
+ /* Clear mask permissions */
+ acl = acl_get_file(TESTDIR, ACL_TYPE_ACCESS);
+ if (!acl)
+ tst_brk(TBROK | TERRNO, "acl_get_file failed");
+
+ if (acl_set_mask_perms(acl, 0) < 0) {
+ acl_free(acl);
+ tst_brk(TBROK | TERRNO, "acl_set_mask_perms failed");
+ }
+
+ if (acl_set_file(TESTDIR, ACL_TYPE_ACCESS, acl) < 0) {
+ acl_free(acl);
+ tst_brk(TBROK | TERRNO, "acl_set_file failed");
+ }
+
+ acl_free(acl);
+
+ try_create_as(USER2_UID, USER2_GID, 0644, EACCES);
+}
+
+/*
+ * Test ACL_GROUP_OBJ permissions with mask.
+ * Group owner permissions should be restricted by ACL_MASK.
+ */
+static void test_acl_group_obj_with_mask(void)
+{
+ struct acl *acl;
+
+ tst_res(TINFO, "Testing ACL_GROUP_OBJ with mask");
+ reset_test_path();
+
+ SAFE_CHOWN(TESTDIR, TEST_UID, USER2_GID);
+ SAFE_CHMOD(TESTDIR, 0550);
+
+ acl = acl_init();
+
+ acl_add_entry(acl, ACL_USER_OBJ,
+ ACL_READ | ACL_WRITE | ACL_EXECUTE, 0);
+ acl_add_entry(acl, ACL_GROUP_OBJ,
+ ACL_READ | ACL_WRITE | ACL_EXECUTE, 0);
+ acl_add_entry(acl, ACL_MASK,
+ ACL_READ | ACL_WRITE | ACL_EXECUTE, 0);
+ acl_add_entry(acl, ACL_OTHER, 0, 0);
+
+ if (acl_set_file(TESTDIR, ACL_TYPE_ACCESS, acl) < 0) {
+ if (errno == EOPNOTSUPP) {
+ acl_free(acl);
+ tst_brk(TCONF | TERRNO, "ACL not supported");
+ }
+ acl_free(acl);
+ tst_brk(TBROK | TERRNO, "ACL setup failed");
+ }
+
+ acl_free(acl);
+
+ try_create_as(USER2_UID, USER2_GID, 0644, 0);
+
+ cleanup_testfile();
+
+ /* Clear mask permissions */
+ acl = acl_get_file(TESTDIR, ACL_TYPE_ACCESS);
+ if (!acl)
+ tst_brk(TBROK | TERRNO, "acl_get_file failed");
+
+ if (acl_set_mask_perms(acl, 0) < 0) {
+ acl_free(acl);
+ tst_brk(TBROK | TERRNO, "acl_set_mask_perms failed");
+ }
+
+ if (acl_set_file(TESTDIR, ACL_TYPE_ACCESS, acl) < 0) {
+ acl_free(acl);
+ tst_brk(TBROK | TERRNO, "acl_set_file failed");
+ }
+
+ acl_free(acl);
+
+ try_create_as(USER2_UID, USER2_GID, 0644, EACCES);
+
+ SAFE_CHOWN(TESTDIR, TEST_UID, TEST_GID);
+}
+
+static void setup(void)
+{
+ reset_test_path();
+}
+
+static void cleanup(void)
+{
+ cleanup_test_paths();
+}
+
+static void run(unsigned int n)
+{
+ switch (n) {
+ case 0:
+ test_acl_user_with_mask();
+ break;
+ case 1:
+ test_acl_group_with_mask();
+ break;
+ case 2:
+ test_acl_group_obj_with_mask();
+ break;
+ }
+}
+
+static struct tst_test test = {
+ .test = run,
+ .tcnt = 3,
+ .setup = setup,
+ .cleanup = cleanup,
+ .needs_root = 1,
+ .mount_device = 1,
+ .mntpoint = MNTPOINT,
+ .forks_child = 1,
+ .filesystems = (struct tst_fs[]) {
+ {.type = "ext2", .mnt_data = "acl"},
+ {.type = "ext3", .mnt_data = "acl"},
+ {.type = "ext4", .mnt_data = "acl"},
+ {.type = "xfs"},
+ {.type = "btrfs"},
+ {}
+ }
+};
+
+#else
+ TST_TEST_TCONF("sys/xattr.h is not available");
+#endif
--
2.39.1
--
Mailing list info: https://lists.linux.it/listinfo/ltp
next prev parent reply other threads:[~2026-06-13 9:06 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-13 9:05 [LTP] [PATCH v8 0/8] Convert shell-based ACL test (tacl_xattr.sh) to C Sachin Sant
2026-06-13 9:05 ` [LTP] [PATCH v8 1/8] fs/acl: Add ACL_USER_OBJ permission test Sachin Sant
2026-06-13 10:36 ` [LTP] " linuxtestproject.agent
2026-06-13 9:05 ` Sachin Sant [this message]
2026-06-13 9:05 ` [LTP] [PATCH v8 3/8] fs/acl: Add ACL_OTHER " Sachin Sant
2026-06-13 9:05 ` [LTP] [PATCH v8 4/8] fs/acl: Add default ACL inheritance test Sachin Sant
2026-06-13 9:05 ` [LTP] [PATCH v8 5/8] fs/acl: Add chmod/chown ACL interaction tests Sachin Sant
2026-06-13 9:05 ` [LTP] [PATCH v8 6/8] fs/acl: Add ACL symlink operations test Sachin Sant
2026-06-13 9:05 ` [LTP] [PATCH v8 7/8] fs/acl: Add extended attributes test Sachin Sant
2026-06-13 9:05 ` [LTP] [PATCH v8 8/8] fs/acl: Remove old shell-based ACL test Sachin Sant
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260613090543.78643-3-sachinp@linux.ibm.com \
--to=sachinp@linux.ibm.com \
--cc=ltp@lists.linux.it \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.