[LTP] [PATCH v1 6/8] fs/acl: Add symlink ACL operations test
Sachin Sant
sachinp@linux.ibm.com
Tue Jun 2 14:19:56 CEST 2026
Add acl_link01 test to validate that ACL operations on symlinks
follow the symlink to the target file.
The test verifies that:
- acl_set_file() on a symlink sets ACL on the target file
- acl_get_file() on a symlink retrieves ACL from the target file
- ACL operations follow symlinks rather than operating on the link itself
This test creates a file and symlink, sets ACL via the symlink path,
and retrieves ACL via the symlink path to confirm both operations
work on the target file. Returns TCONF if ACL on symlinks is not
supported by the filesystem.
Signed-off-by: Sachin Sant <sachinp@linux.ibm.com>
---
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_link01.c | 130 +++++++++++++++++++++++++++
3 files changed, 132 insertions(+)
create mode 100644 testcases/kernel/fs/acl/acl_link01.c
diff --git a/runtest/fs b/runtest/fs
index 2364a8564..89d26e086 100644
--- a/runtest/fs
+++ b/runtest/fs
@@ -93,3 +93,4 @@ acl_mask01 acl_mask01
acl_other01 acl_other01
acl_inherit01 acl_inherit01
acl_file_ops01 acl_file_ops01
+acl_link01 acl_link01
diff --git a/testcases/kernel/fs/acl/.gitignore b/testcases/kernel/fs/acl/.gitignore
index eb4b4a227..4a071d516 100644
--- a/testcases/kernel/fs/acl/.gitignore
+++ b/testcases/kernel/fs/acl/.gitignore
@@ -3,3 +3,4 @@
/acl_other01
/acl_inherit01
/acl_file_ops01
+/acl_link01
diff --git a/testcases/kernel/fs/acl/acl_link01.c b/testcases/kernel/fs/acl/acl_link01.c
new file mode 100644
index 000000000..ff8a71ec7
--- /dev/null
+++ b/testcases/kernel/fs/acl/acl_link01.c
@@ -0,0 +1,130 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) IBM, 2026
+ *
+ * Original shell test by Kai Zhao (ltcd3@cn.ibm.com)
+ * Converted to C by Sachin Sant <sachinp@linux.ibm.com>
+ */
+
+/*\
+ * Test ACL operations on symlinks.
+ *
+ * Verify that ACL operations on symlinks follow the symlink to the target
+ * file. When setting or getting ACLs through a symlink path, the operation
+ * should affect the target file, not the symlink itself.
+ *
+ * Note: Some filesystems may not support ACLs on symlinks and will return
+ * EOPNOTSUPP, which is treated as TCONF (test not applicable).
+ *
+ * [Algorithm]
+ *
+ * 1. Create a regular file
+ * 2. Create a symlink pointing to the file
+ * 3. Set ACL through the symlink path
+ * 4. Verify the ACL was set on the target file
+ * 5. Get ACL through the symlink path
+ * 6. Verify we can read the ACL through the symlink
+ */
+
+#include "acl_lib.h"
+
+uid_t user1_uid, user2_uid, user3_uid;
+gid_t user1_gid, user2_gid, user3_gid;
+int users_created = 0;
+
+#ifdef HAVE_LIBACL
+
+static void run(void)
+{
+ acl_t acl;
+ int fd = -1;
+ int err;
+
+ tst_res(TINFO, "Testing ACL operations on symlinks");
+ reset_test_path();
+
+ fd = SAFE_OPEN(TESTFILE, O_CREAT | O_WRONLY, 0644);
+ SAFE_CLOSE(fd);
+
+ SAFE_SYMLINK("testfile", TESTSYMLINK);
+
+ acl = acl_init(3);
+ if (!acl) {
+ cleanup_testfile();
+ tst_brk(TBROK | TERRNO, "acl_init failed");
+ }
+
+ add_acl_entry(acl, ACL_USER_OBJ, ACL_READ | ACL_WRITE);
+ add_acl_entry(acl, ACL_GROUP_OBJ, ACL_READ);
+ add_acl_entry(acl, ACL_OTHER, ACL_READ);
+
+ err = acl_set_file(TESTSYMLINK, ACL_TYPE_ACCESS, acl);
+ if (err == -1) {
+ safe_acl_free(acl);
+ if (unlink(TESTSYMLINK) == -1)
+ tst_res(TWARN | TERRNO, "unlink symlink failed");
+ cleanup_testfile();
+ if (errno == EOPNOTSUPP) {
+ tst_res(TCONF,
+ "ACL on symlinks not supported");
+ return;
+ }
+ tst_brk(TBROK | TERRNO, "acl_set_file on symlink failed");
+ }
+
+ safe_acl_free(acl);
+
+ acl = acl_get_file(TESTSYMLINK, ACL_TYPE_ACCESS);
+ if (!acl) {
+ if (unlink(TESTSYMLINK) == -1)
+ tst_res(TWARN | TERRNO, "unlink symlink failed");
+ cleanup_testfile();
+ tst_brk(TBROK | TERRNO, "acl_get_file on symlink failed");
+ }
+
+ safe_acl_free(acl);
+
+ if (unlink(TESTSYMLINK) == -1)
+ tst_res(TWARN | TERRNO, "unlink symlink failed");
+ cleanup_testfile();
+ tst_res(TPASS, "Symlink ACL operations work correctly");
+}
+
+static void setup(void)
+{
+ init_test_users();
+ reset_test_path();
+}
+
+static void cleanup(void)
+{
+ cleanup_test_paths();
+ cleanup_test_users();
+}
+
+static struct tst_test test = {
+ .test_all = run,
+ .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"},
+ {}
+ },
+ .needs_cmds = (struct tst_cmd[]) {
+ {.cmd = "useradd"},
+ {.cmd = "userdel"},
+ {}
+ }
+};
+
+#else
+TST_TEST_TCONF("libacl or ACL headers are not available");
+#endif
--
2.39.1
More information about the ltp
mailing list