Linux Test Project
 help / color / mirror / Atom feed
From: Sachin Sant <sachinp@linux.ibm.com>
To: ltp@lists.linux.it
Subject: [LTP] [PATCH v8 1/8] fs/acl: Add ACL_USER_OBJ permission test
Date: Sat, 13 Jun 2026 14:35:36 +0530	[thread overview]
Message-ID: <20260613090543.78643-2-sachinp@linux.ibm.com> (raw)
In-Reply-To: <20260613090543.78643-1-sachinp@linux.ibm.com>

Add acl_user_obj01 test to validate ACL_USER_OBJ permissions:
- Owner permissions correctly control file/directory access
- ACL_USER_OBJ=rwx via setxattr() overrides chmod restrictions
- Owner permissions work independently of group/other permissions
- Tests use arbitrary UIDs without requiring actual user creation

The patch also adds acl_lib.h containing shared helpers for ACL
manipulation via xattr API, including:
- ACL structure management (acl_init, acl_free, acl_add_entry)
- ACL serialization/deserialization for kernel xattr format
- ACL get/set operations using getxattr/setxattr
- permission testing and file operations
- Support for both ACCESS and DEFAULT ACL types

The implementation uses direct xattr API (getxattr/setxattr) to
test kernel ACL behavior directly. Tests run on ext2/3/4,
XFS, and Btrfs filesystems with ACL support.

Suggested-by: Cyril Hrubis <chrubis@suse.cz>
Signed-off-by: Sachin Sant <sachinp@linux.ibm.com>
---
V8 changes:
- Removed no chown variant of reset_test_path
- Use RST manpage formatted documentation
- v7 link https://lore.kernel.org/ltp/20260612171930.11964-1-sachinp@linux.ibm.com/T/#t

V7 changes:
- Use SAFE_ variants of setresgid/setresuid
- Replace TST_EXP_FAIL with TST_EXP_FAIL2
- v6 link https://lore.kernel.org/ltp/20260612102502.24071-1-sachinp@linux.ibm.com/T/#t

V6 changes:
- Added HAVE_SYS_XATTR_H guards for systems without xattr support
- Removed unnecessary error paths and manual status checking
- Uses SAFE_MALLOC() and new helper macros
- Added acl_type_to_name() helper to eliminate duplication
- 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.
- v4 link https://lore.kernel.org/ltp/20260604065417.25924-1-sachinp@linux.ibm.com/T/#t

V4 changes:
- Add -U flag in create_user_if_needed() to useradd for guaranteed
  user-private groups.
- Move EOPNOTSUPP handling into set_acl_file() helper
- v3 link https://lore.kernel.org/ltp/20260603140147.50738-1-sachinp@linux.ibm.com/T/#t

V3 changes:
- Updated copyright header as per LTP format.
- v2 link https://lore.kernel.org/ltp/20260603065744.47106-1-sachinp@linux.ibm.com/T/#t

V2 changes:
- Added no chown variant of reset_test_path to skip chown step.
 acl_link01 and xattr_test01 tests are updated to use this
 variant.
 - Updated acl_user_obj01.c to correct incorrect description
- v1 link https://lore.kernel.org/ltp/20260602121958.27494-1-sachinp@linux.ibm.com/T/#t

V1 changes:
- Use ACL_LIBS variable instead of hardcoded -lacl in Makefile
- Move ACL header includes inside feature guards in acl_lib.h
- 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                               |   3 +
 testcases/kernel/fs/acl/.gitignore       |   1 +
 testcases/kernel/fs/acl/Makefile         |   8 +
 testcases/kernel/fs/acl/acl_lib.h        | 507 +++++++++++++++++++++++
 testcases/kernel/fs/acl/acl_user_obj01.c | 126 ++++++
 5 files changed, 645 insertions(+)
 create mode 100644 testcases/kernel/fs/acl/.gitignore
 create mode 100644 testcases/kernel/fs/acl/Makefile
 create mode 100644 testcases/kernel/fs/acl/acl_lib.h
 create mode 100644 testcases/kernel/fs/acl/acl_user_obj01.c

