All of lore.kernel.org
 help / color / mirror / Atom feed
* Re: [LTP] fs/acl: Add ACL_USER_OBJ permission test
  2026-06-08  9:21 [LTP] [PATCH v5 1/8] " Sachin Sant
@ 2026-06-08 11:01 ` linuxtestproject.agent
  0 siblings, 0 replies; 20+ messages in thread
From: linuxtestproject.agent @ 2026-06-08 11:01 UTC (permalink / raw)
  To: Sachin Sant; +Cc: ltp

Hi Sachin,

On Mon, 8 Jun 2026 14:51:53 +0530, Sachin Sant wrote:
> fs/acl: Add ACL_USER_OBJ permission test

--- [PATCH 1/8] ---

> +#include <sys/xattr.h>

acl_lib.h includes <sys/xattr.h> unconditionally. LTP's configure.ac
checks for this header and defines HAVE_SYS_XATTR_H. Other xattr tests
(e.g. setxattr01, setxattr02, setxattr03) guard their code with
#ifdef HAVE_SYS_XATTR_H.

Each .c test file should wrap all test code in a file-level guard with
TST_TEST_TCONF in the #else branch, e.g.:

  #include "acl_lib.h"

  #ifdef HAVE_SYS_XATTR_H

  /* ... all test code ... */

  static struct tst_test test = { ... };

  #else
      TST_TEST_TCONF("sys/xattr.h is not available");
  #endif

Without this, the tests will fail to compile on systems where
sys/xattr.h is not available.

--- [PATCH 6/8] ---

> +static struct tst_test test = {
> +	.test_all = run,
> +	.setup = setup,
> +	.cleanup = cleanup,
> +	.needs_root = 1,
> +	.mount_device = 1,
> +	.mntpoint = MNTPOINT,
> +	.forks_child = 1,

acl_link01 never forks a child process. It does not call SAFE_FORK(),
try_create_as(), or create_file_as(). Should .forks_child be dropped?

--- [PATCH 7/8] ---

> +	TST_EXP_PASS_SILENT(setxattr(TESTDIR, XATTR_TEST_DIR_NAME,
> +				     XATTR_TEST_DIR_VALUE,
> +				     XATTR_TEST_DIR_SIZE, 0));
> +	if (!TST_PASS) {
> +		if (TST_ERR == EOPNOTSUPP) {
> +			tst_res(TCONF, "Extended attributes not supported");
> +			return;
> +		}
> +		tst_res(TFAIL, "setxattr on directory failed");
> +		return;
> +	}

TST_EXP_PASS_SILENT already reports TFAIL on failure. Then the code
reports TFAIL again (or TCONF for EOPNOTSUPP), resulting in
double-reporting. For the EOPNOTSUPP case the output will contain a
contradictory TFAIL followed by TCONF.

Since custom failure handling is needed here (EOPNOTSUPP -> TCONF),
TEST() should be used instead:

  TEST(setxattr(TESTDIR, XATTR_TEST_DIR_NAME,
                XATTR_TEST_DIR_VALUE, XATTR_TEST_DIR_SIZE, 0));
  if (TST_RET == -1) {
      if (TST_ERR == EOPNOTSUPP) {
          tst_res(TCONF, "Extended attributes not supported");
          return;
      }
      tst_res(TFAIL | TTERRNO, "setxattr on directory failed");
      return;
  }

The same pattern appears for the second setxattr call in test_xattr()
and the first setxattr call in test_xattr_backup_restore().

> +	.forks_child = 1,

Same as patch 6/8: xattr_test01 never forks a child process.
Should .forks_child be dropped?

--- Applies to patches 2/8 through 7/8 ---

> + * [Algorithm]
> + *
> + * 1. Set up ACL with full permissions for the entry

The [Algorithm] section must use a bulleted list with "-" markers,
not numbered lists. This applies to all six tests that have an
[Algorithm] block (acl_mask01, acl_other01, acl_inherit01,
acl_file_ops01, acl_link01, xattr_test01).

Verdict: Needs revision

---
Note:

The agent can sometimes produce false positives although often its
findings are genuine. If you find issues with the review, please
comment this email or ignore the suggestions.

Regards,
LTP AI Reviewer

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

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

* Re: [LTP] fs/acl: Add ACL_USER_OBJ permission test
  2026-06-12 10:24 [LTP] [PATCH v6 1/8] " Sachin Sant
@ 2026-06-12 12:27 ` linuxtestproject.agent
  0 siblings, 0 replies; 20+ messages in thread
From: linuxtestproject.agent @ 2026-06-12 12:27 UTC (permalink / raw)
  To: Sachin Sant; +Cc: ltp

Hi Sachin,

On Fri, 12 Jun 2026 15:54:55 +0530, Sachin Sant wrote:
> fs/acl: Add ACL_USER_OBJ permission test

--- [PATCH 1/8] ---

> +	SAFE_SETGROUPS(0, NULL);
> +
> +	if (setresgid(gid, gid, gid) < 0)
> +		tst_brk(TBROK | TERRNO, "setresgid(%u) failed",
> +			(unsigned int)gid);
> +
> +	if (setresuid(uid, uid, uid) < 0)
> +		tst_brk(TBROK | TERRNO, "setresuid(%u) failed",
> +			(unsigned int)uid);

SAFE_SETRESGID() and SAFE_SETRESUID() exist in
include/tst_safe_macros.h. Since SAFE_SETGROUPS() is already
used on the line above, could these be switched to the SAFE_
variants as well?

> +		if (exp_errno) {
> +			TST_EXP_FAIL(open(TESTFILE, O_CREAT | O_WRONLY, mode),
> +				     exp_errno, "open(%s)", TESTFILE);

open() returns a positive file descriptor on success, not 0.
TST_EXP_FAIL2 should be used here instead of TST_EXP_FAIL.

With TST_EXP_FAIL the PASS_COND is TST_RET == 0, so if open()
unexpectedly succeeds with e.g. fd 5, the macro falls through
to the "invalid retval" branch instead of reporting "succeeded".

Verdict: Needs revision

---
Note:

The agent can sometimes produce false positives although often its
findings are genuine. If you find issues with the review, please
comment this email or ignore the suggestions.

Regards,
LTP AI Reviewer

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

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

* Re: [LTP] fs/acl: Add ACL_USER_OBJ permission test
  2026-06-12 17:19 [LTP] [PATCH v7 1/8] " Sachin Sant
@ 2026-06-12 19:13 ` linuxtestproject.agent
  0 siblings, 0 replies; 20+ messages in thread
From: linuxtestproject.agent @ 2026-06-12 19:13 UTC (permalink / raw)
  To: Sachin Sant; +Cc: ltp

Hi Sachin,

On Fri, 12 Jun 2026, Sachin Sant wrote:
> fs/acl: Add ACL_USER_OBJ permission test

--- [PATCH 1/8] ---

> +static inline void reset_test_path_no_chown(void)
> +{
> +	SAFE_TRY_UNLINK(TESTSYMLINK);
> +	SAFE_TRY_UNLINK(TESTFILE);
> +	SAFE_TRY_RMDIR(TESTDIR);
> +
> +	SAFE_MKDIR(TESTDIR, 0755);
> +}
> +
> +static inline void reset_test_path(void)
> +{
> +	reset_test_path_no_chown();
> +}

reset_test_path() and reset_test_path_no_chown() are identical.
The "_no_chown" suffix implies that reset_test_path() performs a
chown, but it does not. Could this cause confusion for future
maintainers?

If both need to exist for readability, the naming should reflect
the actual difference (which is currently none). Otherwise, one
of them could be dropped.

> +/*\
> + * 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 setxattr() overrides a previous
> + *   chmod restriction

setxattr() should use the RST manpage role for the test catalog,
e.g. :manpage:`setxattr(2)`.

--- [PATCH 5/8] ---

> +/*\
> + * Test chmod and chown interaction with ACLs using direct xattr manipulation.
> + *
> + * Verify that standard file operations (chmod, chown) interact correctly
> + * with ACLs:
> + * - chmod should update ACL_USER_OBJ, ACL_GROUP_OBJ, and ACL_OTHER entries
> + * - chown should change file owner/group without affecting ACL entries

Since the doc comment block is exported to the test catalog, chmod
and chown should use the RST manpage role, e.g.
:manpage:`chmod(2)` and :manpage:`chown(2)`.

> +static struct tst_test test = {
> +	.test = run,
> +	.tcnt = 2,
> +	.setup = setup,
> +	.cleanup = cleanup,
> +	.needs_root = 1,
> +	.mount_device = 1,
> +	.mntpoint = MNTPOINT,
> +	.forks_child = 1,

This test never calls SAFE_FORK() or any forking helper. Is
.forks_child = 1 needed here?

Verdict - Needs revision

---
Note:

The agent can sometimes produce false positives although often its
findings are genuine. If you find issues with the review, please
comment this email or ignore the suggestions.

Regards,
LTP AI Reviewer

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

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

* Re: [LTP] fs/acl: Add ACL_USER_OBJ permission test
  2026-06-13  9:05 [LTP] [PATCH v8 1/8] " Sachin Sant
@ 2026-06-13 10:36 ` linuxtestproject.agent
  0 siblings, 0 replies; 20+ messages in thread
From: linuxtestproject.agent @ 2026-06-13 10:36 UTC (permalink / raw)
  To: Sachin Sant; +Cc: ltp

Hi Sachin,

On Sat Jun 13 14:35:36 2026 +0530, Sachin Sant wrote:
> fs/acl: Add ACL_USER_OBJ permission test

--- [PATCH 1/8] ---

> + * to files and directories. The test validates that:
> + * - ACL_USER_OBJ permissions are applied directly as the owner bits

RST requires a blank line before a bulleted list, otherwise the
list items are parsed as continuation of the preceding paragraph.
Could a blank ` *` line be inserted after "that:"?

--- [PATCH 2/8] ---

> + * For each entry type (ACL_USER, ACL_GROUP, ACL_GROUP_OBJ):
> + * - Set up ACL with full permissions for the entry

Same RST issue here -- a blank ` *` line is needed between the
introductory sentence and the first list item.

--- [PATCH 5/8] ---

> + * Test 1 - :manpage:`chmod(2)` interaction:
> + * - Create file with read-only ACL entries

Missing blank ` *` line before the list.

> + * Test 2 - :manpage:`chown(2)` interaction:
> + * - Create file with specific ACL entries (rw for user, r for group/other)

Same here.

--- [PATCH 7/8] ---

> +	if (removexattr(TESTFILE, XATTR_TEST_FILE_NAME) == -1) {
> +		tst_res(TFAIL | TERRNO, "removexattr failed");

removexattr() is part of the tested functionality and should be
wrapped in TEST(), e.g.:

  TEST(removexattr(TESTFILE, XATTR_TEST_FILE_NAME));
  if (TST_RET == -1) {
      tst_res(TFAIL | TTERRNO, "removexattr failed");

> +	size = getxattr(TESTFILE, XATTR_TEST_FILE_NAME, value,
> +			sizeof(value));
> +	if (size >= 0 || errno != ENODATA) {

This verifies that removal took effect and checks for a specific
errno, so it should also use TEST() and TST_ERR instead of errno
directly, e.g.:

  TEST(getxattr(TESTFILE, XATTR_TEST_FILE_NAME, value,
                sizeof(value)));
  if (TST_RET >= 0 || TST_ERR != ENODATA) {

Verdict - Needs revision

---
Note:

The agent can sometimes produce false positives although often its
findings are genuine. If you find issues with the review, please
comment this email or ignore the suggestions.

Regards,
LTP AI Reviewer

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

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

* Re: [LTP] fs/acl: Add ACL_USER_OBJ permission test
  2026-06-15  5:29 [LTP] [PATCH v9 1/8] " Sachin Sant
@ 2026-06-15  6:32 ` linuxtestproject.agent
  0 siblings, 0 replies; 20+ messages in thread
From: linuxtestproject.agent @ 2026-06-15  6:32 UTC (permalink / raw)
  To: Sachin Sant; +Cc: ltp

Hi Sachin,

On Mon, 15 Jun 2026, Sachin Sant wrote:
> fs/acl: Add ACL_USER_OBJ permission test

--- [PATCH 2/8] ---

> +static void test_acl_user_with_mask(void)
> ...
> +static void test_acl_group_with_mask(void)
> ...
> +static void test_acl_group_obj_with_mask(void)
> ...
> +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;
> +	}
> +}

The three test functions share the same algorithmic structure:
set up ACL with full permissions for an entry type, verify
access is granted with mask=rwx, clear the mask, verify
access is denied. They differ only in the ACL entry type
(ACL_USER / ACL_GROUP / ACL_GROUP_OBJ) and the UID/GID
used.

Could these be collapsed into a single parametrized test
function driven by a struct tcase array? Something along
the lines of:

  struct tcase {
      uint16_t tag;
      uid_t uid;
      gid_t gid;
      uid_t owner_uid;
      gid_t owner_gid;
      const char *desc;
  } tcases[] = {
      {ACL_USER, USER3_UID, USER3_GID,
       TEST_UID, TEST_GID, "ACL_USER with mask"},
      {ACL_GROUP, USER2_UID, USER2_GID,
       TEST_UID, TEST_GID, "ACL_GROUP with mask"},
      {ACL_GROUP_OBJ, USER2_UID, USER2_GID,
       TEST_UID, USER2_GID, "ACL_GROUP_OBJ with mask"},
  };

That would remove roughly 130 lines of duplicated logic and
make the data-driven pattern explicit.

Verdict - Needs revision

---
Note:

The agent can sometimes produce false positives although often its
findings are genuine. If you find issues with the review, please
comment this email or ignore the suggestions.

Regards,
LTP AI Reviewer

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

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

* [LTP] [PATCH v10 0/8] Convert shell-based ACL test (tacl_xattr.sh) to C
@ 2026-06-15  7:25 Sachin Sant
  2026-06-15  7:25 ` [LTP] [PATCH v10 1/8] fs/acl: Add ACL_USER_OBJ permission test Sachin Sant
                   ` (7 more replies)
  0 siblings, 8 replies; 20+ messages in thread
From: Sachin Sant @ 2026-06-15  7:25 UTC (permalink / raw)
  To: ltp

This patch series converts the existing shell-based ACL
test (tacl_xattr.sh) to C implementation, providing better
integration with the LTP test framework and more precise
control over test execution.

v9 -> v10
Updated patch 2/8 to incorporate review comments. Rest of the
patches remain unchanged.

v8 -> v9
Updated patches 1, 2, 5, and 7 to incorporate review comments.

v7 -> v8
Updated patches 1, 5, 6 and 7 to incorporate review comments.

v6 -> v7
Updated 1/8 to address review comments. Rest of the patches
in the series remain unchanged.

v5 -> v6
Updated patches 1 to 7 to address review comments. Added
HAVE_SYS_XATTR_H guards for systems without xattr support

v4 -> v5
Updated patches 1 to 7 to address review comments. Tests rely on
kernel only implementation and removes dependeny on acl library
and useradd/del commands

v3 -> v4
Updated patches 1/8, 4/8 & 6/8 to address review comments.
No changes to other patches in the series.

v2 -> v3
Updated patches 1 through 7 to address review comments.

v1 -> v2
Updated patches 1/8, 6/8 and 7/8 to address review comments.
Remaining patches remain unchanged

Addresses part of issue #1265

The conversion splits functionality into seven focused test files.
Patch 1/8 adds acl_user_obj01.c
Patch 2/8 adds acl_mask01.c
Patch 3/8 adds acl_other01.c
Patch 4/8 adds acl_inherit01.c
Patch 5/8 adds acl_file_ops01.c
Patch 6/8 adds acl_link01.c
Patch 7/8 adds xattr_test01.c

The code has been successfully tested on SLES (kernel 6.12)
and fedora (kernel 7.0) releases on ppc64le arch.

Test build is clean in various distros. CI build report at
https://github.com/sacsant/ltp/actions/runs/27525229838

Sachin Sant (8):
  fs/acl: Add ACL_USER_OBJ permission test
  fs/acl: Add ACL mask interaction tests
  fs/acl: Add ACL_OTHER permission test
  fs/acl: Add default ACL inheritance test
  fs/acl: Add chmod/chown ACL interaction tests
  fs/acl: Add ACL symlink operations test
  fs/acl: Add extended attributes test
  fs/acl: Remove old shell-based ACL test

 runtest/fs                               |   9 +
 testcases/kernel/fs/acl/.gitignore       |   7 +
 testcases/kernel/fs/acl/Makefile         |   8 +
 testcases/kernel/fs/acl/acl_file_ops01.c | 259 ++++++++
 testcases/kernel/fs/acl/acl_inherit01.c  | 113 ++++
 testcases/kernel/fs/acl/acl_lib.h        | 507 ++++++++++++++
 testcases/kernel/fs/acl/acl_link01.c     | 215 ++++++
 testcases/kernel/fs/acl/acl_mask01.c     | 274 ++++++++
 testcases/kernel/fs/acl/acl_other01.c    | 104 +++
 testcases/kernel/fs/acl/acl_user_obj01.c | 127 ++++
 testcases/kernel/fs/acl/tacl_xattr.sh    | 807 -----------------------
 testcases/kernel/fs/acl/xattr_test01.c   | 380 +++++++++++
 12 files changed, 2003 insertions(+), 807 deletions(-)
 create mode 100644 testcases/kernel/fs/acl/.gitignore
 create mode 100644 testcases/kernel/fs/acl/Makefile
 create mode 100644 testcases/kernel/fs/acl/acl_file_ops01.c
 create mode 100644 testcases/kernel/fs/acl/acl_inherit01.c
 create mode 100644 testcases/kernel/fs/acl/acl_lib.h
 create mode 100644 testcases/kernel/fs/acl/acl_link01.c
 create mode 100644 testcases/kernel/fs/acl/acl_mask01.c
 create mode 100644 testcases/kernel/fs/acl/acl_other01.c
 create mode 100644 testcases/kernel/fs/acl/acl_user_obj01.c
 delete mode 100755 testcases/kernel/fs/acl/tacl_xattr.sh
 create mode 100644 testcases/kernel/fs/acl/xattr_test01.c

-- 
2.39.1


-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

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

* [LTP] [PATCH v10 1/8] fs/acl: Add ACL_USER_OBJ permission test
  2026-06-15  7:25 [LTP] [PATCH v10 0/8] Convert shell-based ACL test (tacl_xattr.sh) to C Sachin Sant
@ 2026-06-15  7:25 ` Sachin Sant
  2026-06-15  8:33   ` [LTP] " linuxtestproject.agent
  2026-06-15  7:25 ` [LTP] [PATCH v10 2/8] fs/acl: Add ACL mask interaction tests Sachin Sant
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 20+ messages in thread
From: Sachin Sant @ 2026-06-15  7:25 UTC (permalink / raw)
  To: ltp

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>
---
V10 changes:
- No change

V9 changes:
- Use RST manpage formatted documentation
- v8 link https://lore.kernel.org/ltp/20260613090543.78643-1-sachinp@linux.ibm.com/T/#t

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 | 127 ++++++
 5 files changed, 646 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..89291d275
--- /dev/null
+++ b/testcases/kernel/fs/acl/acl_user_obj01.c
@@ -0,0 +1,127 @@
+// 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

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

* [LTP] [PATCH v10 2/8] fs/acl: Add ACL mask interaction tests
  2026-06-15  7:25 [LTP] [PATCH v10 0/8] Convert shell-based ACL test (tacl_xattr.sh) to C Sachin Sant
  2026-06-15  7:25 ` [LTP] [PATCH v10 1/8] fs/acl: Add ACL_USER_OBJ permission test Sachin Sant
@ 2026-06-15  7:25 ` Sachin Sant
  2026-06-15  7:25 ` [LTP] [PATCH v10 3/8] fs/acl: Add ACL_OTHER permission test Sachin Sant
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 20+ messages in thread
From: Sachin Sant @ 2026-06-15  7:25 UTC (permalink / raw)
  To: ltp

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, ACL_GROUP, and ACL_GROUP_OBJ
permissions are 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>
---
V10 changes:
- Collapsed into a single parametrized test function driven
  by a struct tcase array.
- v9 link https://lore.kernel.org/ltp/20260615052953.18183-1-sachinp@linux.ibm.com/T/#t

V9 changes:
- Use RST manpage formatted documentation
- v8 link https://lore.kernel.org/ltp/20260613090543.78643-1-sachinp@linux.ibm.com/T/#t

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 | 175 +++++++++++++++++++++++++++
 3 files changed, 177 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..8803e91eb
--- /dev/null
+++ b/testcases/kernel/fs/acl/acl_mask01.c
@@ -0,0 +1,175 @@
+// 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]
+ *
+ * The test uses a parametrized approach with three test cases, one for each
+ * entry type (ACL_USER, ACL_GROUP, ACL_GROUP_OBJ). For each test case:
+ *
+ * - Set up ACL with full permissions (rwx) for the entry type
+ * - 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
+
+static struct tcase {
+	uint16_t tag;
+	uid_t uid;
+	gid_t gid;
+	uid_t owner_uid;
+	gid_t owner_gid;
+	const char *desc;
+} tcases[] = {
+	{ACL_USER, USER3_UID, USER3_GID, TEST_UID, TEST_GID,
+	 "ACL_USER with mask"},
+	{ACL_GROUP, USER2_UID, USER2_GID, TEST_UID, TEST_GID,
+	 "ACL_GROUP with mask"},
+	{ACL_GROUP_OBJ, USER2_UID, USER2_GID, TEST_UID, USER2_GID,
+	 "ACL_GROUP_OBJ with mask"},
+};
+
+/*
+ * Test ACL mask interaction with different entry types.
+ * The mask acts as an upper bound on permissions for ACL_USER,
+ * ACL_GROUP, and ACL_GROUP_OBJ entries.
+ */
+static void run(unsigned int n)
+{
+	struct tcase *tc = &tcases[n];
+	struct acl *acl;
+
+	tst_res(TINFO, "Testing %s", tc->desc);
+	reset_test_path();
+
+	SAFE_CHOWN(TESTDIR, tc->owner_uid, tc->owner_gid);
+	SAFE_CHMOD(TESTDIR, 0550);
+
+	acl = acl_init();
+
+	/* Set up ACL with full permissions for the entry type */
+	acl_add_entry(acl, ACL_USER_OBJ,
+		      ACL_READ | ACL_WRITE | ACL_EXECUTE, 0);
+
+	if (tc->tag == ACL_USER) {
+		acl_add_entry(acl, ACL_USER,
+			      ACL_READ | ACL_WRITE | ACL_EXECUTE, tc->uid);
+		acl_add_entry(acl, ACL_GROUP_OBJ, 0, 0);
+	} else if (tc->tag == ACL_GROUP) {
+		acl_add_entry(acl, ACL_GROUP_OBJ, 0, 0);
+		acl_add_entry(acl, ACL_GROUP,
+			      ACL_READ | ACL_WRITE | ACL_EXECUTE, tc->gid);
+	} else {
+		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);
+
+	/* Verify access is granted with mask=rwx */
+	try_create_as(tc->uid, tc->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);
+
+	/* Verify access is denied with mask=--- */
+	try_create_as(tc->uid, tc->gid, 0644, EACCES);
+
+	/* Restore ownership for ACL_GROUP_OBJ case */
+	if (tc->tag == ACL_GROUP_OBJ)
+		SAFE_CHOWN(TESTDIR, TEST_UID, TEST_GID);
+}
+
+static void setup(void)
+{
+	reset_test_path();
+}
+
+static void cleanup(void)
+{
+	cleanup_test_paths();
+}
+
+static struct tst_test test = {
+	.test = run,
+	.tcnt = ARRAY_SIZE(tcases),
+	.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

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

* [LTP] [PATCH v10 3/8] fs/acl: Add ACL_OTHER permission test
  2026-06-15  7:25 [LTP] [PATCH v10 0/8] Convert shell-based ACL test (tacl_xattr.sh) to C Sachin Sant
  2026-06-15  7:25 ` [LTP] [PATCH v10 1/8] fs/acl: Add ACL_USER_OBJ permission test Sachin Sant
  2026-06-15  7:25 ` [LTP] [PATCH v10 2/8] fs/acl: Add ACL mask interaction tests Sachin Sant
@ 2026-06-15  7:25 ` Sachin Sant
  2026-06-15  7:25 ` [LTP] [PATCH v10 4/8] fs/acl: Add default ACL inheritance test Sachin Sant
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 20+ messages in thread
From: Sachin Sant @ 2026-06-15  7:25 UTC (permalink / raw)
  To: ltp

Add test to verify ACL_OTHER permissions work correctly and are not
restricted by ACL_MASK.

The test sets up an ACL with:
- ACL_OTHER with rwx permissions
- ACL_MASK with no permissions (---)
- Verifies that a user matching ACL_OTHER can still create files

This validates that ACL_OTHER permissions are applied directly without
mask restriction, as specified in POSIX ACL semantics.

Suggested-by: Cyril Hrubis <chrubis@suse.cz>
Signed-off-by: Sachin Sant <sachinp@linux.ibm.com>
---
V10 changes:
- No change

V9 changes:
- No change

V8 changes:
- No change

V7 changes:
- No change

V6 changes:
- Added HAVE_SYS_XATTR_H guard
- Removed redundant error checking, relying on library functions
- Updated algorithm documentation with correct format
- 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_other01.c | 104 ++++++++++++++++++++++++++
 3 files changed, 106 insertions(+)
 create mode 100644 testcases/kernel/fs/acl/acl_other01.c

diff --git a/runtest/fs b/runtest/fs
index 69ecb8647..f25487a33 100644
--- a/runtest/fs
+++ b/runtest/fs
@@ -91,3 +91,4 @@ squashfs01 squashfs01
 # Run the acl tests
 acl_user_obj01 acl_user_obj01
 acl_mask01 acl_mask01
+acl_other01 acl_other01
diff --git a/testcases/kernel/fs/acl/.gitignore b/testcases/kernel/fs/acl/.gitignore
index bfcdee93d..c3ec0fad3 100644
--- a/testcases/kernel/fs/acl/.gitignore
+++ b/testcases/kernel/fs/acl/.gitignore
@@ -1,2 +1,3 @@
 /acl_user_obj01
 /acl_mask01
+/acl_other01
diff --git a/testcases/kernel/fs/acl/acl_other01.c b/testcases/kernel/fs/acl/acl_other01.c
new file mode 100644
index 000000000..41349223e
--- /dev/null
+++ b/testcases/kernel/fs/acl/acl_other01.c
@@ -0,0 +1,104 @@
+// 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_OTHER permissions using direct xattr manipulation.
+ *
+ * Verify that ACL_OTHER permissions work correctly and are not affected
+ * by ACL_MASK. The ACL_OTHER entry controls access for users who don't
+ * match any other ACL entry (not the owner, not in any named user entry,
+ * not in the owning group, and not in any named group entry).
+ *
+ * Unlike ACL_USER, ACL_GROUP, and ACL_GROUP_OBJ entries, ACL_OTHER
+ * permissions are not restricted by the ACL_MASK.
+ *
+ * This test uses arbitrary UIDs without creating actual users, testing
+ * only the kernel ACL implementation.
+ *
+ * [Algorithm]
+ *
+ * - Set up ACL with rwx permissions for ACL_OTHER
+ * - Set ACL_MASK to --- (no permissions)
+ * - Attempt file creation as a user matching ACL_OTHER
+ * - Verify access is granted despite restrictive mask
+ */
+
+#include "acl_lib.h"
+
+#ifdef HAVE_SYS_XATTR_H
+
+#define TEST_UID 1000
+#define TEST_GID 1000
+#define OTHER_UID 2000
+#define OTHER_GID 2000
+
+static void run(void)
+{
+	struct acl *acl;
+
+	tst_res(TINFO, "Testing ACL_OTHER permissions");
+	reset_test_path();
+
+	SAFE_CHOWN(TESTDIR, TEST_UID, TEST_GID);
+
+	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_MASK, 0, 0);
+	acl_add_entry(acl, ACL_OTHER,
+		      ACL_READ | ACL_WRITE | ACL_EXECUTE, 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(OTHER_UID, OTHER_GID, 0644, 0);
+
+	cleanup_testfile();
+}
+
+static void setup(void)
+{
+	reset_test_path();
+}
+
+static void cleanup(void)
+{
+	cleanup_test_paths();
+}
+
+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"},
+		{}
+	}
+};
+
+#else
+	TST_TEST_TCONF("sys/xattr.h is not available");
+#endif
-- 
2.39.1


-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

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

* [LTP] [PATCH v10 4/8] fs/acl: Add default ACL inheritance test
  2026-06-15  7:25 [LTP] [PATCH v10 0/8] Convert shell-based ACL test (tacl_xattr.sh) to C Sachin Sant
                   ` (2 preceding siblings ...)
  2026-06-15  7:25 ` [LTP] [PATCH v10 3/8] fs/acl: Add ACL_OTHER permission test Sachin Sant
@ 2026-06-15  7:25 ` Sachin Sant
  2026-06-15  7:25 ` [LTP] [PATCH v10 5/8] fs/acl: Add chmod/chown ACL interaction tests Sachin Sant
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 20+ messages in thread
From: Sachin Sant @ 2026-06-15  7:25 UTC (permalink / raw)
  To: ltp

Add acl_inherit01 test to validate default ACL inheritance from
parent directory to newly created files.

The test verifies that:
- Default ACLs set on a directory are inherited by new files
- New file permissions reflect the default ACL entries
- File created with umask 0 gets permissions from default ACL

This test sets default ACL with read-only permissions (r--r--r--)
on the parent directory, creates a new file with umask 0, and
verifies the file has 0444 permissions inherited from the
default ACL.

Suggested-by: Cyril Hrubis <chrubis@suse.cz>
Signed-off-by: Sachin Sant <sachinp@linux.ibm.com>
---
V10 changes:
- No change

V9 changes:
- No change

V8 changes:
- No change

V7 changes:
- No change

V6 changes:
- Added HAVE_SYS_XATTR_H guard
- Removed redundant error checking, relying on library functions
- Updated algorithm documentation with correct format
- 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:
- Remove unused acl_get_file() block
- keep mode-bit validation with explanatory comment
- v3 link https://lore.kernel.org/ltp/20260603065744.47106-1-sachinp@linux.ibm.com/T/#t

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 changes

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_inherit01.c | 113 ++++++++++++++++++++++++
 3 files changed, 115 insertions(+)
 create mode 100644 testcases/kernel/fs/acl/acl_inherit01.c

diff --git a/runtest/fs b/runtest/fs
index f25487a33..fd295edc7 100644
--- a/runtest/fs
+++ b/runtest/fs
@@ -92,3 +92,4 @@ squashfs01 squashfs01
 acl_user_obj01 acl_user_obj01
 acl_mask01 acl_mask01
 acl_other01 acl_other01
+acl_inherit01 acl_inherit01
diff --git a/testcases/kernel/fs/acl/.gitignore b/testcases/kernel/fs/acl/.gitignore
index c3ec0fad3..bc03ba1fd 100644
--- a/testcases/kernel/fs/acl/.gitignore
+++ b/testcases/kernel/fs/acl/.gitignore
@@ -1,3 +1,4 @@
 /acl_user_obj01
 /acl_mask01
 /acl_other01
+/acl_inherit01
diff --git a/testcases/kernel/fs/acl/acl_inherit01.c b/testcases/kernel/fs/acl/acl_inherit01.c
new file mode 100644
index 000000000..5af96b912
--- /dev/null
+++ b/testcases/kernel/fs/acl/acl_inherit01.c
@@ -0,0 +1,113 @@
+// 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 default ACL inheritance using direct xattr manipulation.
+ *
+ * Verify that files created in a directory with default ACLs inherit
+ * those ACLs as their access ACLs. Default ACLs are only applicable
+ * to directories and define the access ACLs that files and subdirectories
+ * created within that directory will inherit.
+ *
+ * This test uses arbitrary UIDs without creating actual users, testing
+ * only the kernel ACL implementation.
+ *
+ * [Algorithm]
+ *
+ * - Set default ACL on parent directory with read-only permissions
+ * - Create a new file in that directory with umask 0
+ * - Verify the file inherits the default ACL as its access ACL
+ * - Check that file permissions match the inherited ACL (0444)
+ */
+
+#include "acl_lib.h"
+
+#ifdef HAVE_SYS_XATTR_H
+
+#define TEST_UID 1000
+#define TEST_GID 1000
+
+static void run(void)
+{
+	struct acl *acl;
+	struct stat st;
+
+	tst_res(TINFO, "Testing default ACL inheritance");
+	reset_test_path();
+
+	SAFE_CHOWN(TESTDIR, TEST_UID, TEST_GID);
+
+	acl = acl_init();
+
+	acl_add_entry(acl, ACL_USER_OBJ, ACL_READ, 0);
+	acl_add_entry(acl, ACL_GROUP_OBJ, ACL_READ, 0);
+	acl_add_entry(acl, ACL_OTHER, ACL_READ, 0);
+
+	if (acl_set_file(TESTDIR, ACL_TYPE_DEFAULT, 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);
+
+	create_with_umask_as(TEST_UID, TEST_GID, 0666, 0, 0);
+
+	SAFE_STAT(TESTFILE, &st);
+
+	/*
+	 * For a minimal ACL (containing only ACL_USER_OBJ, ACL_GROUP_OBJ,
+	 * and ACL_OTHER), the mode bits are the canonical representation.
+	 * Verifying the mode bits confirms the inherited ACL was applied.
+	 */
+	if ((st.st_mode & 0777) != 0444) {
+		tst_res(TFAIL,
+			"File permissions 0%o, expected 0444 from default ACL",
+			st.st_mode & 0777);
+		cleanup_testfile();
+		return;
+	}
+
+	cleanup_testfile();
+	tst_res(TPASS, "Default ACL inheritance works correctly");
+}
+
+static void setup(void)
+{
+	reset_test_path();
+}
+
+static void cleanup(void)
+{
+	cleanup_test_paths();
+}
+
+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"},
+		{}
+	}
+};
+
+#else
+	TST_TEST_TCONF("sys/xattr.h is not available");
+#endif
-- 
2.39.1


-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

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

* [LTP] [PATCH v10 5/8] fs/acl: Add chmod/chown ACL interaction tests
  2026-06-15  7:25 [LTP] [PATCH v10 0/8] Convert shell-based ACL test (tacl_xattr.sh) to C Sachin Sant
                   ` (3 preceding siblings ...)
  2026-06-15  7:25 ` [LTP] [PATCH v10 4/8] fs/acl: Add default ACL inheritance test Sachin Sant
@ 2026-06-15  7:25 ` Sachin Sant
  2026-06-15  7:25 ` [LTP] [PATCH v10 6/8] fs/acl: Add ACL symlink operations test Sachin Sant
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 20+ messages in thread
From: Sachin Sant @ 2026-06-15  7:25 UTC (permalink / raw)
  To: ltp

Add acl_file_ops01 test to verify that standard file operations
(chmod, chown) interact correctly with POSIX ACLs using direct
xattr manipulation.

Test coverage:
- chmod updates ACL_USER_OBJ, ACL_GROUP_OBJ, and ACL_OTHER entries
- chown changes file owner/group without affecting ACL permissions
- ACL permissions are preserved after ownership changes

The test uses arbitrary UIDs without creating actual users, testing
only the kernel ACL implementation. It runs on ext2/ext3/ext4 (with
acl mount option), XFS, and Btrfs filesystems.

Suggested-by: Cyril Hrubis <chrubis@suse.cz>
Signed-off-by: Sachin Sant <sachinp@linux.ibm.com>
---
V10 changes:
- No change

V9 changes:
- Use RST manpage formatted documentation
- v8 link https://lore.kernel.org/ltp/20260613090543.78643-1-sachinp@linux.ibm.com/T/#t

V8 changes:
- Use RST manpage documentation format for syscalls
- remove forks_child since it is not required.
- v7 link https://lore.kernel.org/ltp/20260612171930.11964-1-sachinp@linux.ibm.com/T/#t

V7 changes:
- No change

V6 changes:
- Added HAVE_SYS_XATTR_H guard
- Removed redundant error checking, relying on library functions
- Updated algorithm documentation with correct format
- 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_file_ops01.c | 259 +++++++++++++++++++++++
 3 files changed, 261 insertions(+)
 create mode 100644 testcases/kernel/fs/acl/acl_file_ops01.c

diff --git a/runtest/fs b/runtest/fs
index fd295edc7..f1eea055b 100644
--- a/runtest/fs
+++ b/runtest/fs
@@ -93,3 +93,4 @@ acl_user_obj01 acl_user_obj01
 acl_mask01 acl_mask01
 acl_other01 acl_other01
 acl_inherit01 acl_inherit01
+acl_file_ops01 acl_file_ops01
diff --git a/testcases/kernel/fs/acl/.gitignore b/testcases/kernel/fs/acl/.gitignore
index bc03ba1fd..eb4b4a227 100644
--- a/testcases/kernel/fs/acl/.gitignore
+++ b/testcases/kernel/fs/acl/.gitignore
@@ -2,3 +2,4 @@
 /acl_mask01
 /acl_other01
 /acl_inherit01
+/acl_file_ops01
diff --git a/testcases/kernel/fs/acl/acl_file_ops01.c b/testcases/kernel/fs/acl/acl_file_ops01.c
new file mode 100644
index 000000000..76da42a49
--- /dev/null
+++ b/testcases/kernel/fs/acl/acl_file_ops01.c
@@ -0,0 +1,259 @@
+// 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 :manpage:`chmod(2)` and :manpage:`chown(2)` interaction
+ * with ACLs using direct xattr manipulation.
+ *
+ * Verify that standard file operations interact correctly
+ * with ACLs:
+ *
+ * - :manpage:`chmod(2)` should update ACL_USER_OBJ, ACL_GROUP_OBJ,
+ *   and ACL_OTHER entries
+ * - :manpage:`chown(2)` should change file owner/group without
+ *   affecting ACL entries
+ * - ACL permissions should be preserved after ownership changes
+ *
+ * This test uses arbitrary UIDs without creating actual users, testing
+ * only the kernel ACL implementation.
+ *
+ * [Algorithm]
+ *
+ * Test 1 - :manpage:`chmod(2)` interaction:
+ *
+ * - Create file with read-only ACL entries
+ * - Use :manpage:`chmod(2)` to set permissions to 0777
+ * - Verify ACL entries are updated to rwx for user, group, and other
+ *
+ * Test 2 - :manpage:`chown(2)` interaction:
+ *
+ * - Create file with specific ACL entries (rw for user, r for group/other)
+ * - Use :manpage:`chown(2)` to change owner and group
+ * - Verify ownership changed correctly
+ * - Verify ACL entries preserved their permissions after
+ *   :manpage:`chown(2)`
+ */
+
+#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
+
+/*
+ * Test chmod interaction with ACLs.
+ * chmod should update ACL_USER_OBJ, ACL_GROUP_OBJ, and ACL_OTHER.
+ */
+static void test_chmod_acl(void)
+{
+	struct acl *acl;
+	int fd = -1;
+	int user_ok = 0, group_ok = 0, other_ok = 0;
+
+	tst_res(TINFO, "Testing chmod interaction with ACLs");
+	reset_test_path();
+
+	fd = SAFE_OPEN(TESTFILE, O_CREAT | O_WRONLY, 0644);
+	SAFE_CLOSE(fd);
+
+	acl = acl_init();
+
+	acl_add_entry(acl, ACL_USER_OBJ, ACL_READ, 0);
+	acl_add_entry(acl, ACL_GROUP_OBJ, ACL_READ, 0);
+	acl_add_entry(acl, ACL_OTHER, ACL_READ, 0);
+
+	if (acl_set_file(TESTFILE, ACL_TYPE_ACCESS, acl) < 0) {
+		if (errno == EOPNOTSUPP) {
+			acl_free(acl);
+			cleanup_testfile();
+			tst_brk(TCONF | TERRNO, "ACL not supported");
+		}
+		acl_free(acl);
+		cleanup_testfile();
+		tst_brk(TBROK | TERRNO, "ACL setup failed");
+	}
+
+	acl_free(acl);
+
+	SAFE_CHMOD(TESTFILE, 0777);
+
+	acl = acl_get_file(TESTFILE, ACL_TYPE_ACCESS);
+	if (!acl) {
+		cleanup_testfile();
+		tst_brk(TBROK | TERRNO, "acl_get_file failed");
+	}
+
+	/* Check if all entries have rwx permissions */
+	for (int i = 0; i < acl->count; i++) {
+		struct acl_entry *entry = &acl->entries[i];
+
+		if (entry->tag == ACL_USER_OBJ) {
+			if (acl_entry_has_rwx(entry))
+				user_ok = 1;
+		} else if (entry->tag == ACL_GROUP_OBJ) {
+			if (acl_entry_has_rwx(entry))
+				group_ok = 1;
+		} else if (entry->tag == ACL_OTHER) {
+			if (acl_entry_has_rwx(entry))
+				other_ok = 1;
+		}
+	}
+
+	acl_free(acl);
+	cleanup_testfile();
+
+	if (user_ok && group_ok && other_ok)
+		tst_res(TPASS, "chmod correctly updated ACL entries");
+	else
+		tst_res(TFAIL, "chmod did not update ACL entries correctly");
+}
+
+/*
+ * Test chown interaction with ACLs.
+ * chown should change file owner and group without affecting ACL entries.
+ */
+static void test_chown_acl(void)
+{
+	struct acl *acl;
+	struct stat st;
+	int fd = -1;
+	int found_user_obj = 0, found_group_obj = 0, found_other = 0;
+
+	tst_res(TINFO, "Testing chown interaction with ACLs");
+	reset_test_path();
+
+	fd = SAFE_OPEN(TESTFILE, O_CREAT | O_WRONLY, 0644);
+	SAFE_CLOSE(fd);
+
+	acl = acl_init();
+
+	acl_add_entry(acl, ACL_USER_OBJ, ACL_READ | ACL_WRITE, 0);
+	acl_add_entry(acl, ACL_GROUP_OBJ, ACL_READ, 0);
+	acl_add_entry(acl, ACL_OTHER, ACL_READ, 0);
+
+	if (acl_set_file(TESTFILE, ACL_TYPE_ACCESS, acl) < 0) {
+		acl_free(acl);
+		cleanup_testfile();
+		if (errno == EOPNOTSUPP)
+			tst_brk(TCONF | TERRNO, "ACL not supported");
+		tst_brk(TBROK | TERRNO, "acl_set_file failed");
+	}
+
+	acl_free(acl);
+
+	SAFE_CHOWN(TESTFILE, USER2_UID, USER2_GID);
+
+	SAFE_STAT(TESTFILE, &st);
+
+	if (st.st_uid != USER2_UID || st.st_gid != USER2_GID) {
+		cleanup_testfile();
+		tst_res(TFAIL, "chown did not change owner/group correctly");
+		return;
+	}
+
+	/* Verify ACL entries are preserved after chown */
+	acl = acl_get_file(TESTFILE, ACL_TYPE_ACCESS);
+	if (!acl) {
+		cleanup_testfile();
+		tst_brk(TBROK | TERRNO, "acl_get_file failed");
+	}
+
+	for (int i = 0; i < acl->count; i++) {
+		struct acl_entry *entry = &acl->entries[i];
+
+		if (entry->tag == ACL_USER_OBJ) {
+			found_user_obj = 1;
+			if (!acl_entry_has_perm(entry, ACL_READ) ||
+			    !acl_entry_has_perm(entry, ACL_WRITE)) {
+				acl_free(acl);
+				cleanup_testfile();
+				tst_res(TFAIL,
+					"ACL_USER_OBJ perms changed after chown");
+				return;
+			}
+		} else if (entry->tag == ACL_GROUP_OBJ) {
+			found_group_obj = 1;
+			if (!acl_entry_has_perm(entry, ACL_READ) ||
+			    acl_entry_has_perm(entry, ACL_WRITE)) {
+				acl_free(acl);
+				cleanup_testfile();
+				tst_res(TFAIL,
+					"ACL_GROUP_OBJ perms changed after chown");
+				return;
+			}
+		} else if (entry->tag == ACL_OTHER) {
+			found_other = 1;
+			if (!acl_entry_has_perm(entry, ACL_READ) ||
+			    acl_entry_has_perm(entry, ACL_WRITE)) {
+				acl_free(acl);
+				cleanup_testfile();
+				tst_res(TFAIL,
+					"ACL_OTHER perms changed after chown");
+				return;
+			}
+		}
+	}
+
+	acl_free(acl);
+
+	if (!found_user_obj || !found_group_obj || !found_other) {
+		cleanup_testfile();
+		tst_res(TFAIL, "ACL entries missing after chown");
+		return;
+	}
+
+	cleanup_testfile();
+	tst_res(TPASS, "chown preserved ACL entries correctly");
+}
+
+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_chmod_acl();
+		break;
+	case 1:
+		test_chown_acl();
+		break;
+	}
+}
+
+static struct tst_test test = {
+	.test = run,
+	.tcnt = 2,
+	.setup = setup,
+	.cleanup = cleanup,
+	.needs_root = 1,
+	.mount_device = 1,
+	.mntpoint = MNTPOINT,
+	.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

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

* [LTP] [PATCH v10 6/8] fs/acl: Add ACL symlink operations test
  2026-06-15  7:25 [LTP] [PATCH v10 0/8] Convert shell-based ACL test (tacl_xattr.sh) to C Sachin Sant
                   ` (4 preceding siblings ...)
  2026-06-15  7:25 ` [LTP] [PATCH v10 5/8] fs/acl: Add chmod/chown ACL interaction tests Sachin Sant
@ 2026-06-15  7:25 ` Sachin Sant
  2026-06-15  7:25 ` [LTP] [PATCH v10 7/8] fs/acl: Add extended attributes test Sachin Sant
  2026-06-15  7:25 ` [LTP] [PATCH v10 8/8] fs/acl: Remove old shell-based ACL test Sachin Sant
  7 siblings, 0 replies; 20+ messages in thread
From: Sachin Sant @ 2026-06-15  7:25 UTC (permalink / raw)
  To: ltp

Add acl_link01 test to verify that ACL operations on symlinks
follow the symlink to the target file rather than operating on
the symlink itself.

The test:
- Creates a regular file with mode 0600
- Creates a symlink pointing to the file
- Sets ACL (rwxrw----) through the symlink path
- Verifies the ACL was applied to the target file
- Confirms reading ACL via symlink returns target's ACL

This validates kernel behavior where ACL set/get operations
on symlinks affect the target file, not the symlink.

Uses direct xattr manipulation without requiring actual users,
testing only kernel ACL implementation. Handles EOPNOTSUPP
gracefully for filesystems without ACL support.

Suggested-by: Cyril Hrubis <chrubis@suse.cz>
Signed-off-by: Sachin Sant <sachinp@linux.ibm.com>
---
V10 changes:
- No change

V9 changes:
- No change

V8 changes:
- Use reset_test_path() instead of chown variant.
- v7 link https://lore.kernel.org/ltp/20260612171930.11964-1-sachinp@linux.ibm.com/T/#t

V7 changes:
- No change

V6 changes:
- Added HAVE_SYS_XATTR_H guard
- Removed redundant error checking, relying on library functions
- Updated algorithm documentation with correct format
- Removed unnecessary .forks_child flag
- 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:
- Rewrite test logic to use distinct ACL (rwxrw----) that
  differs from initial mode.
- Update commit message to reflect the implementation.
- v3 link https://lore.kernel.org/ltp/20260603140147.50738-1-sachinp@linux.ibm.com/T/#t

V3 changes:
- Updated the test to read the ACL from both TESTSYMLINK
  and TESTFILE, and verify the expected entries/permissions match.
- Updated commit message to reflect this change.
- 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:
- Updated incorrect TCONF message and description text
- Updated commit message to remove incorrect symlinks wording
- Use reset_test_path_no_chown variant to skip chown step
  and removed needs_cmd tag to avoid useradd/userdel dependency
- v1 link https://lore.kernel.org/ltp/20260602121958.27494-1-sachinp@linux.ibm.com/T/#t

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 | 215 +++++++++++++++++++++++++++
 3 files changed, 217 insertions(+)
 create mode 100644 testcases/kernel/fs/acl/acl_link01.c

diff --git a/runtest/fs b/runtest/fs
index f1eea055b..64deb56e6 100644
--- a/runtest/fs
+++ b/runtest/fs
@@ -94,3 +94,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..5e70f36ff
--- /dev/null
+++ b/testcases/kernel/fs/acl/acl_link01.c
@@ -0,0 +1,215 @@
+// 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 operations on symlinks using direct xattr manipulation.
+ *
+ * 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 the target file and will
+ * return EOPNOTSUPP, which is treated as TCONF (test not applicable).
+ *
+ * This test uses direct xattr manipulation without creating actual users,
+ * testing only the kernel ACL implementation.
+ *
+ * [Algorithm]
+ *
+ * - Create a regular file with mode 0600 (rw-------)
+ * - Create a symlink pointing to the file
+ * - Set a distinct ACL through the symlink path (rwxrw----)
+ * - Verify the ACL was set on the target file by reading it directly
+ * - Get ACL through the symlink path
+ * - Verify both ACLs match and differ from the initial 0600 mode
+ */
+
+#include "acl_lib.h"
+
+#ifdef HAVE_SYS_XATTR_H
+
+static void run(void)
+{
+	struct acl *acl, *target_acl = NULL, *symlink_acl = NULL;
+	struct acl_entry *user_obj, *group_obj, *other;
+	struct acl_entry *t, *s;
+	int fd = -1;
+	int match, count, i;
+
+	tst_res(TINFO, "Testing ACL operations on symlinks");
+	reset_test_path();
+
+	fd = SAFE_OPEN(TESTFILE, O_CREAT | O_WRONLY, 0600);
+	SAFE_CLOSE(fd);
+
+	SAFE_SYMLINK("testfile", TESTSYMLINK);
+
+	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, 0);
+	acl_add_entry(acl, ACL_OTHER, 0, 0);
+
+	if (acl_set_file(TESTSYMLINK, ACL_TYPE_ACCESS, acl) < 0) {
+		if (errno == EOPNOTSUPP) {
+			acl_free(acl);
+			if (unlink(TESTSYMLINK) == -1)
+				tst_res(TWARN | TERRNO, "unlink symlink failed");
+			cleanup_testfile();
+			tst_res(TCONF,
+				"ACL not supported by this filesystem");
+			return;
+		}
+		acl_free(acl);
+		if (unlink(TESTSYMLINK) == -1)
+			tst_res(TWARN | TERRNO, "unlink symlink failed");
+		cleanup_testfile();
+		tst_brk(TBROK | TERRNO, "ACL setup failed");
+	}
+
+	acl_free(acl);
+
+	/* Verify ACL was actually set on target file with expected values */
+	target_acl = acl_get_file(TESTFILE, ACL_TYPE_ACCESS);
+	if (!target_acl) {
+		if (unlink(TESTSYMLINK) == -1)
+			tst_res(TWARN | TERRNO, "unlink symlink failed");
+		cleanup_testfile();
+		tst_brk(TBROK | TERRNO, "acl_get_file on target file failed");
+	}
+
+	/* Verify expected ACL entries: USER_OBJ=rwx, GROUP_OBJ=rw, OTHER=--- */
+	if (target_acl->count != 3) {
+		count = target_acl->count;
+
+		acl_free(target_acl);
+		if (unlink(TESTSYMLINK) == -1)
+			tst_res(TWARN | TERRNO, "unlink symlink failed");
+		cleanup_testfile();
+		tst_res(TFAIL, "Expected 3 ACL entries, got %d", count);
+		return;
+	}
+
+	user_obj = acl_find_entry(target_acl, ACL_USER_OBJ, 0);
+	group_obj = acl_find_entry(target_acl, ACL_GROUP_OBJ, 0);
+	other = acl_find_entry(target_acl, ACL_OTHER, 0);
+
+	if (!user_obj || !group_obj || !other) {
+		acl_free(target_acl);
+		if (unlink(TESTSYMLINK) == -1)
+			tst_res(TWARN | TERRNO, "unlink symlink failed");
+		cleanup_testfile();
+		tst_res(TFAIL, "Missing required ACL entries");
+		return;
+	}
+
+	if (user_obj->perm != (ACL_READ | ACL_WRITE | ACL_EXECUTE)) {
+		acl_free(target_acl);
+		if (unlink(TESTSYMLINK) == -1)
+			tst_res(TWARN | TERRNO, "unlink symlink failed");
+		cleanup_testfile();
+		tst_res(TFAIL, "USER_OBJ has wrong permissions: %o (expected rwx)",
+			user_obj->perm);
+		return;
+	}
+
+	if (group_obj->perm != (ACL_READ | ACL_WRITE)) {
+		acl_free(target_acl);
+		if (unlink(TESTSYMLINK) == -1)
+			tst_res(TWARN | TERRNO, "unlink symlink failed");
+		cleanup_testfile();
+		tst_res(TFAIL, "GROUP_OBJ has wrong permissions: %o (expected rw-)",
+			group_obj->perm);
+		return;
+	}
+
+	if (other->perm != 0) {
+		acl_free(target_acl);
+		if (unlink(TESTSYMLINK) == -1)
+			tst_res(TWARN | TERRNO, "unlink symlink failed");
+		cleanup_testfile();
+		tst_res(TFAIL, "OTHER has wrong permissions: %o (expected ---)",
+			other->perm);
+		return;
+	}
+
+	/* Now verify that reading via symlink gives the same result */
+	symlink_acl = acl_get_file(TESTSYMLINK, ACL_TYPE_ACCESS);
+	if (!symlink_acl) {
+		acl_free(target_acl);
+		if (unlink(TESTSYMLINK) == -1)
+			tst_res(TWARN | TERRNO, "unlink symlink failed");
+		cleanup_testfile();
+		tst_brk(TBROK | TERRNO, "acl_get_file on symlink failed");
+	}
+
+	/* Compare ACLs */
+	match = 1;
+	if (target_acl->count != symlink_acl->count) {
+		match = 0;
+	} else {
+		for (i = 0; i < target_acl->count; i++) {
+			t = &target_acl->entries[i];
+			s = &symlink_acl->entries[i];
+
+			if (t->tag != s->tag || t->perm != s->perm ||
+			    t->id != s->id) {
+				match = 0;
+				break;
+			}
+		}
+	}
+
+	acl_free(symlink_acl);
+	acl_free(target_acl);
+
+	if (unlink(TESTSYMLINK) == -1)
+		tst_res(TWARN | TERRNO, "unlink symlink failed");
+	cleanup_testfile();
+
+	if (!match) {
+		tst_res(TFAIL,
+			"ACL via symlink differs from ACL on target file");
+		return;
+	}
+
+	tst_res(TPASS,
+		"ACL set via symlink was applied to target file (rwxrw----)");
+}
+
+static void setup(void)
+{
+	reset_test_path();
+}
+
+static void cleanup(void)
+{
+	cleanup_test_paths();
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.setup = setup,
+	.cleanup = cleanup,
+	.needs_root = 1,
+	.mount_device = 1,
+	.mntpoint = MNTPOINT,
+	.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

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

* [LTP] [PATCH v10 7/8] fs/acl: Add extended attributes test
  2026-06-15  7:25 [LTP] [PATCH v10 0/8] Convert shell-based ACL test (tacl_xattr.sh) to C Sachin Sant
                   ` (5 preceding siblings ...)
  2026-06-15  7:25 ` [LTP] [PATCH v10 6/8] fs/acl: Add ACL symlink operations test Sachin Sant
@ 2026-06-15  7:25 ` Sachin Sant
  2026-06-15  7:25 ` [LTP] [PATCH v10 8/8] fs/acl: Remove old shell-based ACL test Sachin Sant
  7 siblings, 0 replies; 20+ messages in thread
From: Sachin Sant @ 2026-06-15  7:25 UTC (permalink / raw)
  To: ltp

Add xattr_test01 to validate extended attribute operations on
filesystems.

The test covers:
- Setting and retrieving extended attributes on files and directories
- Removing extended attributes and verifying removal
- Backing up extended attributes to a file
- Restoring extended attributes from backup
- Verifying restored attributes match original values

The test runs on ext2/ext3/ext4 (with user_xattr mount option),
xfs, and btrfs filesystems. It properly handles EOPNOTSUPP for
filesystems without extended attribute support.

Suggested-by: Cyril Hrubis <chrubis@suse.cz>
Signed-off-by: Sachin Sant <sachinp@linux.ibm.com>
---
V10 changes:
- No change

V9 changes:
- Use TEST() method as appropriate.
- v8 link https://lore.kernel.org/ltp/20260613090543.78643-1-sachinp@linux.ibm.com/T/#t

V8 changes:
- Use reset_test_path() instead of chown variant.
- v7 link https://lore.kernel.org/ltp/20260612171930.11964-1-sachinp@linux.ibm.com/T/#t

V7 changes:
- No change

V6 changes:
- Added HAVE_SYS_XATTR_H guard
- Switched from TST_EXP_PASS_SILENT to TEST() with TTERRNO for better
  diagnostics
- Updated algorithm documentation with correct format
- Removed unnecessary .forks_child flag
- 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.
- Updated commit message as per review comments.
- v2 link https://lore.kernel.org/ltp/20260603065744.47106-1-sachinp@linux.ibm.com/T/#t

V2 changes:
- Use reset_test_path_no_chown variant to skip chown step
  and removed needs_cmd tag to avoid useradd/userdel dependency
- v1 link https://lore.kernel.org/ltp/20260602121958.27494-1-sachinp@linux.ibm.com/T/#t

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/xattr_test01.c | 380 +++++++++++++++++++++++++
 3 files changed, 382 insertions(+)
 create mode 100644 testcases/kernel/fs/acl/xattr_test01.c

diff --git a/runtest/fs b/runtest/fs
index 64deb56e6..f9acac387 100644
--- a/runtest/fs
+++ b/runtest/fs
@@ -95,3 +95,4 @@ acl_other01 acl_other01
 acl_inherit01 acl_inherit01
 acl_file_ops01 acl_file_ops01
 acl_link01 acl_link01
+xattr_test01 xattr_test01
diff --git a/testcases/kernel/fs/acl/.gitignore b/testcases/kernel/fs/acl/.gitignore
index 4a071d516..62ccd0457 100644
--- a/testcases/kernel/fs/acl/.gitignore
+++ b/testcases/kernel/fs/acl/.gitignore
@@ -4,3 +4,4 @@
 /acl_inherit01
 /acl_file_ops01
 /acl_link01
+/xattr_test01
diff --git a/testcases/kernel/fs/acl/xattr_test01.c b/testcases/kernel/fs/acl/xattr_test01.c
new file mode 100644
index 000000000..7b86a43ed
--- /dev/null
+++ b/testcases/kernel/fs/acl/xattr_test01.c
@@ -0,0 +1,380 @@
+// 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 Extended Attributes (xattr).
+ *
+ * Some filesystems require explicit user_xattr mount options,
+ * while others (e.g. xfs and btrfs) provide these features without
+ * mount options.
+ *
+ * This test validates:
+ * - Extended attributes set/get/remove operations
+ * - Extended attributes backup and restore operations
+ *
+ * [Algorithm]
+ *
+ * - Set extended attributes on directories and files
+ * - Verify attributes can be retrieved correctly
+ * - Test attribute removal
+ * - Create backup of extended attributes to a file
+ * - Remove original attributes
+ * - Restore attributes from backup file
+ * - Verify restored attributes match original values
+ */
+
+#include "acl_lib.h"
+
+#ifdef HAVE_SYS_XATTR_H
+
+/*
+ * Test extended attributes.
+ * Set, get, and remove extended attributes on files and directories.
+ */
+static void test_xattr(void)
+{
+	char value[256];
+	int fd = -1;
+	int file_created = 0;
+
+	tst_res(TINFO, "Testing extended attributes");
+	reset_test_path();
+
+	TEST(setxattr(TESTDIR, XATTR_TEST_DIR_NAME, XATTR_TEST_DIR_VALUE,
+		      XATTR_TEST_DIR_SIZE, 0));
+	if (TST_RET == -1) {
+		if (TST_ERR == EOPNOTSUPP) {
+			tst_res(TCONF, "Extended attributes not supported");
+			return;
+		}
+		tst_res(TFAIL | TTERRNO, "setxattr on directory failed");
+		return;
+	}
+
+	TEST(getxattr(TESTDIR, XATTR_TEST_DIR_NAME, value, sizeof(value)));
+	if (TST_RET < 0) {
+		tst_res(TFAIL | TTERRNO, "getxattr on directory failed");
+		goto cleanup_dir_xattr;
+	}
+
+	if (TST_RET != XATTR_TEST_DIR_SIZE ||
+	    memcmp(value, XATTR_TEST_DIR_VALUE, XATTR_TEST_DIR_SIZE) != 0) {
+		tst_res(TFAIL, "getxattr returned wrong directory value");
+		goto cleanup_dir_xattr;
+	}
+
+	fd = SAFE_OPEN(TESTFILE, O_CREAT | O_WRONLY, 0644);
+	SAFE_CLOSE(fd);
+	file_created = 1;
+
+	TEST(setxattr(TESTFILE, XATTR_TEST_FILE_NAME, XATTR_TEST_FILE_VALUE,
+		      XATTR_TEST_FILE_SIZE, 0));
+	if (TST_RET == -1) {
+		if (TST_ERR == EOPNOTSUPP) {
+			tst_res(TCONF, "Extended attributes not supported");
+			goto cleanup_file_and_dir;
+		}
+		tst_res(TFAIL | TTERRNO, "setxattr on file failed");
+		goto cleanup_file_and_dir;
+	}
+
+	TEST(getxattr(TESTFILE, XATTR_TEST_FILE_NAME, value, sizeof(value)));
+	if (TST_RET < 0) {
+		tst_res(TFAIL | TTERRNO, "getxattr on file failed");
+		goto cleanup_file_and_dir;
+	}
+
+	if (TST_RET != XATTR_TEST_FILE_SIZE ||
+	    memcmp(value, XATTR_TEST_FILE_VALUE, XATTR_TEST_FILE_SIZE) != 0) {
+		tst_res(TFAIL, "getxattr returned wrong file value");
+		goto cleanup_file_and_dir;
+	}
+
+	TEST(removexattr(TESTFILE, XATTR_TEST_FILE_NAME));
+	if (TST_RET == -1) {
+		tst_res(TFAIL | TTERRNO, "removexattr failed");
+		goto cleanup_file_and_dir;
+	}
+
+	TEST(getxattr(TESTFILE, XATTR_TEST_FILE_NAME, value, sizeof(value)));
+	if (TST_RET >= 0 || TST_ERR != ENODATA) {
+		tst_res(TFAIL, "getxattr after removal should fail with ENODATA");
+		goto cleanup_file_and_dir;
+	}
+
+	tst_res(TPASS, "Extended attributes work correctly");
+
+cleanup_file_and_dir:
+	if (file_created)
+		cleanup_testfile();
+cleanup_dir_xattr:
+	if (removexattr(TESTDIR, XATTR_TEST_DIR_NAME) == -1 &&
+	    errno != ENODATA)
+		tst_res(TWARN | TERRNO, "removexattr failed");
+}
+
+#define XATTR_BACKUP_TEST_COUNT 2
+
+/*
+ * Helper function to cleanup test xattrs.
+ */
+static inline void cleanup_test_xattrs(void)
+{
+	if (removexattr(TESTFILE, XATTR_TEST1_NAME) == -1 &&
+	    errno != ENODATA)
+		tst_res(TWARN | TERRNO, "removexattr XATTR_TEST1_NAME failed");
+	if (removexattr(TESTFILE, XATTR_TEST2_NAME) == -1 &&
+	    errno != ENODATA)
+		tst_res(TWARN | TERRNO, "removexattr XATTR_TEST2_NAME failed");
+}
+
+/*
+ * Test extended attributes backup and restore.
+ * Extended attributes should be preserved through backup/restore.
+ */
+static void test_xattr_backup_restore(void)
+{
+	char value[256];
+	char line[512];
+	char attr_name[256];
+	char attr_value[256];
+	char list[512];
+	size_t name_len, value_len;
+	ssize_t list_size;
+	int fd = -1;
+	FILE *fp = NULL;
+	int restored_count = 0;
+	int backup_created = 0;
+	char *attr_ptr;
+
+	tst_res(TINFO, "Testing extended attributes backup and restore");
+	reset_test_path();
+
+	fd = SAFE_OPEN(TESTFILE, O_CREAT | O_WRONLY, 0644);
+	SAFE_CLOSE(fd);
+
+	TEST(setxattr(TESTFILE, XATTR_TEST1_NAME, XATTR_TEST1_VALUE,
+		      XATTR_TEST1_SIZE, 0));
+	if (TST_RET == -1) {
+		cleanup_testfile();
+		if (TST_ERR == EOPNOTSUPP) {
+			tst_res(TCONF, "Extended attributes not supported");
+			return;
+		}
+		tst_res(TFAIL | TTERRNO, "setxattr failed");
+		return;
+	}
+
+	TEST(setxattr(TESTFILE, XATTR_TEST2_NAME, XATTR_TEST2_VALUE,
+		      XATTR_TEST2_SIZE, 0));
+	if (TST_RET == -1) {
+		tst_res(TFAIL | TTERRNO, "setxattr failed");
+		goto cleanup_xattrs;
+	}
+
+	/* Create genuine backup by reading xattrs from filesystem */
+	fp = SAFE_FOPEN(XATTR_BACKUP_FILE, "w");
+	backup_created = 1;
+
+	if (fprintf(fp, "# file: %s\n", TESTFILE) < 0) {
+		tst_res(TFAIL | TERRNO, "fprintf failed");
+		goto cleanup_backup;
+	}
+
+	TEST(listxattr(TESTFILE, list, sizeof(list)));
+	if (TST_RET < 0) {
+		tst_res(TFAIL | TTERRNO, "listxattr failed");
+		goto cleanup_backup;
+	}
+
+	/* Save list size before it gets overwritten by subsequent TEST() calls */
+	list_size = TST_RET;
+
+	attr_ptr = list;
+	while (attr_ptr < list + list_size) {
+		/* Only backup user.* attributes for this test */
+		if (strncmp(attr_ptr, "user.", 5) != 0) {
+			attr_ptr += strlen(attr_ptr) + 1;
+			continue;
+		}
+
+		TEST(getxattr(TESTFILE, attr_ptr, value, sizeof(value)));
+		if (TST_RET < 0) {
+			tst_res(TFAIL | TTERRNO, "getxattr failed for %s",
+				attr_ptr);
+			goto cleanup_backup;
+		}
+
+		/* Write to backup file with null terminator for string values */
+		if (fprintf(fp, "%s=\"%.*s\"\n", attr_ptr, (int)TST_RET,
+			    value) < 0) {
+			tst_res(TFAIL | TERRNO, "fprintf failed");
+			goto cleanup_backup;
+		}
+
+		attr_ptr += strlen(attr_ptr) + 1;
+	}
+
+	SAFE_FCLOSE(fp);
+	fp = NULL;
+
+	/* Remove xattrs to simulate loss */
+	cleanup_test_xattrs();
+
+	/* Restore from backup file */
+	fp = SAFE_FOPEN(XATTR_BACKUP_FILE, "r");
+	while (fgets(line, sizeof(line), fp)) {
+		char *p, *q;
+
+		if (line[0] == '#' || line[0] == '\n')
+			continue;
+
+		/* Parse: attr_name="attr_value" */
+		p = strchr(line, '=');
+		if (!p)
+			continue;
+
+		/* Safe copy of attribute name with length check */
+		name_len = p - line;
+
+		if (name_len >= sizeof(attr_name)) {
+			tst_res(TWARN, "Attribute name too long, skipping");
+			continue;
+		}
+		memcpy(attr_name, line, name_len);
+		attr_name[name_len] = '\0';
+
+		/* Only restore user.* attributes for this test */
+		if (strncmp(attr_name, "user.", 5) != 0)
+			continue;
+
+		p++;
+		if (*p != '"')
+			continue;
+		p++;
+
+		q = strchr(p, '"');
+		if (!q)
+			continue;
+
+		/* Safe copy of attribute value with length check */
+		value_len = q - p;
+
+		if (value_len >= sizeof(attr_value)) {
+			tst_res(TWARN, "Attribute value too long, skipping");
+			continue;
+		}
+		memcpy(attr_value, p, value_len);
+		attr_value[value_len] = '\0';
+
+		/* Restore the xattr */
+		if (setxattr(TESTFILE, attr_name, attr_value, value_len,
+			     0) == -1) {
+			tst_res(TFAIL | TERRNO,
+				"setxattr restore failed for %s", attr_name);
+			goto cleanup_backup;
+		}
+		restored_count++;
+	}
+	SAFE_FCLOSE(fp);
+	fp = NULL;
+
+	if (restored_count != XATTR_BACKUP_TEST_COUNT) {
+		tst_res(TFAIL, "Expected %d xattrs restored, got %d",
+			XATTR_BACKUP_TEST_COUNT, restored_count);
+		goto cleanup_backup;
+	}
+
+	/* Verify restored xattrs */
+	TEST(getxattr(TESTFILE, XATTR_TEST1_NAME, value, sizeof(value)));
+	if (TST_RET < 0) {
+		tst_res(TFAIL | TTERRNO, "getxattr failed for %s",
+			XATTR_TEST1_NAME);
+		goto cleanup_backup;
+	}
+
+	if (TST_RET != XATTR_TEST1_SIZE ||
+	    memcmp(value, XATTR_TEST1_VALUE, XATTR_TEST1_SIZE) != 0) {
+		tst_res(TFAIL,
+			"Extended attribute %s restore verification failed",
+			XATTR_TEST1_NAME);
+		goto cleanup_backup;
+	}
+
+	TEST(getxattr(TESTFILE, XATTR_TEST2_NAME, value, sizeof(value)));
+	if (TST_RET < 0) {
+		tst_res(TFAIL | TTERRNO, "getxattr failed for %s",
+			XATTR_TEST2_NAME);
+		goto cleanup_backup;
+	}
+
+	if (TST_RET != XATTR_TEST2_SIZE ||
+	    memcmp(value, XATTR_TEST2_VALUE, XATTR_TEST2_SIZE) != 0) {
+		tst_res(TFAIL,
+			"Extended attribute %s restore verification failed",
+			XATTR_TEST2_NAME);
+		goto cleanup_backup;
+	}
+
+	tst_res(TPASS, "Extended attributes backup/restore work correctly");
+
+cleanup_backup:
+	if (fp)
+		SAFE_FCLOSE(fp);
+	if (backup_created) {
+		if (unlink(XATTR_BACKUP_FILE) == -1)
+			tst_res(TWARN | TERRNO, "unlink backup file failed");
+	}
+cleanup_xattrs:
+	cleanup_test_xattrs();
+	cleanup_testfile();
+}
+
+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_xattr();
+		break;
+	case 1:
+		test_xattr_backup_restore();
+		break;
+	}
+}
+
+static struct tst_test test = {
+	.test = run,
+	.tcnt = 2,
+	.setup = setup,
+	.cleanup = cleanup,
+	.needs_root = 1,
+	.mount_device = 1,
+	.mntpoint = MNTPOINT,
+	.filesystems = (struct tst_fs[]) {
+		{.type = "ext2", .mnt_data = "user_xattr"},
+		{.type = "ext3", .mnt_data = "user_xattr"},
+		{.type = "ext4", .mnt_data = "user_xattr"},
+		{.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

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

* [LTP] [PATCH v10 8/8] fs/acl: Remove old shell-based ACL test
  2026-06-15  7:25 [LTP] [PATCH v10 0/8] Convert shell-based ACL test (tacl_xattr.sh) to C Sachin Sant
                   ` (6 preceding siblings ...)
  2026-06-15  7:25 ` [LTP] [PATCH v10 7/8] fs/acl: Add extended attributes test Sachin Sant
@ 2026-06-15  7:25 ` Sachin Sant
  7 siblings, 0 replies; 20+ messages in thread
From: Sachin Sant @ 2026-06-15  7:25 UTC (permalink / raw)
  To: ltp

Remove tacl_xattr.sh, the old shell-based ACL and extended attribute
test script. This test has been replaced by the new modular C-based
test suite:

- acl_user_obj01: ACL_USER_OBJ permissions
- acl_mask01: ACL mask interactions
- acl_other01: ACL_OTHER permissions
- acl_inherit01: Default ACL inheritance
- acl_file_ops01: chmod/chown interactions
- acl_link01: Symlink ACL operations
- xattr_test01: Extended attributes

Signed-off-by: Sachin Sant <sachinp@linux.ibm.com>
---
No changes in v2 to v10

V1 changes:
- Updated commit message to reflect correct number of
  test scenario in xattr_test01
- rfc link https://lore.kernel.org/ltp/477836fd-80c8-4168-bfe6-00b374bb2534@linux.ibm.com/T/#t

---
 testcases/kernel/fs/acl/tacl_xattr.sh | 807 --------------------------
 1 file changed, 807 deletions(-)
 delete mode 100755 testcases/kernel/fs/acl/tacl_xattr.sh

diff --git a/testcases/kernel/fs/acl/tacl_xattr.sh b/testcases/kernel/fs/acl/tacl_xattr.sh
deleted file mode 100755
index c2383fdd9..000000000
--- a/testcases/kernel/fs/acl/tacl_xattr.sh
+++ /dev/null
@@ -1,807 +0,0 @@
-#!/bin/bash
-##############################################################
-#
-#  Copyright (c) International Business Machines  Corp., 2003
-#
-#  This program is free software;  you can redistribute it and/or modify
-#  it under the terms of the GNU General Public License as published by
-#  the Free Software Foundation; either version 2 of the License, or
-#  (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY;  without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
-#  the GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program;  if not, write to the Free Software
-#  Foundation,
-#
-#  FILE        : tacl_xattr.sh
-#  USAGE       : ./tacl_xattr.sh
-#
-#  DESCRIPTION : A script that will test ACL and Extend Attribute on Linux system.
-#  REQUIREMENTS:
-#                1) Kernel with loop device support
-#                2) A spare (scratch) disk partition of 100MB or larger.
-#                3) Kernel with ACL and Extend Attribute function support
-#
-#  HISTORY     :
-#      10/23/2003 Kai Zhao (ltcd3@cn.ibm.com)
-#      07/06/2004 Jacky Malcles enable ext3 & clean users home dir.
-#
-#  CODE COVERAGE:
-#                 76.3% - fs/posix_acl.c
-#                 80.9% - xattr_acl.c
-#                 73.0% - xattr.c
-#
-##############################################################
-
-CUR_PATH=""
-CONTENT=""
-RES=""
-USER_PERMISSION=""
-GROUP_PERMISSION=""
-OTHER_PERMISSION=""
-ITEM_OWNER=""
-ITEM_GROUP=""
-
-################################################################
-#
-# Make sure that uid=root is running this script.
-# Make sure that loop device is built into the kernel
-# Make sure that ACL(Access Control List) and Extended Attribute are
-#     built into the kernel
-#
-################################################################
-
-if [ $UID != 0 ]
-then
-	echo "FAILED: Must have root access to execute this script"
-	exit 1
-fi
-
-#################################################################
-#
-# Prepare Ext2 file system for ACL and Extended Attribute test
-# Make some directory , file and symlink for the test
-# Add three users for the test
-#
-#################################################################
-
-if [ ! -e tacl ]
-then
-	mkdir -m 777 tacl
-else
-	echo "FAILED: Directory tacl are exist"
-	exit 1
-fi
-
-dd if=/dev/zero of=tacl/blkext2 bs=1k count=10240
-chmod 777 tacl/blkext2
-
-losetup /dev/loop0 tacl/blkext2 >/dev/null 2>&1
-if [ $? != 0 ]
-then
-	printf "\nFAILED:  [ losetup ] Must have loop device support by kernel\n"
-	printf "\t to execute this script\n"
-	exit 1
-fi
-
-mount | grep ext2
-if [ $? != 0 ]
-then
-	mkfs -t ext3 /dev/loop0
-	mkdir  -m 777 tacl/mount-ext2
-	mount -t ext3 -o defaults,acl,user_xattr /dev/loop0 tacl/mount-ext2
-	if [ $? != 0 ]
-	then
-		printf "\nFAILED:  [ mount ] Make sure that ACL (Access Control List)\n"
-		printf "\t and Extended Attribute are built into the kernel\n"
-		printf "\t Can not mount ext2 file system with acl and user_xattr options\n"
-		exit 1
-	fi
-
-else
-	mkfs -t ext2 /dev/loop0
-	mkdir  -m 777 tacl/mount-ext2
-	mount -t ext2 -o defaults,acl,user_xattr /dev/loop0 tacl/mount-ext2
-	if [ $? != 0 ]
-	then
-		printf "\nFAILED:  [ mount ] Make sure that ACL (Access Control List)\n"
-		printf "\t and Extended Attribute are built into the kernel\n"
-		printf "\t Can not mount ext2 file system with acl and user_xattr options\n"
-		exit 1
-	fi
-fi
-
-chmod 777 tacl/mount-ext2
-
-useradd -d `pwd`/tacl/tacluser1 tacluser1
-useradd -d `pwd`/tacl/tacluser2 tacluser2
-useradd -d `pwd`/tacl/tacluser3 tacluser3
-useradd -d `pwd`/tacl/tacluser4 tacluser4
-
-if [ ! -e tacl/mount-ext2/shared ]
-then
-	mkdir -p -m 777 tacl/mount-ext2/shared
-fi
-
-CUR_PATH=`pwd`
-
-su - tacluser1 << TACL_USER1
-
-	mkdir $CUR_PATH/tacl/mount-ext2/shared/team1
-	touch $CUR_PATH/tacl/mount-ext2/shared/team1/file1
-
-	cd $CUR_PATH/tacl/mount-ext2/shared/team1
-	ln -sf file1 symlinkfile1
-	cd $CUR_PATH
-
-	cd $CUR_PATH/tacl/mount-ext2/shared
-	ln -sf team1 symlinkdir1
-	cd $CUR_PATH
-
-TACL_USER1
-
-su - tacluser2 << TACL_USER2
-
-	mkdir $CUR_PATH/tacl/mount-ext2/shared/team2
-	touch $CUR_PATH/tacl/mount-ext2/shared/team2/file1
-
-	cd $CUR_PATH/tacl/mount-ext2/shared/team2
-	ln -sf file1 symlinkfile1
-	cd $CUR_PATH
-
-	cd $CUR_PATH/tacl/mount-ext2/shared
-	ln -sf team2 symlinkdir2
-	cd $CUR_PATH
-
-TACL_USER2
-
-#############################################################################################
-#
-#  The permissions bit limit user's act
-#  lrwxrwxrwx    1 tacluser1 tacluser1        5 Jun 23 13:39 symlinkdir1 -> team1
-#  lrwxrwxrwx    1 tacluser2 tacluser2        5 Jun 23 13:39 symlinkdir2 -> team2
-#  dr-x------    2 tacluser1 tacluser1     1024 Jun 23 13:39 team1
-#  drwxrwxr-x    2 tacluser2 tacluser2     1024 Jun 23 13:39 team2
-#
-#############################################################################################
-
-chmod 500 tacl/mount-ext2/shared/team1
-
-su - tacluser1 << TACL_USER1
-
-	touch $CUR_PATH/tacl/mount-ext2/shared/team1/newfil1 2> /dev/null
-	if [ -e $CUR_PATH/tacl/mount-ext2/shared/team1/newfile1 ]
-	then
-		printf "\nFAILED:  [ touch ] Create file must be denied by file permission bits\n"
-		printf "\t [ Physical Directory ]\n"
-	else
-		printf "\nSUCCESS: Create file denied by file permission bits [ Physical directory ]\n"
-	fi
-
-	touch $CUR_PATH/tacl/mount-ext2/shared/symlinkdir1/newfil2 2> /dev/null
-	if [ -e $CUR_PATH/tacl/mount-ext2/shared/team1/newfile2 ]
-	then
-		printf "\nFAILED:  [ touch ] Create file must be denied by file permission bits\n"
-		printf "\t [ Symlink Directory ]\n"
-	else
-		printf "\nSUCCESS: Create file denied by file permission bits [ Symlink directory ]\n"
-	fi
-
-TACL_USER1
-
-#################################################################
-#
-# ACL_USER_OBJ are a superset of the permissions specified
-#   by the file permission bits.
-# The effective user ID of the process matches the user ID of
-#   the file object owner.
-# Owner's act are based ACL_USER_OBJ
-#
-#################################################################
-
-setfacl -m u::rx tacl/mount-ext2/shared/team1
-su - tacluser1 << TACL_USER1
-
-	cd $CUR_PATH/tacl/mount-ext2/shared/team1/ 2> /dev/null
-	if [ $? != 0 ]
-	then
-		printf "\nFAILED:  [ touch ] ACL_USER_OBJ  entry already contains the owner execute\n"
-		printf "\t permissions, but operation failed [ Physical Directory ]\n"
-	else
-		printf "\nSUCCESS: ACL_USER_OBJ  entry contains the owner execute permissions,\n"
-		printf "\t operation success [ Physical Directory ]\n"
-	fi
-
-	cd $CUR_PATH/tacl/mount-ext2/shared/symlinkdir1/ 2> /dev/null
-	if [ $? != 0 ]
-	then
-		printf "\nFAILED: [ touch ] ACL_USER_OBJ  entry already contains the owner execute\n"
-		printf "\t permissions, but operation failed [ Symlink Directory ]\n"
-	else
-		printf "\nSUCCESS: ACL_USER_OBJ  entry contains the owner execute permissions,\n"
-		printf "\t operation success [ Symlink Directory ]\n"
-	fi
-
-TACL_USER1
-
-setfacl -m u::rwx tacl/mount-ext2/shared/team1
-
-su - tacluser1 << TACL_USER1
-
-	touch $CUR_PATH/tacl/mount-ext2/shared/team1/newfil1 2> /dev/null
-	if [ -e $CUR_PATH/tacl/mount-ext2/shared/team1/newfile1 ]
-	then
-		printf "\nFAILED:  [ touch ] ACL_USER_OBJ  entry already contains the owner write \n"
-		printf "\t permissions, but operation failed [ Physical Directory ]\n"
-	else
-		printf "\nSUCCESS: ACL_USER_OBJ  entry contains the owner write permissions,\n"
-		printf "\t operation success [ Physical Directory ]\n"
-	fi
-
-	touch $CUR_PATH/tacl/mount-ext2/shared/symlinkdir1/newfil2 2> /dev/null
-	if [ -e $CUR_PATH/tacl/mount-ext2/shared/team1/newfile2 ]
-	then
-		printf "\nFAILED:  [ touch ] ACL_USER_OBJ  entry already contains the owner write \n"
-		printf "\t permissions, but operation failed [ Symlink Directory ]\n"
-	else
-		printf "\nSUCCESS: ACL_USER_OBJ  entry contains the owner write permissions,\n"
-		printf "\t operation success [ Symlink Directory ]\n"
-	fi
-
-TACL_USER1
-
-#################################################################
-#
-# The effective user ID of the process matches the qualifier of
-#   any entry of type ACL_USER
-# IF  the  matching  ACL_USER entry and the ACL_MASK
-#   entry contain the requested permissions,#  access is granted,
-#  ELSE access is denied.
-#
-#################################################################
-
-setfacl -m u:tacluser3:rwx tacl/mount-ext2/shared/team1
-
-su - tacluser3 << TACL_USER3
-
-	touch $CUR_PATH/tacl/mount-ext2/shared/team1/newfile3 2> /dev/null
-	if [ -e $CUR_PATH/tacl/mount-ext2/shared/team1/newfile3 ]
-	then
-		printf "\nSUCCESS: ACL_USER entry contains the user permissions,\n"
-		printf "\t operation success [ Physical Directory ]\n"
-	else
-		printf "\nFAILED:  ACL_USER entry contains the user permissions,\n"
-		printf "\t but operation denied [ Physical Directory ]\n"
-	fi
-
-	touch $CUR_PATH/tacl/mount-ext2/shared/symlinkdir1/newfile4 2> /dev/null
-	if [ -e $CUR_PATH/tacl/mount-ext2/shared/symlinkdir1/newfile4 ]
-	then
-		printf "\nSUCCESS: ACL_USER entry contains the user permissions,\n"
-		printf "\t operation success [ Symlink Directory ]\n"
-	else
-		printf "\nFAILED:  ACL_USER entry contains the user permissions,\n"
-		printf "\t but operation denied [ Symlink Directory ]\n"
-	fi
-
-TACL_USER3
-
-setfacl -m mask:--- tacl/mount-ext2/shared/team1
-
-su - tacluser3 << TACL_USER3
-
-	touch $CUR_PATH/tacl/mount-ext2/shared/team1/newfile5 2> /dev/null
-	if [ -e $CUR_PATH/tacl/mount-ext2/shared/team1/newfile5 ]
-	then
-		printf "\nFAILED:  [ touch ] ACL_USER entry contains the user permissions\n"
-		printf "\t but ACL_MASK are set --- ,\n"
-		printf "\t operation must be denied [ Physical Directory ]\n"
-	else
-		printf "\nSUCCESS: ACL_USER entry contains the user permissions,\n"
-		printf "\t but ACL_MASK are set ___ ,\n"
-		printf "\t operation success [ Physical Directory ]\n"
-	fi
-
-	touch $CUR_PATH/tacl/mount-ext2/shared/symlinkdir1/newfile6 2> /dev/null
-	if [ -e $CUR_PATH/tacl/mount-ext2/shared/symlinkdir1/newfile6 ]
-	then
-		printf "\nFAILED:  [ touch ] ACL_USER entry contains the user permissions\n"
-		printf "\t but ACL_MASK are set --- ,\n"
-		printf "\t operation must be denied [ Symlink Directory ]\n"
-	else
-		printf "\nSUCCESS: ACL_USER entry contains the user permissions,\n"
-		printf "\t but ACL_MASK are set ___ ,\n"
-		printf "\t operation success [ Symlink Directory ]\n"
-	fi
-
-TACL_USER3
-
-###########################################################################################
-#
-# The effective group ID or any of the supplementary group IDs of the process match the
-#  qualifier of the entry of type ACL_GROUP_OBJ, or the qualifier of any entry of type
-#  ACL_GROUP
-#
-# IF the ACL contains an ACL_MASK entry, THEN
-#                 if  the ACL_MASK entry and any of the matching ACL_GROUP_OBJ
-#                 or ACL_GROUP  entries  contain  the  requested  permissions,
-#                 access is granted,
-#
-#                 else access is denied.
-#
-# ELSE  (note  that  there  can be no ACL_GROUP entries without an ACL_MASK entry)
-#                 if the ACL_GROUP_OBJ entry contains  the  requested  permis-
-#                 sions, access is granted,
-#
-#                 else access is denied.
-#
-###########################################################################################
-
-setfacl -m g:tacluser2:rwx tacl/mount-ext2/shared/team1
-
-su - tacluser2 << TACL_USER2
-	touch $CUR_PATH/tacl/mount-ext2/shared/team1/newfile7 2> /dev/null
-	if [ -e $CUR_PATH/tacl/mount-ext2/shared/team1/newfile7 ]
-	then
-		printf "\nSUCCESS: ACL_GROUP entry contains the group permissions,\n"
-		printf "\t option success [ Physical Directory ]\n"
-	else
-		printf "\nFAILED:  [ touch ] ACL_GROUP entry already contains the group permissions,\n"
-		printf "\t but option success [ Physical Directory ]\n"
-	fi
-
-	touch $CUR_PATH/tacl/mount-ext2/shared/symlinkdir1/newfile8 2> /dev/null
-	if [ -e $CUR_PATH/tacl/mount-ext2/shared/symlinkdir1/newfile8 ]
-	then
-		printf "\nSUCCESS: ACL_GROUP entry contains the group permissions,\n"
-		printf "\t option success [ Symlink Directory ]\n"
-	else
-		printf "\nFAILED:  [ touch ] ACL_GROUP entry already contains the group permissions,\n"
-		printf "\t but option success [ Symlink Directory ]\n"
-	fi
-
-TACL_USER2
-
-setfacl -m mask:--- tacl/mount-ext2/shared/team1
-
-su - tacluser2 << TACL_USER2
-	touch $CUR_PATH/tacl/mount-ext2/shared/team1/newfile9 2> /dev/null
-	if [ -e $CUR_PATH/tacl/mount-ext2/shared/team1/newfile9 ]
-	then
-		printf "\nFAILED:  [ touch ] ACL_GROUP entry contains the group permissions\n"
-		printf "\t and ACL_MASK entry are set ---,\n"
-		printf "\t option must no be success [ Physical Directory ]\n"
-	else
-		printf "\nSUCCESS: ACL_GROUP entry already contains the group permissions\n"
-		printf "\t and ACL_MASK entry are set ---,\n"
-		printf "\t option success [ Physical Directory ]\n"
-	fi
-
-	touch $CUR_PATH/tacl/mount-ext2/shared/symlinkdir1/newfile10 2> /dev/null
-	if [ -e $CUR_PATH/tacl/mount-ext2/shared/symlinkdir1/newfile10 ]
-	then
-		printf "\nFAILED:  [ touch ] ACL_GROUP entry contains the group permissions\n"
-		printf "\t and ACL_MASK entry are set ---,\n"
-		printf "\t option must no be success [ Symlink Directory ]\n"
-	else
-		printf "\nSUCCESS: ACL_GROUP entry already contains the group permissions\n"
-		printf "\t and ACL_MASK entry are set ---,\n"
-		printf "\t option success [ Symlink Directory ]\n"
-	fi
-
-TACL_USER2
-
-setfacl -m g::rwx tacl/mount-ext2/shared/team1
-usermod -g tacluser1 tacluser2
-
-su - tacluser2 << TACL_USER2
-
-	touch $CUR_PATH/tacl/mount-ext2/shared/team1/newfile11 2> /dev/null
-	if [ -e $CUR_PATH/tacl/mount-ext2/shared/team1/newfile11 ]
-	then
-		printf "\nSUCCESS: ACL_GROUP_OBJ entry contains the group owner permissions,\n"
-		printf "\t option success [ Physical Directory ]\n"
-	else
-		printf "\nFAILED:  [ touch ] ACL_GROUP_OBJ entry already contains the group owner,\n"
-		printf "\t but option denied [ Physical Directory ]\n"
-	fi
-
-	touch $CUR_PATH/tacl/mount-ext2/shared/symlinkdir1/newfile12 2> /dev/null
-	if [ -e $CUR_PATH/tacl/mount-ext2/shared/symlinkdir1/newfile12 ]
-	then
-		printf "\nSUCCESS: ACL_GROUP_OBJ entry contains the group owner permissions,\n"
-		printf "\t option success [ Symlink Directory ]\n"
-	else
-		printf "\nFAILED:  [ touch ] ACL_GROUP_OBJ entry already contains the group owner,\n"
-		printf "\t but option denied [ Symlink Directory ]\n"
-	fi
-
-TACL_USER2
-
-setfacl -m mask:--- tacl/mount-ext2/shared/team1
-
-su - tacluser2 << TACL_USER2
-	touch $CUR_PATH/tacl/mount-ext2/shared/team1/newfile13 2> /dev/null
-	if [ -e $CUR_PATH/tacl/mount-ext2/shared/team1/newfile13 ]
-	then
-		printf "\nFAILED:  [ touch ] ACL_GROUP_OBJ entry contains the group owner permissions\n"
-		printf "\t and ACL_MASK entry are set ---,\n"
-		printf "\t option must no be success [ Physical Directory ]\n"
-	else
-		printf "\nSUCCESS: ACL_GROUP_OBJ entry already contains the group owner permissions\n"
-		printf "\t and ACL_MASK entry are set ---,\n"
-		printf "\t option success [ Physical Directory ]\n"
-	fi
-
-	touch $CUR_PATH/tacl/mount-ext2/shared/symlinkdir1/newfile14 2> /dev/null
-	if [ -e $CUR_PATH/tacl/mount-ext2/shared/symlinkdir1/newfile14 ]
-	then
-		printf "\nFAILED:  [ touch ] ACL_GROUP_OBJ entry contains the group owner permissions\n"
-		printf "\t and ACL_MASK entry are set ---,\n"
-		printf "\t option must no be success [ Symlink Directory ]\n"
-	else
-		printf "\nSUCCESS: ACL_GROUP_OBJ entry already contains the group owner permissions\n"
-		printf "\t and ACL_MASK entry are set ---,\n"
-		printf "\t option success [ Symlink Directory ]\n"
-	fi
-
-TACL_USER2
-
-usermod -g tacluser2 tacluser2
-
-###################################################################################
-#
-# IF the ACL_OTHER entry contains the requested permissions, access is granted
-#
-###################################################################################
-
-setfacl -m o::rwx tacl/mount-ext2/shared/team1
-
-su - tacluser4 << TACL_USER4
-
-	touch $CUR_PATH/tacl/mount-ext2/shared/team1/newfile15 2> /dev/null
-	if [ -e $CUR_PATH/tacl/mount-ext2/shared/team1/newfile15 ]
-	then
-		printf "\nSUCCESS: ACL_OTHER entry contains the user permissions,\n"
-		printf "\t operation success [ Physical Directory ]\n"
-	else
-		printf "\nFAILED:  ACL_OTHER entry contains the user permissions,\n"
-		printf "\t but operation denied [ Physical Directory ]\n"
-	fi
-
-	touch $CUR_PATH/tacl/mount-ext2/shared/symlinkdir1/newfile16 2> /dev/null
-	if [ -e $CUR_PATH/tacl/mount-ext2/shared/symlinkdir1/newfile16 ]
-	then
-		printf "\nSUCCESS: ACL_OTHER entry contains the user permissions,\n"
-		printf "\t operation success [ Symlink Directory ]\n"
-	else
-		printf "\nFAILED:  ACL_OTHER entry contains the user permissions,\n"
-		printf "\t but operation denied [ Symlink Directory ]\n"
-	fi
-
-TACL_USER4
-
-setfacl -m mask:--- tacl/mount-ext2/shared/team1
-
-su - tacluser4 << TACL_USER4
-
-	touch $CUR_PATH/tacl/mount-ext2/shared/team1/newfile17 2> /dev/null
-	if [ -e $CUR_PATH/tacl/mount-ext2/shared/team1/newfile17 ]
-	then
-		printf "\nSUCCESS: [ touch ] ACL_OTHER do not strick by ACL_MASK [ Physical Directory ]\n"
-	else
-		printf "\nFAILED:  ACL_OTHER do not strick by ACL_MASK [ Physical Directory ]\n"
-	fi
-
-	touch $CUR_PATH/tacl/mount-ext2/shared/symlinkdir1/newfile18 2> /dev/null
-	if [ -e $CUR_PATH/tacl/mount-ext2/shared/symlinkdir1/newfile18 ]
-	then
-		printf "\nSUCCESS: [ touch ] ACL_OTHER do not strick by ACL_MASK [ Symlink Directory ]\n"
-	else
-		printf "\nFAILED:  ACL_OTHER do not strick by ACL_MASK [ Symlink Directory ]\n"
-	fi
-
-TACL_USER4
-
-############################################################################
-#
-# OBJECT CREATION AND DEFAULT ACLs
-# The new object inherits the default ACL of the containing directory as its access ACL.
-#
-############################################################################
-
-rm -f tacl/mount-ext2/shared/team1/newfil*
-
-#
-# Test ACL_USER_OBJ default ACLs
-#
-setfacl -m d:u::r -m d:g::r -m d:o::r tacl/mount-ext2/shared/team1
-
-su - tacluser1 << TACL_USER1
-
-	MASK=`umask`
-	umask 0
-	touch $CUR_PATH/tacl/mount-ext2/shared/team1/newfile1
-	umask $MASK > /dev/null
-
-TACL_USER1
-
-CONTENT=""
-CONTENT=`ls -l tacl/mount-ext2/shared/team1/newfile1`
-RES=`echo $CONTENT | grep ".r--r--r--" | awk '{print $1}'`
-
-if [ $RES != "" ]
-then
-	printf "\nSUCCESS: With default ACLs set, new file permission set correct.\n"
-else
-	printf "\nFAILED:  With default ACLs set, new file permission set not correct\n"
-fi
-
-
-
-#
-# Test ACL_USER and ACL_GROUP defaults ACLs
-#
-setfacl -m d:u:tacluser3:rw -m d:g:tacluser3:rw tacl/mount-ext2/shared/team1
-su - tacluser3 << TACL_USER3
-
-	MASK=`umask`
-	umask 0
-	touch $CUR_PATH/tacl/mount-ext2/shared/team1/newfile2
-	umask $MASK > /dev/null
-
-TACL_USER3
-
-CONTENT=""
-CONTENT=`ls -l tacl/mount-ext2/shared/team1/newfile2`
-RES=`echo $CONTENT | grep ".r--rw-r--" | awk '{print $1}'`
-
-if [ $RES != "" ]
-then
-	printf "\nSUCCESS: With default ACLs set, new file permission set correct.\n"
-else
-	printf "\nFAILED:  With default ACLs set, new file permission set not correct\n"
-fi
-
-#
-# Test ACL_GROUP default ACLs
-#
-
-setfacl -m d:u::rwx -m d:g::rwx -m d:o::rwx tacl/mount-ext2/shared/team1
-su - tacluser3 << TACL_USER3
-
-	MASK=`umask`
-	umask 0
-	touch $CUR_PATH/tacl/mount-ext2/shared/team1/newfile3
-	umask $MASK > /dev/null
-
-TACL_USER3
-
-CONTENT=""
-CONTENT=`ls -l tacl/mount-ext2/shared/team1/newfile3`
-RES=`echo $CONTENT | grep ".rw-rw-rw-" | awk '{print \$1}'`
-
-if [ $RES != "" ]
-then
-	printf "\nSUCCESS: With default ACLs set, new file permission set correct.\n"
-else
-	printf "\nFAILED:  With default ACLs set, new file permission set not correct\n"
-fi
-
-
-#################################################################################
-#
-# Chmod also change ACL_USER_OBJ ACL_GROUP_OBJ and ACL_OTHER permissions
-#
-#################################################################################
-su - tacluser3 << TACL_USER3
-	MASK=`umask`
-	umask 0
-
-	chmod 777 $CUR_PATH/tacl/mount-ext2/shared/team1/newfile3
-	umask $MASK > /dev/null
-TACL_USER3
-
-CONTENT=""
-CONTENT=`getfacl tacl/mount-ext2/shared/team1/newfile3`
-
-USER_PERMISSION=`echo $CONTENT | awk '{print \$10}'`
-
-GROUP_PERMISSION=`echo $CONTENT | awk '{print \$12}'`
-OTHER_PERMISSION=`echo $CONTENT | awk '{print \$15}'`
-
-if [ $USER_PERMISSION = "user::rwx" ]
-then
-	if [ $GROUP_PERMISSION = "group::rwx" ]
-	then
-		if [ $OTHER_PERMISSION = "other::rwx" ]
-		then
-			printf "\nSUCCESS: Chmod with ACL_USER_OBJ ACL_GROUP_OBJ and ACL_OTHER are correct\n"
-		else
-			printf "\nFAILED:  Chmod with ACL_USER_OBJ ACL_GROUP_OBJ and ACL_OTHER are not correct\n"
-		fi
-	else
-		printf "\nFAILED:  Chmod with ACL_USER_OBJ ACL_GROUP_OBJ and ACL_OTHER are not correct\n"
-	fi
-else
-	printf "\nFAILED:  Chmod with ACL_USER_OBJ ACL_GROUP_OBJ and ACL_OTHER are not correct\n"
-fi
-
-
-#####################################################################################
-#
-# Chown only change object owner and group
-#
-#####################################################################################
-
-chown tacluser2.tacluser2 tacl/mount-ext2/shared/team1/newfile2
-CONTENT=""
-CONTENT=`getfacl tacl/mount-ext2/shared/team1/newfile2`
-
-ITEM_OWNER=`echo $CONTENT | awk '{print \$6}'`
-ITEM_GROUP=`echo $CONTENT | awk '{print \$9}'`
-
-if [ $ITEM_OWNER = "tacluser2" ]
-then
-	if [ $ITEM_GROUP = "tacluser2" ]
-	then
-		printf "\nSUCCESS: Chown correct\n"
-	else
-		printf "\nFAILED:  Chown are not correct\n"
-	fi
-else
-	echo "FAILED:  Chown are not correct"
-fi
-
-#####################################################
-#
-# Test ACLs backup and restore
-#
-#####################################################
-
-getfacl -RL tacl/mount-ext2/ > tacl/tmp1
-setfacl -m u::--- -m g::--- -m o::--- tacl/mount-ext2/shared/team1
-setfacl --restore tacl/tmp1
-getfacl -RL tacl/mount-ext2/ > tacl/tmp2
-
-if [ `diff tacl/tmp1 tacl/tmp2` ]
-then
-	printf "\nFAILED:  ACLs backup and restore are not correct\n"
-else
-	printf "\nSUCCESS: ACLs backup and restore are correct\n"
-fi
-
-printf "\n\tEnd ACLs Test\n"
-
-#####################################################
-#
-# Now begin Extend Attribute test
-#
-#####################################################
-
-printf "\nNow begin Extend Attribute Test\n"
-
-# dir
-printf "\nAttach name:value pair to object dir\n\n"
-attr -s attrname1 -V attrvalue1 tacl/mount-ext2/shared/team2
-if [ $? != 0 ]
-then
-	echo "FAILED: Attach name:value pair to object dir"
-fi
-
-#file
-echo
-echo "Attach name:value pair to object file "
-echo ""
-attr -s attrname2 -V attrvalue2 tacl/mount-ext2/shared/team2/file1
-if [ $? != 0 ]
-then
-	echo "FAILED: Attach name:value pair to object file"
-fi
-
-#symlink file
-echo
-echo "Attach name:value pair to object symlink file"
-echo ""
-attr -s attrname3 -V attrvalue3 tacl/mount-ext2/shared/team2/symlinkfile1
-if [ $? != 0 ]
-then
-	echo "INFO: Can't attach name:value pair to object symlink file"
-fi
-
-echo ""
-ls -lRt tacl/mount-ext2/shared/team2
-
-echo
-echo "get extended attributes of filesystem objects"
-echo ""
-
-echo "Dump the values"
-getfattr -d tacl/mount-ext2/shared/team2
-if [ $? != 0 ]
-then
-	echo "FAILED: getfattr: Dump the values"
-fi
-
-echo "Recursively dump the values"
-getfattr -dR tacl/mount-ext2/*
-if [ $? != 0 ]
-then
-	echo "FAILED: getfattr: Recursively Dump the values"
-fi
-
-echo "Do not follow symlinks."
-echo "but extended user attributes are disallowed for symbolic links"
-getfattr -h --no-dereference tacl/mount-ext2/shared/team2/symlinkfile1
-if [ $? != 0 ]
-then
-        echo "FAILED: getfattr: Do not follow symlinks."
-fi
-echo
-
-echo "Logical walk, follow symbolic links"
-getfattr -L tacl/mount-ext2/shared/team2/*
-if [ $? != 0 ]
-then
-	echo "FAILED: getfattr: Logical walk"
-fi
-
-echo "Physical walk, skip all symbolic links"
-getfattr -P tacl/mount-ext2/shared/team2/*
-if [ $? != 0 ]
-then
-	echo "FAILED: getfattr: Physical walk"
-fi
-
-echo "attr -g to search the named object"
-attr -g attrname1 tacl/mount-ext2/shared/team2
-if [ $? != 0 ]
-then
-	echo "FAILED: attr: to search the named object"
-fi
-echo
-
-echo "attr -r to remove the named object"
-attr -r attrname2 tacl/mount-ext2/shared/team2/file1
-if [ $? != 0 ]
-then
-	echo "FAILED: attr: to remove the named object"
-fi
-
-
-#################################
-#
-# Backup and Restore
-#
-#################################
-getfattr -dhR -m- -e hex tacl/mount-ext2 > tacl/backup.ea
-setfattr -h --restore=tacl/backup.ea
-
-getfattr -dhR -m- -e hex tacl/mount-ext2 > tacl/backup.ea1
-if [ `diff  tacl/backup.ea1  tacl/backup.ea` ]
-then
-        printf "\nFAILED:  EAs backup and restore are not correct\n"
-else
-        printf "\nSUCCESS: EAs backup and restore are correct\n"
-fi
-
-printf "\n\tEnd EAs Test\n"
-
-
-
-#####################################################
-#
-# Clean up
-#
-#####################################################
-
-userdel tacluser1
-userdel tacluser2
-userdel tacluser3
-userdel tacluser4
-umount -d tacl/mount-ext2
-rm -rf tacl
-- 
2.39.1


-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

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

* Re: [LTP] fs/acl: Add ACL_USER_OBJ permission test
  2026-06-15  7:25 ` [LTP] [PATCH v10 1/8] fs/acl: Add ACL_USER_OBJ permission test Sachin Sant
@ 2026-06-15  8:33   ` linuxtestproject.agent
  2026-06-15  9:04     ` Andrea Cervesato via ltp
  0 siblings, 1 reply; 20+ messages in thread
From: linuxtestproject.agent @ 2026-06-15  8:33 UTC (permalink / raw)
  To: Sachin Sant; +Cc: ltp

Hi Sachin,

On Mon, 15 Jun 2026, Sachin Sant wrote:
> fs/acl: Add ACL_USER_OBJ permission test

--- [PATCH 5/8] ---

> +static void test_chown_acl(void)
> +{
> ...
> +	if (acl_set_file(TESTFILE, ACL_TYPE_ACCESS, acl) < 0) {
> +		acl_free(acl);
> +		cleanup_testfile();
> +		if (errno == EOPNOTSUPP)
> +			tst_brk(TCONF | TERRNO, "ACL not supported");
> +		tst_brk(TBROK | TERRNO, "acl_set_file failed");
> +	}

The errno check for EOPNOTSUPP happens after acl_free() and
cleanup_testfile(). cleanup_testfile() calls unlink() internally,
and POSIX does not guarantee that errno is preserved after a
successful syscall. If unlink() clobbers errno, the EOPNOTSUPP
check silently fails and the test reports TBROK instead of TCONF.

test_chmod_acl() in the same file checks errno first:

    if (acl_set_file(...) < 0) {
        if (errno == EOPNOTSUPP) {
            acl_free(acl);
            cleanup_testfile();
            tst_brk(TCONF | TERRNO, ...);
        }
        acl_free(acl);
        cleanup_testfile();
        tst_brk(TBROK | TERRNO, ...);
    }

Could test_chown_acl() use the same pattern?

Verdict - Needs revision

---
Note:

The agent can sometimes produce false positives although often its
findings are genuine. If you find issues with the review, please
comment this email or ignore the suggestions.

Regards,
LTP AI Reviewer

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

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

* Re: [LTP] fs/acl: Add ACL_USER_OBJ permission test
  2026-06-15  8:33   ` [LTP] " linuxtestproject.agent
@ 2026-06-15  9:04     ` Andrea Cervesato via ltp
  2026-06-15  9:29       ` Andrea Cervesato via ltp
  2026-06-15 11:25       ` Sachin Sant
  0 siblings, 2 replies; 20+ messages in thread
From: Andrea Cervesato via ltp @ 2026-06-15  9:04 UTC (permalink / raw)
  To: linuxtestproject.agent; +Cc: ltp

Hi Sachin,

> 
> The errno check for EOPNOTSUPP happens after acl_free() and
> cleanup_testfile(). cleanup_testfile() calls unlink() internally,
> and POSIX does not guarantee that errno is preserved after a
> successful syscall. If unlink() clobbers errno, the EOPNOTSUPP
> check silently fails and the test reports TBROK instead of TCONF.
> 
> test_chmod_acl() in the same file checks errno first:
> 
>     if (acl_set_file(...) < 0) {
>         if (errno == EOPNOTSUPP) {
>             acl_free(acl);
>             cleanup_testfile();
>             tst_brk(TCONF | TERRNO, ...);
>         }
>         acl_free(acl);
>         cleanup_testfile();
>         tst_brk(TBROK | TERRNO, ...);
>     }
> 
> Could test_chown_acl() use the same pattern?

This is correct, but it's also true that TERRNO is printing
errno with its description, so the example is wrong. If any
syscall after acl_set_file() will fail, we will print the errno
of rmdir() or unlink().

You need to save the errno using TEST().

Also, please don't define SAFE_* macros inside the tests, their
are part of the core library and they should not be defined out
of it. Instead, use inline functions.

Regards,
--
Andrea Cervesato
SUSE QE Automation Engineer Linux
andrea.cervesato@suse.com

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

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

* Re: [LTP] fs/acl: Add ACL_USER_OBJ permission test
  2026-06-15  9:04     ` Andrea Cervesato via ltp
@ 2026-06-15  9:29       ` Andrea Cervesato via ltp
  2026-06-15 11:25       ` Sachin Sant
  1 sibling, 0 replies; 20+ messages in thread
From: Andrea Cervesato via ltp @ 2026-06-15  9:29 UTC (permalink / raw)
  To: Andrea Cervesato; +Cc: ltp, linuxtestproject.agent

> This is correct, but it's also true that TERRNO is printing
> errno with its description, so the example is wrong. If any
> syscall after acl_set_file() will fail, we will print the errno
> of rmdir() or unlink().
> 
> You need to save the errno using TEST().

I forgot to mention to use TEST() first and TTERRNO then. It will
print TST_ERR.

--
Andrea Cervesato
SUSE QE Automation Engineer Linux
andrea.cervesato@suse.com

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

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

* Re: [LTP] fs/acl: Add ACL_USER_OBJ permission test
  2026-06-15  9:04     ` Andrea Cervesato via ltp
  2026-06-15  9:29       ` Andrea Cervesato via ltp
@ 2026-06-15 11:25       ` Sachin Sant
  2026-06-15 12:07         ` Andrea Cervesato via ltp
  1 sibling, 1 reply; 20+ messages in thread
From: Sachin Sant @ 2026-06-15 11:25 UTC (permalink / raw)
  To: Andrea Cervesato, linuxtestproject.agent; +Cc: ltp



On 15/06/26 2:34 pm, Andrea Cervesato wrote:
> Also, please don't define SAFE_* macros inside the tests, their
> are part of the core library and they should not be defined out
> of it. Instead, use inline functions.
I think you are referring to SAFE_TRY_UNLINK/RMDIR implemented in acl_lib.h

Apart from acl tests no other test use it today. In future there may be
additional users.
Would it make sense to move them to lib/safe_macros (tst_safe_macros)?

-- 
Thanks
- Sachin



-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

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

* Re: [LTP] fs/acl: Add ACL_USER_OBJ permission test
  2026-06-15 11:25       ` Sachin Sant
@ 2026-06-15 12:07         ` Andrea Cervesato via ltp
  0 siblings, 0 replies; 20+ messages in thread
From: Andrea Cervesato via ltp @ 2026-06-15 12:07 UTC (permalink / raw)
  To: Sachin Sant; +Cc: ltp, linuxtestproject.agent

> On 15/06/26 2:34 pm, Andrea Cervesato wrote:
> > Also, please don't define SAFE_* macros inside the tests, their
> > are part of the core library and they should not be defined out
> > of it. Instead, use inline functions.
> I think you are referring to SAFE_TRY_UNLINK/RMDIR implemented in acl_lib.h

Yes

> 
> Apart from acl tests no other test use it today. In future there may be
> additional users.
> Would it make sense to move them to lib/safe_macros (tst_safe_macros)?

No, it's better to keep them inside the tests. The SAFE_* functions are
meant to be as atomic as possible.

--
Andrea Cervesato
SUSE QE Automation Engineer Linux
andrea.cervesato@suse.com

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

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

* Re: [LTP] fs/acl: Add ACL_USER_OBJ permission test
  2026-06-15 15:15 [LTP] [PATCH v11 1/8] fs/acl: Add ACL_USER_OBJ permission test Sachin Sant
@ 2026-06-15 18:35 ` linuxtestproject.agent
  0 siblings, 0 replies; 20+ messages in thread
From: linuxtestproject.agent @ 2026-06-15 18:35 UTC (permalink / raw)
  To: Sachin Sant; +Cc: ltp

Hi Sachin,

On Mon, 15 Jun 2026 20:45:48 +0530, Sachin Sant wrote:
> fs/acl: Add ACL_USER_OBJ permission test

--- [PATCH 5/8] ---

> fs/acl: Add ACL symlink operations test

> +	if (user_obj->perm != (ACL_READ | ACL_WRITE | ACL_EXECUTE)) {
> +		acl_free(target_acl);
> +		if (unlink(TESTSYMLINK) == -1)
> +			tst_res(TWARN | TERRNO, "unlink symlink failed");
> +		cleanup_testfile();
> +		tst_res(TFAIL, "USER_OBJ has wrong permissions: %o (expected rwx)",
> +			user_obj->perm);

Use-after-free: user_obj points into the target_acl->entries[]
array that was just freed by acl_free(target_acl) on the line
above. Dereferencing user_obj->perm after the free is undefined
behavior.

The same pattern repeats for group_obj->perm and other->perm in the
two blocks that follow.

One fix would be to save the perm value before freeing:

    uint16_t perm = user_obj->perm;
    acl_free(target_acl);
    ...
    tst_res(TFAIL, "USER_OBJ has wrong permissions: %o ...", perm);

Or move acl_free(target_acl) after the tst_res() call in each block.

Verdict - Needs revision

---
Note:

The agent can sometimes produce false positives although often its
findings are genuine. If you find issues with the review, please
comment this email or ignore the suggestions.

Regards,
LTP AI Reviewer

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

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

end of thread, other threads:[~2026-06-15 18:35 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-15  7:25 [LTP] [PATCH v10 0/8] Convert shell-based ACL test (tacl_xattr.sh) to C Sachin Sant
2026-06-15  7:25 ` [LTP] [PATCH v10 1/8] fs/acl: Add ACL_USER_OBJ permission test Sachin Sant
2026-06-15  8:33   ` [LTP] " linuxtestproject.agent
2026-06-15  9:04     ` Andrea Cervesato via ltp
2026-06-15  9:29       ` Andrea Cervesato via ltp
2026-06-15 11:25       ` Sachin Sant
2026-06-15 12:07         ` Andrea Cervesato via ltp
2026-06-15  7:25 ` [LTP] [PATCH v10 2/8] fs/acl: Add ACL mask interaction tests Sachin Sant
2026-06-15  7:25 ` [LTP] [PATCH v10 3/8] fs/acl: Add ACL_OTHER permission test Sachin Sant
2026-06-15  7:25 ` [LTP] [PATCH v10 4/8] fs/acl: Add default ACL inheritance test Sachin Sant
2026-06-15  7:25 ` [LTP] [PATCH v10 5/8] fs/acl: Add chmod/chown ACL interaction tests Sachin Sant
2026-06-15  7:25 ` [LTP] [PATCH v10 6/8] fs/acl: Add ACL symlink operations test Sachin Sant
2026-06-15  7:25 ` [LTP] [PATCH v10 7/8] fs/acl: Add extended attributes test Sachin Sant
2026-06-15  7:25 ` [LTP] [PATCH v10 8/8] fs/acl: Remove old shell-based ACL test Sachin Sant
  -- strict thread matches above, loose matches on Subject: below --
2026-06-15 15:15 [LTP] [PATCH v11 1/8] fs/acl: Add ACL_USER_OBJ permission test Sachin Sant
2026-06-15 18:35 ` [LTP] " linuxtestproject.agent
2026-06-15  5:29 [LTP] [PATCH v9 1/8] " Sachin Sant
2026-06-15  6:32 ` [LTP] " linuxtestproject.agent
2026-06-13  9:05 [LTP] [PATCH v8 1/8] " Sachin Sant
2026-06-13 10:36 ` [LTP] " linuxtestproject.agent
2026-06-12 17:19 [LTP] [PATCH v7 1/8] " Sachin Sant
2026-06-12 19:13 ` [LTP] " linuxtestproject.agent
2026-06-12 10:24 [LTP] [PATCH v6 1/8] " Sachin Sant
2026-06-12 12:27 ` [LTP] " linuxtestproject.agent
2026-06-08  9:21 [LTP] [PATCH v5 1/8] " Sachin Sant
2026-06-08 11:01 ` [LTP] " linuxtestproject.agent

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.