diff --git a/runtest/fs b/runtest/fs
index 1d753e0dd..2a878744b 100644
--- a/runtest/fs
+++ b/runtest/fs
@@ -87,3 +87,6 @@ binfmt_misc01 binfmt_misc01.sh
 binfmt_misc02 binfmt_misc02.sh
 
 squashfs01 squashfs01
+
+# Run the acl tests
+acl_user_obj01 acl_user_obj01
diff --git a/testcases/kernel/fs/acl/.gitignore b/testcases/kernel/fs/acl/.gitignore
new file mode 100644
index 000000000..d9c46db11
--- /dev/null
+++ b/testcases/kernel/fs/acl/.gitignore
@@ -0,0 +1 @@
+/acl_user_obj01
diff --git a/testcases/kernel/fs/acl/Makefile b/testcases/kernel/fs/acl/Makefile
new file mode 100644
index 000000000..2d9cba46d
--- /dev/null
+++ b/testcases/kernel/fs/acl/Makefile
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (c) 2026 IBM
+
+top_srcdir		?= ../../../..
+
+include $(top_srcdir)/include/mk/testcases.mk
+
+include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/testcases/kernel/fs/acl/acl_lib.h b/testcases/kernel/fs/acl/acl_lib.h
new file mode 100644
index 000000000..7fe68aa59
--- /dev/null
+++ b/testcases/kernel/fs/acl/acl_lib.h
@@ -0,0 +1,507 @@
+/* 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>
+ *
+ * Common library for ACL and extended attribute tests using xattr API
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#ifndef ACL_LIB_H
+#define ACL_LIB_H
+
+#include "config.h"
+
+#include <pwd.h>
+#include <grp.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdint.h>
+#include <endian.h>
+#include <sys/fsuid.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#ifdef HAVE_SYS_XATTR_H
+#include <sys/xattr.h>
+#endif
+#include "tst_test.h"
+#include "tst_safe_stdio.h"
+#include "tst_capability.h"
+
+#define MNTPOINT	"mntpoint"
+#define TESTDIR		MNTPOINT "/testdir"
+#define TESTFILE	TESTDIR "/testfile"
+#define TESTSYMLINK	TESTDIR "/testsymlink"
+#define XATTR_BACKUP_FILE MNTPOINT "/xattr_backup.txt"
+
+/* Extended attribute test values */
+#define XATTR_TEST_DIR_NAME	"user.test_attr"
+#define XATTR_TEST_DIR_VALUE	"test_value"
+#define XATTR_TEST_DIR_SIZE	10
+#define XATTR_TEST_FILE_NAME	"user.file_attr"
+#define XATTR_TEST_FILE_VALUE	"file_val"
+#define XATTR_TEST_FILE_SIZE	8
+#define XATTR_TEST1_NAME	"user.test1"
+#define XATTR_TEST1_VALUE	"value1"
+#define XATTR_TEST1_SIZE	6
+#define XATTR_TEST2_NAME	"user.test2"
+#define XATTR_TEST2_VALUE	"value2"
+#define XATTR_TEST2_SIZE	6
+
+/*
+ * POSIX ACL xattr format definitions
+ * These match the kernel's internal representation
+ */
+#define POSIX_ACL_XATTR_VERSION	0x0002
+
+/* ACL entry tag types */
+#define ACL_UNDEFINED_TAG	0x00
+#define ACL_USER_OBJ		0x01
+#define ACL_USER		0x02
+#define ACL_GROUP_OBJ		0x04
+#define ACL_GROUP		0x08
+#define ACL_MASK		0x10
+#define ACL_OTHER		0x20
+
+/* ACL permissions */
+#define ACL_READ		0x04
+#define ACL_WRITE		0x02
+#define ACL_EXECUTE		0x01
+
+/* ACL xattr names */
+#define XATTR_NAME_POSIX_ACL_ACCESS	"system.posix_acl_access"
+#define XATTR_NAME_POSIX_ACL_DEFAULT	"system.posix_acl_default"
+
+/* ACL type for set/get operations */
+#define ACL_TYPE_ACCESS		1
+#define ACL_TYPE_DEFAULT	2
+
+/* Convert host to little-endian */
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define cpu_to_le16(x) (x)
+#define cpu_to_le32(x) (x)
+#define le16_to_cpu(x) (x)
+#define le32_to_cpu(x) (x)
+#else
+#define cpu_to_le16(x) __builtin_bswap16(x)
+#define cpu_to_le32(x) __builtin_bswap32(x)
+#define le16_to_cpu(x) __builtin_bswap16(x)
+#define le32_to_cpu(x) __builtin_bswap32(x)
+#endif
+
+/*
+ * POSIX ACL xattr format as stored in kernel
+ * This is the on-disk/in-xattr representation
+ */
+struct posix_acl_xattr_header {
+	uint32_t a_version;
+};
+
+struct posix_acl_xattr_entry {
+	uint16_t e_tag;
+	uint16_t e_perm;
+	uint32_t e_id;
+};
+
+/*
+ * Combined xattr structure for ACL operations
+ */
+struct acl_xattr {
+	struct posix_acl_xattr_header header;
+	struct posix_acl_xattr_entry entries[];
+};
+
+/*
+ * In-memory ACL representation for building ACLs
+ */
+#define MAX_ACL_ENTRIES 32
+
+struct acl_entry {
+	uint16_t tag;
+	uint16_t perm;
+	uint32_t id;
+};
+
+struct acl {
+	int count;
+	struct acl_entry entries[MAX_ACL_ENTRIES];
+};
+
+/*
+ * SAFE_TRY_UNLINK - unlink a file, ignoring ENOENT
+ * Won't TBROK if file doesn't exist
+ */
+#define SAFE_TRY_UNLINK(path) do { \
+	if (unlink(path) == -1 && errno != ENOENT) \
+		tst_brk(TBROK | TERRNO, "unlink(%s) failed", path); \
+} while (0)
+
+/*
+ * SAFE_TRY_RMDIR - remove a directory, ignoring ENOENT
+ * Won't TBROK if directory doesn't exist
+ */
+#define SAFE_TRY_RMDIR(path) do { \
+	if (rmdir(path) == -1 && errno != ENOENT) \
+		tst_brk(TBROK | TERRNO, "rmdir(%s) failed", path); \
+} while (0)
+
+static inline void reset_test_path(void)
+{
+	SAFE_TRY_UNLINK(TESTSYMLINK);
+	SAFE_TRY_UNLINK(TESTFILE);
+	SAFE_TRY_RMDIR(TESTDIR);
+
+	SAFE_MKDIR(TESTDIR, 0755);
+}
+
+static inline void cleanup_testfile(void)
+{
+	SAFE_TRY_UNLINK(TESTFILE);
+}
+
+#ifdef HAVE_SYS_XATTR_H
+
+/*
+ * Initialize an empty ACL structure
+ */
+static inline struct acl *acl_init(void)
+{
+	struct acl *acl = SAFE_MALLOC(sizeof(struct acl));
+
+	acl->count = 0;
+	return acl;
+}
+
+/*
+ * Free an ACL structure
+ */
+static inline void acl_free(struct acl *acl)
+{
+	free(acl);
+}
+
+/*
+ * Add an ACL entry to the ACL structure
+ */
+static inline int acl_add_entry(struct acl *acl, uint16_t tag, uint16_t perm,
+				uint32_t id)
+{
+	if (acl->count >= MAX_ACL_ENTRIES) {
+		errno = ENOMEM;
+		return -1;
+	}
+
+	acl->entries[acl->count].tag = tag;
+	acl->entries[acl->count].perm = perm;
+	acl->entries[acl->count].id = id;
+	acl->count++;
+	return 0;
+}
+
+/*
+ * Convert ACL type to xattr name
+ */
+static inline const char *acl_type_to_name(int type)
+{
+	if (type == ACL_TYPE_ACCESS)
+		return XATTR_NAME_POSIX_ACL_ACCESS;
+	else if (type == ACL_TYPE_DEFAULT)
+		return XATTR_NAME_POSIX_ACL_DEFAULT;
+	else
+		return NULL;
+}
+
+/*
+ * Set ACL on a file using xattr.
+ *
+ * The kernel stores access ACLs only when they differ from the file mode.
+ * If the ACL is equivalent to st_mode, the xattr is removed and future
+ * getxattr() calls return ENODATA. Mirror libacl semantics by treating
+ * ENODATA as a valid minimal ACL derived from st_mode.
+ */
+static inline int acl_set_file(const char *path, int type, struct acl *acl)
+{
+	const char *xattr_name;
+	size_t size;
+	char *buf;
+	struct posix_acl_xattr_header *header;
+	struct posix_acl_xattr_entry *entries;
+	int i, ret;
+
+	xattr_name = acl_type_to_name(type);
+	if (!xattr_name) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	size = sizeof(struct posix_acl_xattr_header) +
+	       acl->count * sizeof(struct posix_acl_xattr_entry);
+
+	buf = malloc(size);
+	if (!buf)
+		return -1;
+
+	header = (struct posix_acl_xattr_header *)buf;
+	header->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
+
+	entries = (struct posix_acl_xattr_entry *)(buf + sizeof(*header));
+
+	for (i = 0; i < acl->count; i++) {
+		entries[i].e_tag = cpu_to_le16(acl->entries[i].tag);
+		entries[i].e_perm = cpu_to_le16(acl->entries[i].perm);
+		entries[i].e_id = cpu_to_le32(acl->entries[i].id);
+	}
+
+	ret = setxattr(path, xattr_name, buf, size, 0);
+	free(buf);
+
+	return ret;
+}
+
+static inline void acl_add_mode_entries(struct acl *acl, mode_t mode)
+{
+	acl_add_entry(acl, ACL_USER_OBJ, (mode >> 6) & 07, 0);
+	acl_add_entry(acl, ACL_GROUP_OBJ, (mode >> 3) & 07, 0);
+	acl_add_entry(acl, ACL_OTHER, mode & 07, 0);
+}
+
+/*
+ * Synthesize an ACL from file mode bits.
+ * Used when no xattr exists for an access ACL.
+ */
+static inline struct acl *acl_from_mode(const char *path)
+{
+	struct acl *acl;
+	struct stat st;
+
+	if (stat(path, &st) < 0)
+		return NULL;
+
+	acl = acl_init();
+	acl_add_mode_entries(acl, st.st_mode);
+
+	return acl;
+}
+
+/*
+ * Get ACL from a file using xattr.
+ *
+ * Access ACLs equivalent to file mode may not have a backing xattr at all.
+ * In that case synthesize the base ACL from st_mode so callers observe the
+ * same behavior as acl_get_file(3).
+ */
+static inline struct acl *acl_get_file(const char *path, int type)
+{
+	const char *xattr_name;
+	ssize_t size;
+	struct acl_xattr *ax;
+	struct acl *acl;
+	int i, count;
+
+	xattr_name = acl_type_to_name(type);
+	if (!xattr_name) {
+		errno = EINVAL;
+		return NULL;
+	}
+
+	size = getxattr(path, xattr_name, NULL, 0);
+	if (size < 0) {
+		if (errno != ENODATA || type != ACL_TYPE_ACCESS)
+			return NULL;
+
+		return acl_from_mode(path);
+	}
+
+	/* Handle race: xattr removed between size check and actual read */
+	if (size == 0)
+		return acl_from_mode(path);
+
+	ax = malloc(size);
+	if (!ax)
+		return NULL;
+
+	size = getxattr(path, xattr_name, ax, size);
+	if (size < 0) {
+		free(ax);
+		/* Handle race: xattr removed between size check and read */
+		if (errno == ENODATA && type == ACL_TYPE_ACCESS)
+			return acl_from_mode(path);
+		return NULL;
+	}
+
+	if (le32_to_cpu(ax->header.a_version) != POSIX_ACL_XATTR_VERSION) {
+		free(ax);
+		errno = EINVAL;
+		return NULL;
+	}
+
+	count = (size - sizeof(ax->header)) /
+		sizeof(struct posix_acl_xattr_entry);
+
+	acl = acl_init();
+	if (!acl) {
+		free(ax);
+		return NULL;
+	}
+
+	for (i = 0; i < count; i++) {
+		uint16_t tag = le16_to_cpu(ax->entries[i].e_tag);
+		uint16_t perm = le16_to_cpu(ax->entries[i].e_perm);
+		uint32_t id = le32_to_cpu(ax->entries[i].e_id);
+
+		if (acl_add_entry(acl, tag, perm, id) < 0) {
+			acl_free(acl);
+			free(ax);
+			return NULL;
+		}
+	}
+
+	free(ax);
+	return acl;
+}
+
+/*
+ * Check if an ACL entry has a specific permission
+ */
+static inline int acl_entry_has_perm(struct acl_entry *entry, uint16_t perm)
+{
+	return (entry->perm & perm) == perm;
+}
+
+/*
+ * Check if an ACL entry has all rwx permissions
+ */
+static inline int acl_entry_has_rwx(struct acl_entry *entry)
+{
+	return acl_entry_has_perm(entry,
+				  ACL_READ | ACL_WRITE | ACL_EXECUTE);
+}
+
+/*
+ * Find an ACL entry by tag type
+ */
+static inline struct acl_entry *acl_find_entry(struct acl *acl, uint16_t tag,
+					       uint32_t id)
+{
+	int i;
+
+	for (i = 0; i < acl->count; i++) {
+		if (acl->entries[i].tag == tag) {
+			if (tag == ACL_USER || tag == ACL_GROUP) {
+				if (acl->entries[i].id == id)
+					return &acl->entries[i];
+			} else {
+				return &acl->entries[i];
+			}
+		}
+	}
+
+	return NULL;
+}
+
+/*
+ * Update ACL mask permissions
+ */
+static inline int acl_set_mask_perms(struct acl *acl, uint16_t perm)
+{
+	struct acl_entry *mask_entry = acl_find_entry(acl, ACL_MASK, 0);
+
+	if (!mask_entry) {
+		errno = ENOENT;
+		return -1;
+	}
+
+	mask_entry->perm = perm;
+	return 0;
+}
+
+static inline void create_file_as(uid_t uid, gid_t gid, mode_t mode,
+				   int use_umask, mode_t mask, int exp_errno)
+{
+	pid_t pid;
+
+	pid = SAFE_FORK();
+	if (!pid) {
+		uid_t fsuid;
+		gid_t fsgid;
+		struct tst_cap_user_header hdr = {
+			.version = 0x20080522,
+			.pid = 0,
+		};
+		struct tst_cap_user_data data[2] = {};
+
+		SAFE_SETGROUPS(0, NULL);
+		SAFE_SETRESGID(gid, gid, gid);
+		SAFE_SETRESUID(uid, uid, uid);
+
+		/* Drop all capabilities to ensure DAC checks are enforced */
+		if (tst_capset(&hdr, data) < 0)
+			tst_brk(TBROK | TERRNO, "capset failed");
+
+		/*
+		 * setfsuid()/setfsgid() return the previous value, not -1 on
+		 * failure. Verify the effective filesystem credentials by
+		 * reading them back.
+		 */
+		setfsuid(uid);
+		fsuid = setfsuid((uid_t)-1);
+		if (fsuid != uid)
+			tst_brk(TBROK,
+				"setfsuid verification failed, expected %u got %u",
+				(unsigned int)uid, (unsigned int)fsuid);
+
+		setfsgid(gid);
+		fsgid = setfsgid((gid_t)-1);
+		if (fsgid != gid)
+			tst_brk(TBROK,
+				"setfsgid verification failed, expected %u got %u",
+				(unsigned int)gid, (unsigned int)fsgid);
+
+		if (use_umask)
+			umask(mask);
+
+		if (exp_errno) {
+			TST_EXP_FAIL2(open(TESTFILE, O_CREAT | O_WRONLY, mode),
+				      exp_errno, "open(%s)", TESTFILE);
+		} else {
+			TST_EXP_FD(open(TESTFILE, O_CREAT | O_WRONLY, mode),
+				   "open(%s)", TESTFILE);
+			if (TST_RET >= 0)
+				SAFE_CLOSE(TST_RET);
+		}
+
+		exit(0);
+	}
+
+	tst_reap_children();
+}
+
+static inline void try_create_as(uid_t uid, gid_t gid, mode_t mode,
+				  int exp_errno)
+{
+	create_file_as(uid, gid, mode, 0, 0, exp_errno);
+}
+
+static inline void create_with_umask_as(uid_t uid, gid_t gid, mode_t mode,
+					 mode_t mask, int exp_errno)
+{
+	create_file_as(uid, gid, mode, 1, mask, exp_errno);
+}
+
+static inline void cleanup_test_paths(void)
+{
+	SAFE_TRY_UNLINK(TESTSYMLINK);
+	SAFE_TRY_UNLINK(TESTFILE);
+	SAFE_TRY_RMDIR(TESTDIR);
+}
+
+#endif /* HAVE_SYS_XATTR_H */
+
+#endif /* ACL_LIB_H */
diff --git a/testcases/kernel/fs/acl/acl_user_obj01.c b/testcases/kernel/fs/acl/acl_user_obj01.c
new file mode 100644
index 000000000..a442f1131
--- /dev/null
+++ b/testcases/kernel/fs/acl/acl_user_obj01.c
@@ -0,0 +1,126 @@
+// 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_USER_OBJ permissions using direct xattr manipulation.
+ *
+ * Verify that owner permissions (ACL_USER_OBJ) correctly control access
+ * to files and directories. The test validates that:
+ * - ACL_USER_OBJ permissions are applied directly as the owner bits
+ * - Setting ACL_USER_OBJ=rwx via :manpage:`setxattr(2)` overrides 
+ *   a previous :manpage:`chmod(2)` restriction
+ * - Owner permissions work independently of group and other permissions
+ *
+ * This test uses arbitrary UIDs without creating actual users, testing
+ * only the kernel ACL implementation.
+ */
+
+#include "acl_lib.h"
+
+#ifdef HAVE_SYS_XATTR_H
+
+#define TEST_UID 1000
+#define TEST_GID 1000
+
+/*
+ * Test permission bits deny access.
+ * Owner should be denied file creation when directory mode is 0555.
+ */
+static void test_deny_by_mode(void)
+{
+	tst_res(TINFO, "Testing permission bits deny access");
+	reset_test_path();
+
+	SAFE_CHOWN(TESTDIR, TEST_UID, TEST_GID);
+	SAFE_CHMOD(TESTDIR, 0555);
+
+	try_create_as(TEST_UID, TEST_GID, 0644, EACCES);
+}
+
+/*
+ * Test ACL_USER_OBJ grants access.
+ * Setting ACL_USER_OBJ=rwx should restore owner write permission and
+ * allow file creation after the restrictive mode baseline.
+ */
+static void test_grant_by_acl(void)
+{
+	struct acl *acl;
+
+	tst_res(TINFO, "Testing ACL_USER_OBJ grants access");
+	reset_test_path();
+
+	SAFE_CHOWN(TESTDIR, TEST_UID, TEST_GID);
+	SAFE_CHMOD(TESTDIR, 0555);
+
+	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_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(TEST_UID, TEST_GID, 0644, 0);
+
+	cleanup_testfile();
+}
+
+static void run(unsigned int n)
+{
+	switch (n) {
+	case 0:
+		test_deny_by_mode();
+		break;
+	case 1:
+		test_grant_by_acl();
+		break;
+	}
+}
+
+static void setup(void)
+{
+	reset_test_path();
+}
+
+static void cleanup(void)
+{
+	cleanup_test_paths();
+}
+
+static struct tst_test test = {
+	.test = run,
+	.tcnt = 2,
+	.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

  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 ` Sachin Sant [this message]
2026-06-13 10:36   ` [LTP] fs/acl: Add ACL_USER_OBJ permission test linuxtestproject.agent
2026-06-13  9:05 ` [LTP] [PATCH v8 2/8] fs/acl: Add ACL mask interaction tests Sachin Sant
2026-06-13  9:05 ` [LTP] [PATCH v8 3/8] fs/acl: Add ACL_OTHER permission test 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-2-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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox