* [LTP] [PATCH v5 0/4] syscalls: lchown: Convert to new API
@ 2025-08-29 21:01 Ricardo B. Marlière via ltp
2025-08-29 21:02 ` [LTP] [PATCH v5 1/4] lib: Add SAFE_LCHOWN Ricardo B. Marlière via ltp
` (3 more replies)
0 siblings, 4 replies; 8+ messages in thread
From: Ricardo B. Marlière via ltp @ 2025-08-29 21:01 UTC (permalink / raw)
To: Linux Test Project; +Cc: Ricardo B. Marlière
Signed-off-by: Ricardo B. Marlière <rbm@suse.com>
---
Changes in v5:
- lchown01: recover original test intent
- lchown02: simplified test description info print
- Link to v4: https://lore.kernel.org/r/20250828-conversions-lchown-v4-0-60dd9a0145f3@suse.com
Changes in v4:
- Merged lchown03 into lchown02
- Link to v3: https://lore.kernel.org/r/20250825-conversions-lchown-v3-0-2d261b3de236@suse.com
Changes in v3:
- Properly used buffer guards
- Rebased
- Link to v2: https://lore.kernel.org/r/20250806-conversions-lchown-v2-0-345590fefaae@suse.com
Changes in v2:
- Join test_case_t structs and arrays definitions
- Simplify overall by removing unneeded comments
- Use octal permission modes
- Use SAFE_TOUCH when possible
- lchown01: Removed unneeded use of geteuid() and getegid()
- lchown02: Merged all setup into a single function
- lchown03: Added test descriptions and used snprintf() instead of strcpy()
- Link to v1: https://lore.kernel.org/r/20250702-conversions-lchown-v1-0-ac7adb3af51d@suse.com
---
Ricardo B. Marlière (4):
lib: Add SAFE_LCHOWN
syscalls: lchown01: Convert to new API
syscalls: lchown02: Convert to new API
syscalls: lchown03: Merge into lchown02
include/safe_macros_fn.h | 3 +
include/tst_safe_macros.h | 3 +
lib/safe_macros.c | 19 ++
runtest/syscalls | 2 -
testcases/kernel/syscalls/lchown/.gitignore | 2 -
testcases/kernel/syscalls/lchown/Makefile | 5 -
testcases/kernel/syscalls/lchown/lchown01.c | 195 ++++-----------
testcases/kernel/syscalls/lchown/lchown02.c | 357 +++++++---------------------
testcases/kernel/syscalls/lchown/lchown03.c | 153 ------------
9 files changed, 160 insertions(+), 579 deletions(-)
---
base-commit: f8c7b6c22db90db8e62d59cb869f6d622d45003f
change-id: 20250702-conversions-lchown-8dbc583f10b8
Best regards,
--
Ricardo B. Marlière <rbm@suse.com>
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 8+ messages in thread
* [LTP] [PATCH v5 1/4] lib: Add SAFE_LCHOWN
2025-08-29 21:01 [LTP] [PATCH v5 0/4] syscalls: lchown: Convert to new API Ricardo B. Marlière via ltp
@ 2025-08-29 21:02 ` Ricardo B. Marlière via ltp
2025-08-29 21:02 ` [LTP] [PATCH v5 2/4] syscalls: lchown01: Convert to new API Ricardo B. Marlière via ltp
` (2 subsequent siblings)
3 siblings, 0 replies; 8+ messages in thread
From: Ricardo B. Marlière via ltp @ 2025-08-29 21:02 UTC (permalink / raw)
To: Linux Test Project; +Cc: Ricardo B. Marlière
From: Ricardo B. Marlière <rbm@suse.com>
Reviewed-by: Andrea Cervesato <andrea.cervesato@suse.com>
Reviewed-by: Li Wang <liwang@redhat.com>
Reviewed-by: Cyril Hrubis <chrubis@suse.cz>
Signed-off-by: Ricardo B. Marlière <rbm@suse.com>
---
include/safe_macros_fn.h | 3 +++
include/tst_safe_macros.h | 3 +++
lib/safe_macros.c | 19 +++++++++++++++++++
3 files changed, 25 insertions(+)
diff --git a/include/safe_macros_fn.h b/include/safe_macros_fn.h
index d256091b76ad10b06b29e3fd5fad8853faa14c08..3799873a248f36e0ff31c862de2703a13fee1bfd 100644
--- a/include/safe_macros_fn.h
+++ b/include/safe_macros_fn.h
@@ -151,6 +151,9 @@ int safe_chown(const char *file, const int lineno, void (cleanup_fn)(void),
int safe_fchown(const char *file, const int lineno, void (cleanup_fn)(void),
int fd, uid_t owner, gid_t group);
+int safe_lchown(const char *file, const int lineno, void (*cleanup_fn)(void),
+ const char *path, uid_t owner, gid_t group);
+
pid_t safe_wait(const char *file, const int lineno, void (cleanup_fn)(void),
int *status);
diff --git a/include/tst_safe_macros.h b/include/tst_safe_macros.h
index 19504beb57ad379c835a13ed5d35fe06e42a6ed6..41d17b1ca4590458cf651a59a6e377c215727094 100644
--- a/include/tst_safe_macros.h
+++ b/include/tst_safe_macros.h
@@ -220,6 +220,9 @@ int safe_getgroups(const char *file, const int lineno, int size, gid_t list[]);
#define SAFE_FCHOWN(fd, owner, group) \
safe_fchown(__FILE__, __LINE__, NULL, (fd), (owner), (group))
+#define SAFE_LCHOWN(path, owner, group) \
+ safe_lchown(__FILE__, __LINE__, NULL, (path), (owner), (group))
+
#define SAFE_WAIT(status) \
safe_wait(__FILE__, __LINE__, NULL, (status))
diff --git a/lib/safe_macros.c b/lib/safe_macros.c
index 726c9ae8ee53759ba983339662a6b41e94eacd7a..60d28b5bdf2bd6fdd348fad50be45ca66fb159a1 100644
--- a/lib/safe_macros.c
+++ b/lib/safe_macros.c
@@ -775,6 +775,25 @@ int safe_fchown(const char *file, const int lineno, void (cleanup_fn)(void),
return rval;
}
+int safe_lchown(const char *file, const int lineno, void (cleanup_fn)(void),
+ const char *path, uid_t owner, gid_t group)
+{
+ int rval;
+
+ rval = lchown(path, owner, group);
+
+ if (rval == -1) {
+ tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn,
+ "lchown(%s,%d,%d) failed", path, owner, group);
+ } else if (rval) {
+ tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn,
+ "Invalid lchown(%s,%d,%d) return value %d", path,
+ owner, group, rval);
+ }
+
+ return rval;
+}
+
pid_t safe_wait(const char *file, const int lineno, void (cleanup_fn)(void),
int *status)
{
--
2.51.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [LTP] [PATCH v5 2/4] syscalls: lchown01: Convert to new API
2025-08-29 21:01 [LTP] [PATCH v5 0/4] syscalls: lchown: Convert to new API Ricardo B. Marlière via ltp
2025-08-29 21:02 ` [LTP] [PATCH v5 1/4] lib: Add SAFE_LCHOWN Ricardo B. Marlière via ltp
@ 2025-08-29 21:02 ` Ricardo B. Marlière via ltp
2025-09-02 13:41 ` Cyril Hrubis
2025-08-29 21:02 ` [LTP] [PATCH v5 3/4] syscalls: lchown02: " Ricardo B. Marlière via ltp
2025-08-29 21:02 ` [LTP] [PATCH v5 4/4] syscalls: lchown03: Merge into lchown02 Ricardo B. Marlière via ltp
3 siblings, 1 reply; 8+ messages in thread
From: Ricardo B. Marlière via ltp @ 2025-08-29 21:02 UTC (permalink / raw)
To: Linux Test Project; +Cc: Ricardo B. Marlière
From: Ricardo B. Marlière <rbm@suse.com>
Reviewed-by: Andrea Cervesato <andrea.cervesato@suse.com>
Reviewed-by: Li Wang <liwang@redhat.com>
Signed-off-by: Ricardo B. Marlière <rbm@suse.com>
---
testcases/kernel/syscalls/lchown/lchown01.c | 195 ++++++----------------------
1 file changed, 43 insertions(+), 152 deletions(-)
diff --git a/testcases/kernel/syscalls/lchown/lchown01.c b/testcases/kernel/syscalls/lchown/lchown01.c
index aaa0ef4038a1aad23212ec2d188274ddd7fcf50d..6204c2acd27c2f407dd57a33e6b8691a8cb96b8d 100644
--- a/testcases/kernel/syscalls/lchown/lchown01.c
+++ b/testcases/kernel/syscalls/lchown/lchown01.c
@@ -1,175 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) International Business Machines Corp., 2001
- *
- * 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/*
- * Test Description:
- * Verify that, lchown(2) succeeds to change the owner and group of a file
- * specified by path to any numeric owner(uid)/group(gid) values when invoked
- * by super-user.
- *
- * Expected Result:
- * lchown(2) should return 0 and the ownership set on the file should match
- * the numeric values contained in owner and group respectively.
- *
- * HISTORY
* 07/2001 Ported by Wayne Boyer
* 11/2010 Code cleanup by Cyril Hrubis chrubis@suse.cz
+ * Copyright (c) 2025 SUSE LLC Ricardo B. Marlière <rbm@suse.com>
*/
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <string.h>
-#include <signal.h>
-
-#include "test.h"
-#include "safe_macros.h"
-
-/*
- * Don't forget to remove USE_LEGACY_COMPAT_16_H from Makefile after
- * rewriting all tests to the new API.
+/*\
+ * Verify that, lchown(2) succeeds to change the owner and group of a file
+ * specified by path to any numeric owner(uid)/group(gid) values when invoked
+ * by super-user.
+ *
+ * lchown(2) should return 0 and the ownership set on the file should match
+ * the numeric values contained in owner and group respectively.
*/
-#include "compat_16.h"
-#define FILE_MODE (S_IFREG|S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
-#define TESTFILE "testfile"
-#define SFILE "slink_file"
+#include "tst_test.h"
-TCID_DEFINE(lchown01);
-int TST_TOTAL = 5;
+#define TESTFILE "testfile"
+#define SFILE "slink_file"
-struct test_case_t {
+static struct test_case_t {
char *desc;
uid_t user_id;
gid_t group_id;
+} test_cases[] = {
+ { "Change Owner/Group ids", 700, 701 },
+ { "Change Owner id only", 702, -1 },
+ { "Change Owner/Group ids", 703, 701 },
+ { "Change Group id only", -1, 704 },
+ { "Change Group/Group ids", 703, 705 },
+ { "Change none", -1, -1 },
};
-static struct test_case_t test_cases[] = {
- {"Change Owner/Group ids", 700, 701},
- {"Change Owner id only", 702, -1},
- {"Change Owner/Group ids", 703, 701},
- {"Change Group id only", -1, 704},
- {"Change Group/Group ids", 703, 705},
- {"Change none", -1, -1},
- {NULL, 0, 0}
-};
-
-static void setup(void);
-static void cleanup(void);
-
-int main(int argc, char *argv[])
+static void run(unsigned int i)
{
struct stat stat_buf;
- int lc;
- int i;
-
- tst_parse_opts(argc, argv, NULL, NULL);
-
- setup();
-
- for (lc = 0; TEST_LOOPING(lc); lc++) {
-
- tst_count = 0;
-
- for (i = 0; test_cases[i].desc != NULL; i++) {
- uid_t user_id = test_cases[i].user_id;
- gid_t group_id = test_cases[i].group_id;
- char *test_desc = test_cases[i].desc;
-
- /*
- * Call lchown(2) with different user id and
- * group id (numeric values) to set it on
- * symlink of testfile.
- */
- TEST(LCHOWN(cleanup, SFILE, user_id, group_id));
-
- if (TEST_RETURN == -1) {
- tst_resm(TFAIL,
- "lchown() Fails to %s, errno %d",
- test_desc, TEST_ERRNO);
- continue;
- }
-
- if (lstat(SFILE, &stat_buf) < 0) {
- tst_brkm(TFAIL, cleanup, "lstat(2) "
- "%s failed, errno %d",
- SFILE, TEST_ERRNO);
- }
-
- if ((int)user_id == -1) {
- if (i > 0)
- user_id =
- test_cases[i - 1].user_id;
- else
- user_id = geteuid();
- }
-
- if ((int)group_id == -1) {
- if (i > 0)
- group_id =
- test_cases[i - 1].group_id;
- else
- group_id = getegid();
- }
-
- /*
- * Check for expected Ownership ids
- * set on testfile.
- */
- if ((stat_buf.st_uid != user_id) ||
- (stat_buf.st_gid != group_id)) {
- tst_resm(TFAIL,
- "%s: incorrect ownership set, "
- "Expected %d %d", SFILE,
- user_id, group_id);
- } else {
- tst_resm(TPASS, "lchown() succeeds to "
- "%s of %s", test_desc, SFILE);
- }
- }
- }
-
- cleanup();
- tst_exit();
+ struct test_case_t *tc = &test_cases[i];
+ uid_t user_id = tc->user_id;
+ gid_t group_id = tc->group_id;
+
+ SAFE_LSTAT(SFILE, &stat_buf);
+ uid_t cmp_usr_id = user_id == -1 ? stat_buf.st_uid : user_id;
+ gid_t cmp_grp_id = group_id == -1 ? stat_buf.st_gid : group_id;
+
+ tst_res(TINFO, "%s", tc->desc);
+ SAFE_LCHOWN(SFILE, user_id, group_id);
+ SAFE_LSTAT(SFILE, &stat_buf);
+ TST_EXP_EQ_LI(stat_buf.st_uid, cmp_usr_id);
+ TST_EXP_EQ_LI(stat_buf.st_gid, cmp_grp_id);
}
static void setup(void)
{
- int fd;
-
- tst_sig(NOFORK, DEF_HANDLER, cleanup);
-
- tst_require_root();
-
- TEST_PAUSE;
- tst_tmpdir();
-
- if ((fd = open(TESTFILE, O_RDWR | O_CREAT, FILE_MODE)) == -1) {
- tst_brkm(TBROK, cleanup, "open failed");
- }
- SAFE_CLOSE(cleanup, fd);
-
- SAFE_SYMLINK(cleanup, TESTFILE, SFILE);
+ SAFE_TOUCH(TESTFILE, 0644, NULL);
+ SAFE_SYMLINK(TESTFILE, SFILE);
}
-static void cleanup(void)
-{
- tst_rmdir();
-}
+static struct tst_test test = {
+ .tcnt = ARRAY_SIZE(test_cases),
+ .test = run,
+ .setup = setup,
+ .needs_tmpdir = 1,
+ .needs_root = 1,
+};
--
2.51.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [LTP] [PATCH v5 3/4] syscalls: lchown02: Convert to new API
2025-08-29 21:01 [LTP] [PATCH v5 0/4] syscalls: lchown: Convert to new API Ricardo B. Marlière via ltp
2025-08-29 21:02 ` [LTP] [PATCH v5 1/4] lib: Add SAFE_LCHOWN Ricardo B. Marlière via ltp
2025-08-29 21:02 ` [LTP] [PATCH v5 2/4] syscalls: lchown01: Convert to new API Ricardo B. Marlière via ltp
@ 2025-08-29 21:02 ` Ricardo B. Marlière via ltp
2025-09-02 14:20 ` Cyril Hrubis
2025-08-29 21:02 ` [LTP] [PATCH v5 4/4] syscalls: lchown03: Merge into lchown02 Ricardo B. Marlière via ltp
3 siblings, 1 reply; 8+ messages in thread
From: Ricardo B. Marlière via ltp @ 2025-08-29 21:02 UTC (permalink / raw)
To: Linux Test Project; +Cc: Ricardo B. Marlière
From: Ricardo B. Marlière <rbm@suse.com>
Signed-off-by: Ricardo B. Marlière <rbm@suse.com>
---
testcases/kernel/syscalls/lchown/lchown02.c | 342 +++++++---------------------
1 file changed, 76 insertions(+), 266 deletions(-)
diff --git a/testcases/kernel/syscalls/lchown/lchown02.c b/testcases/kernel/syscalls/lchown/lchown02.c
index c0932fb7a9f6ec592d7628f96813876f34dc0440..f8da416e24456b3097fe6be8f80b13a8ec233f05 100644
--- a/testcases/kernel/syscalls/lchown/lchown02.c
+++ b/testcases/kernel/syscalls/lchown/lchown02.c
@@ -1,296 +1,106 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) International Business Machines Corp., 2001
- *
- * 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/*
- * Test Name: lchown02
- *
- * Test Description:
- * Verify that,
- * 1) lchown(2) returns -1 and sets errno to EPERM if the effective user id
- * of process does not match the owner of the file and the process is
- * not super user.
- * 2) lchown(2) returns -1 and sets errno to EACCES if search permission is
- * denied on a component of the path prefix.
- * 3) lchown(2) returns -1 and sets errno to EFAULT if pathname points
- * outside user's accessible address space.
- * 4) lchown(2) returns -1 and sets errno to ENAMETOOLONG if the pathname
- * component is too long.
- * 5) lchown(2) returns -1 and sets errno to ENOTDIR if the directory
- * component in pathname is not a directory.
- * 6) lchown(2) returns -1 and sets errno to ENOENT if the specified file
- * does not exists.
- *
- * Expected Result:
- * lchown() should fail with return value -1 and set expected errno.
- *
- * HISTORY
* 07/2001 Ported by Wayne Boyer
* 11/2010 Rewritten by Cyril Hrubis chrubis@suse.cz
+ * Copyright (c) 2025 SUSE LLC Ricardo B. Marlière <rbm@suse.com>
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <string.h>
-#include <signal.h>
-#include <grp.h>
-#include <pwd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-
-#include "test.h"
-#include "safe_macros.h"
-
-/*
- * Don't forget to remove USE_LEGACY_COMPAT_16_H from Makefile after
- * rewriting all tests to the new API.
+/*\
+ * Verify that lchown(2) fails with errno:
+ *
+ * - EPERM, if the effective user id of process does not match the owner of
+ * the file and the process is not super user.
+ * - EACCES, if search permission is denied on a component of the path prefix.
+ * - EFAULT, if pathname points outside user's accessible address space.
+ * - ENAMETOOLONG, if the pathname component is too long.
+ * - ENOTDIR, if the directory component in pathname is not a directory.
+ * - ENOENT, if the specified file does not exists.
*/
-#include "compat_16.h"
-
-#define TEST_USER "nobody"
-#define MODE_RWX S_IRWXU | S_IRWXG | S_IRWXO
-#define FILE_MODE S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
-#define DIR_TEMP "testdir_1"
-#define TEST_FILE1 "tfile_1"
-#define SFILE1 "sfile_1"
-#define TEST_FILE2 "testdir_1/tfile_2"
-#define SFILE2 "testdir_1/sfile_2"
-#define TFILE3 "t_file"
-#define SFILE3 "t_file/sfile"
-TCID_DEFINE(lchown02);
-int TST_TOTAL = 7;
-
-static void setup(void);
-static void cleanup(void);
-static void setup_eperm(int pos);
-static void setup_eacces(int pos);
-static void setup_enotdir(int pos);
-static void setup_longpath(int pos);
-static void setup_efault(int pos);
+#include <pwd.h>
-static char path[PATH_MAX + 2];
+#include "tst_test.h"
+#include "compat_tst_16.h"
+
+#define TEST_USER "nobody"
+#define DIR_TEMP "testdir_1"
+#define TFILE1 "tfile_1"
+#define SFILE1 "sfile_1"
+#define TFILE2 "testdir_1/tfile_2"
+#define SFILE2 "testdir_1/sfile_2"
+#define TFILE3 "t_file"
+#define SFILE3 "t_file/sfile"
+#define LONGPATHSIZE (PATH_MAX+2)
+
+static char *sfile1;
+static char *sfile2;
+static char *bad_addr;
+static char *longpath;
+static char *sfile3;
+static char *empty;
+static struct passwd *ltpuser;
-struct test_case_t {
- char *pathname;
+static struct test_case_t {
+ char **pathname;
char *desc;
int exp_errno;
- void (*setup) (int pos);
-};
-
-static struct test_case_t test_cases[] = {
- {SFILE1, "Process is not owner/root", EPERM, setup_eperm},
- {SFILE2, "Search permission denied", EACCES, setup_eacces},
- {NULL, "Unaccessible address space", EFAULT, setup_efault},
- {path, "Pathname too long", ENAMETOOLONG, setup_longpath},
- {SFILE3, "Path contains regular file", ENOTDIR, setup_enotdir},
- {"", "Pathname is empty", ENOENT, NULL},
- {NULL, NULL, 0, NULL}
+} test_cases[] = {
+ { &sfile1, "Process is not owner/root", EPERM },
+ { &sfile2, "Search permission denied", EACCES },
+ { &bad_addr, "Unaccessible address space", EFAULT },
+ { &longpath, "Pathname too long", ENAMETOOLONG },
+ { &sfile3, "Path contains regular file", ENOTDIR },
+ { &empty, "Pathname is empty", ENOENT },
};
-static struct passwd *ltpuser;
-
-int main(int argc, char *argv[])
+static void run(unsigned int i)
{
- int lc;
uid_t user_id;
gid_t group_id;
- int i;
-
- tst_parse_opts(argc, argv, NULL, NULL);
-
- setup();
+ struct test_case_t *tc = &test_cases[i];
- user_id = geteuid();
- UID16_CHECK(user_id, lchown, cleanup);
- group_id = getegid();
- GID16_CHECK(group_id, lchown, cleanup);
+ UID16_CHECK((user_id = geteuid()), "lchown");
+ GID16_CHECK((group_id = getegid()), "lchown");
- for (lc = 0; TEST_LOOPING(lc); lc++) {
- tst_count = 0;
-
- for (i = 0; test_cases[i].desc != NULL; i++) {
- char *file_name = test_cases[i].pathname;
- char *test_desc = test_cases[i].desc;
-
- /*
- * Call lchown(2) to test different test conditions.
- * verify that it fails with -1 return value and
- * sets appropriate errno.
- */
- TEST(LCHOWN(cleanup, file_name, user_id, group_id));
-
- /* Check return code from lchown(2) */
- if (TEST_RETURN == -1) {
- if (TEST_ERRNO == test_cases[i].exp_errno) {
- tst_resm(TPASS,
- "lchown(2) fails, %s, errno:%d",
- test_desc, TEST_ERRNO);
- } else {
- tst_resm(TFAIL, "lchown(2) fails, %s, "
- "errno:%d, expected errno:%d",
- test_desc, TEST_ERRNO,
- test_cases[i].exp_errno);
- }
- } else {
- tst_resm(TFAIL, "lchown(2) returned %ld, "
- "expected -1, errno:%d", TEST_RETURN,
- test_cases[i].exp_errno);
- }
- }
- }
-
- cleanup();
- tst_exit();
+ TST_EXP_FAIL(lchown(*tc->pathname, user_id, group_id), tc->exp_errno, "%s", tc->desc);
}
static void setup(void)
{
- int i;
-
- tst_sig(FORK, DEF_HANDLER, cleanup);
-
- tst_require_root();
-
- TEST_PAUSE;
-
- /* change euid and gid to nobody */
- ltpuser = getpwnam(TEST_USER);
-
- if (ltpuser == NULL)
- tst_brkm(TBROK, cleanup, "getpwnam failed");
-
- if (setgid(ltpuser->pw_uid) == -1)
- tst_resm(TBROK | TERRNO, "setgid failed");
-
- tst_tmpdir();
-
- for (i = 0; test_cases[i].desc != NULL; i++)
- if (test_cases[i].setup != NULL)
- test_cases[i].setup(i);
-}
-
-/*
- * setup_eperm() - setup function for a test condition for which lchown(2)
- * returns -1 and sets errno to EPERM.
- *
- * Create test file and symlink with uid 0.
- */
-static void setup_eperm(int pos LTP_ATTRIBUTE_UNUSED)
-{
- int fd;
-
- /* create a testfile */
- if ((fd = open(TEST_FILE1, O_RDWR | O_CREAT, 0666)) == -1)
- tst_brkm(TBROK | TERRNO, cleanup, "open failed");
-
- SAFE_CLOSE(cleanup, fd);
-
- /* become root once more */
- if (seteuid(0) == -1)
- tst_resm(TBROK | TERRNO, "setuid(0) failed");
-
- /* create symling to testfile */
- SAFE_SYMLINK(cleanup, TEST_FILE1, SFILE1);
-
- /* back to the user nobody */
- if (seteuid(ltpuser->pw_uid) == -1)
- tst_resm(TBROK | TERRNO, "seteuid(%d) failed", ltpuser->pw_uid);
-}
-
-/*
- * setup_eaccess() - setup function for a test condition for which lchown(2)
- * returns -1 and sets errno to EACCES.
- *
- * Create a test directory under temporary directory and create a test file
- * under this directory with mode "0666" permissions.
- * Modify the mode permissions on test directory such that process will not
- * have search permissions on test directory.
- */
-static void setup_eacces(int pos LTP_ATTRIBUTE_UNUSED)
-{
- int fd;
-
- /* create a test directory */
- SAFE_MKDIR(cleanup, DIR_TEMP, MODE_RWX);
-
- /* create a file under test directory */
- if ((fd = open(TEST_FILE2, O_RDWR | O_CREAT, 0666)) == -1)
- tst_brkm(TBROK | TERRNO, cleanup, "open failed");
-
- SAFE_CLOSE(cleanup, fd);
-
- /* create a symlink of testfile */
- SAFE_SYMLINK(cleanup, TEST_FILE2, SFILE2);
+ bad_addr = tst_get_bad_addr(NULL);
- /* modify mode permissions on test directory */
- SAFE_CHMOD(cleanup, DIR_TEMP, FILE_MODE);
-}
+ memset(longpath, 'a', LONGPATHSIZE - 1);
+ longpath[LONGPATHSIZE-1] = 0;
-/*
- * setup_efault() -- setup for a test condition where lchown(2) returns -1 and
- * sets errno to EFAULT.
- *
- * Create "bad address" by explicitly mmaping anonymous page that may not be
- * accesed (see PROT_NONE).
- */
-static void setup_efault(int pos)
-{
- test_cases[pos].pathname = tst_get_bad_addr(cleanup);
-}
+ ltpuser = SAFE_GETPWNAM(TEST_USER);
+ SAFE_SETGID(ltpuser->pw_uid);
-/*
- * setup_enotdir() - setup function for a test condition for which chown(2)
- * returns -1 and sets errno to ENOTDIR.
- *
- * Create a regular file "t_file" to call lchown(2) on "t_file/sfile" later.
- */
-static void setup_enotdir(int pos LTP_ATTRIBUTE_UNUSED)
-{
- int fd;
+ SAFE_TOUCH(TFILE1, 0666, NULL);
+ SAFE_SETEUID(0);
+ SAFE_SYMLINK(TFILE1, SFILE1);
+ SAFE_SETEUID(ltpuser->pw_uid);
- /* create a testfile under temporary directory */
- if ((fd = open(TFILE3, O_RDWR | O_CREAT, MODE_RWX)) == -1) {
- tst_brkm(TBROK | TERRNO, cleanup, "open(2) %s failed", TFILE3);
- }
+ SAFE_MKDIR(DIR_TEMP, 0777);
+ SAFE_TOUCH(TFILE2, 0666, NULL);
+ SAFE_SYMLINK(TFILE2, SFILE2);
+ SAFE_CHMOD(DIR_TEMP, 0644);
- SAFE_CLOSE(cleanup, fd);
+ SAFE_TOUCH(TFILE3, 0777, NULL);
}
-/*
- * longpath_setup() - setup to create a node with a name length exceeding
- * the length of PATH_MAX.
- */
-static void setup_longpath(int pos)
-{
- memset(test_cases[pos].pathname, 'a', PATH_MAX + 1);
- test_cases[pos].pathname[PATH_MAX + 1] = '\0';
-}
-
-static void cleanup(void)
-{
- if (seteuid(0) == -1) {
- tst_resm(TINFO | TERRNO,
- "seteuid(2) failed to set the effective uid to 0");
- }
-
- tst_rmdir();
-}
+static struct tst_test test = {
+ .tcnt = ARRAY_SIZE(test_cases),
+ .test = run,
+ .setup = setup,
+ .needs_root = 1,
+ .needs_tmpdir = 1,
+ .bufs = (struct tst_buffers []) {
+ {&longpath, .size = LONGPATHSIZE},
+ {&sfile1, .str = SFILE1},
+ {&sfile2, .str = SFILE2},
+ {&sfile3, .str = SFILE3},
+ {&empty, .str = ""},
+ {}
+ },
+};
--
2.51.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [LTP] [PATCH v5 4/4] syscalls: lchown03: Merge into lchown02
2025-08-29 21:01 [LTP] [PATCH v5 0/4] syscalls: lchown: Convert to new API Ricardo B. Marlière via ltp
` (2 preceding siblings ...)
2025-08-29 21:02 ` [LTP] [PATCH v5 3/4] syscalls: lchown02: " Ricardo B. Marlière via ltp
@ 2025-08-29 21:02 ` Ricardo B. Marlière via ltp
2025-09-02 14:27 ` Cyril Hrubis
3 siblings, 1 reply; 8+ messages in thread
From: Ricardo B. Marlière via ltp @ 2025-08-29 21:02 UTC (permalink / raw)
To: Linux Test Project; +Cc: Ricardo B. Marlière
From: Ricardo B. Marlière <rbm@suse.com>
Signed-off-by: Ricardo B. Marlière <rbm@suse.com>
---
runtest/syscalls | 2 -
testcases/kernel/syscalls/lchown/.gitignore | 2 -
testcases/kernel/syscalls/lchown/Makefile | 5 -
testcases/kernel/syscalls/lchown/lchown02.c | 29 ++++--
testcases/kernel/syscalls/lchown/lchown03.c | 153 ----------------------------
5 files changed, 23 insertions(+), 168 deletions(-)
diff --git a/runtest/syscalls b/runtest/syscalls
index c9b46b8efe3217150ee0740e982ea5a133b3aa46..4b284f27939d270ce920e02e2febc1fccc0fa231 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -732,9 +732,7 @@ landlock10 landlock10
lchown01 lchown01
lchown01_16 lchown01_16
lchown02 lchown02
-lchown03 lchown03
lchown02_16 lchown02_16
-lchown03_16 lchown03_16
lgetxattr01 lgetxattr01
lgetxattr02 lgetxattr02
diff --git a/testcases/kernel/syscalls/lchown/.gitignore b/testcases/kernel/syscalls/lchown/.gitignore
index e3c7bc29c32d6ef65fd8debfdb9e651dbd96364b..491ffa0815984ec68484c07696621ff668648351 100644
--- a/testcases/kernel/syscalls/lchown/.gitignore
+++ b/testcases/kernel/syscalls/lchown/.gitignore
@@ -2,5 +2,3 @@
/lchown01_16
/lchown02
/lchown02_16
-/lchown03
-/lchown03_16
diff --git a/testcases/kernel/syscalls/lchown/Makefile b/testcases/kernel/syscalls/lchown/Makefile
index 7c76afea572e8ba6c5509714ba6f9f45a7b2d4d7..1a66088e3206b2073a3cac2e62a71115ece9b4e7 100644
--- a/testcases/kernel/syscalls/lchown/Makefile
+++ b/testcases/kernel/syscalls/lchown/Makefile
@@ -3,13 +3,8 @@
top_srcdir ?= ../../../..
-# Remove after rewriting all tests to the new API.
-USE_LEGACY_COMPAT_16_H := 1
-
include $(top_srcdir)/include/mk/testcases.mk
-SRCS := $(sort $(wildcard $(abs_srcdir)/lchown*.c))
-
include $(abs_srcdir)/../utils/compat_16.mk
include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/testcases/kernel/syscalls/lchown/lchown02.c b/testcases/kernel/syscalls/lchown/lchown02.c
index f8da416e24456b3097fe6be8f80b13a8ec233f05..db068865acdc7d0ccbbc307633df45993ad95959 100644
--- a/testcases/kernel/syscalls/lchown/lchown02.c
+++ b/testcases/kernel/syscalls/lchown/lchown02.c
@@ -16,6 +16,8 @@
* - ENAMETOOLONG, if the pathname component is too long.
* - ENOTDIR, if the directory component in pathname is not a directory.
* - ENOENT, if the specified file does not exists.
+ * - ELOOP, if too many symbolic links were encountered in resolving path.
+ * - EROFS, if the file is on a read-only file system.
*/
#include <pwd.h>
@@ -31,14 +33,17 @@
#define SFILE2 "testdir_1/sfile_2"
#define TFILE3 "t_file"
#define SFILE3 "t_file/sfile"
-#define LONGPATHSIZE (PATH_MAX+2)
+#define TEST_EROFS "mntpoint"
+#define MAXPATH (PATH_MAX+2)
static char *sfile1;
static char *sfile2;
static char *bad_addr;
-static char *longpath;
+static char *maxpath;
static char *sfile3;
static char *empty;
+static char *longpath;
+static char *erofs;
static struct passwd *ltpuser;
static struct test_case_t {
@@ -49,9 +54,11 @@ static struct test_case_t {
{ &sfile1, "Process is not owner/root", EPERM },
{ &sfile2, "Search permission denied", EACCES },
{ &bad_addr, "Unaccessible address space", EFAULT },
- { &longpath, "Pathname too long", ENAMETOOLONG },
+ { &maxpath, "Pathname too long", ENAMETOOLONG },
{ &sfile3, "Path contains regular file", ENOTDIR },
{ &empty, "Pathname is empty", ENOENT },
+ { &longpath, "Too many symlinks", ELOOP },
+ { &erofs, "Read-only filesystem", EROFS },
};
static void run(unsigned int i)
@@ -70,8 +77,14 @@ static void setup(void)
{
bad_addr = tst_get_bad_addr(NULL);
- memset(longpath, 'a', LONGPATHSIZE - 1);
- longpath[LONGPATHSIZE-1] = 0;
+ memset(maxpath, 'a', MAXPATH - 1);
+ maxpath[MAXPATH-1] = 0;
+
+ snprintf(longpath, sizeof(longpath), ".");
+ SAFE_MKDIR("longpath", 0755);
+ SAFE_SYMLINK("../longpath", "longpath/longpath");
+ for (int i = 0; i < 43; i++)
+ strcat(longpath, "/longpath");
ltpuser = SAFE_GETPWNAM(TEST_USER);
SAFE_SETGID(ltpuser->pw_uid);
@@ -95,12 +108,16 @@ static struct tst_test test = {
.setup = setup,
.needs_root = 1,
.needs_tmpdir = 1,
+ .mntpoint = TEST_EROFS,
+ .needs_rofs = 1,
.bufs = (struct tst_buffers []) {
- {&longpath, .size = LONGPATHSIZE},
+ {&maxpath, .size = MAXPATH},
{&sfile1, .str = SFILE1},
{&sfile2, .str = SFILE2},
{&sfile3, .str = SFILE3},
+ {&longpath, .size = PATH_MAX},
{&empty, .str = ""},
+ { &erofs, .str = TEST_EROFS },
{}
},
};
diff --git a/testcases/kernel/syscalls/lchown/lchown03.c b/testcases/kernel/syscalls/lchown/lchown03.c
deleted file mode 100644
index ecb6ed64dfd472d56abbc5a4fe5da67a48919c58..0000000000000000000000000000000000000000
--- a/testcases/kernel/syscalls/lchown/lchown03.c
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (c) 2014 Fujitsu Ltd.
- * Author: Zeng Linggang <zenglg.jy@cn.fujitsu.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-/*
- * Test Description:
- * Verify that,
- * 1. lchown() fails with -1 return value and sets errno to ELOOP
- * if too many symbolic links were encountered in resolving path.
- * 2. lchown() fails with -1 return value and sets errno to EROFS
- * if the file is on a read-only file system.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <string.h>
-#include <signal.h>
-#include <grp.h>
-#include <pwd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-#include <sys/mount.h>
-
-#include "test.h"
-#include "safe_macros.h"
-
-/*
- * Don't forget to remove USE_LEGACY_COMPAT_16_H from Makefile after
- * rewriting all tests to the new API.
- */
-#include "compat_16.h"
-
-#define DIR_MODE (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP| \
- S_IXGRP|S_IROTH|S_IXOTH)
-#define TEST_EROFS "mntpoint"
-
-static char test_eloop[PATH_MAX] = ".";
-static const char *device;
-static int mount_flag;
-
-static struct test_case_t {
- char *pathname;
- int exp_errno;
-} test_cases[] = {
- {test_eloop, ELOOP},
- {TEST_EROFS, EROFS},
-};
-
-TCID_DEFINE(lchown03);
-int TST_TOTAL = ARRAY_SIZE(test_cases);
-
-static void setup(void);
-static void lchown_verify(const struct test_case_t *);
-static void cleanup(void);
-
-int main(int argc, char *argv[])
-{
- int lc;
- int i;
-
- tst_parse_opts(argc, argv, NULL, NULL);
-
- setup();
-
- for (lc = 0; TEST_LOOPING(lc); lc++) {
- tst_count = 0;
- for (i = 0; i < TST_TOTAL; i++)
- lchown_verify(&test_cases[i]);
- }
-
- cleanup();
- tst_exit();
-}
-
-static void setup(void)
-{
- int i;
- const char *fs_type;
-
- tst_require_root();
-
- tst_sig(NOFORK, DEF_HANDLER, cleanup);
-
- TEST_PAUSE;
-
- tst_tmpdir();
-
- fs_type = tst_dev_fs_type();
- device = tst_acquire_device(cleanup);
-
- if (!device)
- tst_brkm(TCONF, cleanup, "Failed to acquire device");
-
- SAFE_MKDIR(cleanup, "test_eloop", DIR_MODE);
- SAFE_SYMLINK(cleanup, "../test_eloop", "test_eloop/test_eloop");
- for (i = 0; i < 43; i++)
- strcat(test_eloop, "/test_eloop");
-
- tst_mkfs(cleanup, device, fs_type, NULL, NULL);
- SAFE_MKDIR(cleanup, TEST_EROFS, DIR_MODE);
- SAFE_MOUNT(cleanup, device, TEST_EROFS, fs_type, MS_RDONLY, NULL);
- mount_flag = 1;
-}
-
-static void lchown_verify(const struct test_case_t *test)
-{
- UID16_CHECK(geteuid(), "lchown", cleanup)
- GID16_CHECK(getegid(), "lchown", cleanup)
-
- TEST(LCHOWN(cleanup, test->pathname, geteuid(), getegid()));
-
- if (TEST_RETURN != -1) {
- tst_resm(TFAIL, "lchown() returned %ld, expected -1, errno=%d",
- TEST_RETURN, test->exp_errno);
- return;
- }
-
- if (TEST_ERRNO == test->exp_errno) {
- tst_resm(TPASS | TTERRNO, "lchown() failed as expected");
- } else {
- tst_resm(TFAIL | TTERRNO,
- "lchown() failed unexpectedly; expected: %d - %s",
- test->exp_errno,
- strerror(test->exp_errno));
- }
-}
-
-static void cleanup(void)
-{
- if (mount_flag && tst_umount(TEST_EROFS) < 0)
- tst_resm(TWARN | TERRNO, "umount device:%s failed", device);
-
- if (device)
- tst_release_device(device);
-
- tst_rmdir();
-}
--
2.51.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [LTP] [PATCH v5 2/4] syscalls: lchown01: Convert to new API
2025-08-29 21:02 ` [LTP] [PATCH v5 2/4] syscalls: lchown01: Convert to new API Ricardo B. Marlière via ltp
@ 2025-09-02 13:41 ` Cyril Hrubis
0 siblings, 0 replies; 8+ messages in thread
From: Cyril Hrubis @ 2025-09-02 13:41 UTC (permalink / raw)
To: Ricardo B. Marlière; +Cc: Linux Test Project
Hi!
Reviewed-by: Cyril Hrubis <chrubis@suse.cz>
--
Cyril Hrubis
chrubis@suse.cz
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [LTP] [PATCH v5 3/4] syscalls: lchown02: Convert to new API
2025-08-29 21:02 ` [LTP] [PATCH v5 3/4] syscalls: lchown02: " Ricardo B. Marlière via ltp
@ 2025-09-02 14:20 ` Cyril Hrubis
0 siblings, 0 replies; 8+ messages in thread
From: Cyril Hrubis @ 2025-09-02 14:20 UTC (permalink / raw)
To: Ricardo B. Marlière; +Cc: Linux Test Project
Hi!
> + UID16_CHECK((user_id = geteuid()), "lchown");
> + GID16_CHECK((group_id = getegid()), "lchown");
The test does not change the uid/git during it's run so user_id and
group_id can be checked and initialized once in the test setup. We also
set it to ltpuser ids so we know the value there as well.
Anyways that is very minor so with that fixed:
Reviewed-by: Cyril Hrubis <chrubis@suse.cz>
--
Cyril Hrubis
chrubis@suse.cz
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [LTP] [PATCH v5 4/4] syscalls: lchown03: Merge into lchown02
2025-08-29 21:02 ` [LTP] [PATCH v5 4/4] syscalls: lchown03: Merge into lchown02 Ricardo B. Marlière via ltp
@ 2025-09-02 14:27 ` Cyril Hrubis
0 siblings, 0 replies; 8+ messages in thread
From: Cyril Hrubis @ 2025-09-02 14:27 UTC (permalink / raw)
To: Ricardo B. Marlière; +Cc: Linux Test Project
Hi!
> static void run(unsigned int i)
> @@ -70,8 +77,14 @@ static void setup(void)
> {
> bad_addr = tst_get_bad_addr(NULL);
>
> - memset(longpath, 'a', LONGPATHSIZE - 1);
> - longpath[LONGPATHSIZE-1] = 0;
> + memset(maxpath, 'a', MAXPATH - 1);
> + maxpath[MAXPATH-1] = 0;
> +
> + snprintf(longpath, sizeof(longpath), ".");
> + SAFE_MKDIR("longpath", 0755);
> + SAFE_SYMLINK("../longpath", "longpath/longpath");
> + for (int i = 0; i < 43; i++)
> + strcat(longpath, "/longpath");
There is much more easier way how to get ELOOP, just create two symlinks
pointing to each other.
SAFE_SYMLINK("infinte_loop_a", "infinite_loop_b");
SAFE_SYMLINK("infinte_loop_b", "infinite_loop_a");
Trying to resolve either of these ends up in ELOOP.
--
Cyril Hrubis
chrubis@suse.cz
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2025-09-02 14:26 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-29 21:01 [LTP] [PATCH v5 0/4] syscalls: lchown: Convert to new API Ricardo B. Marlière via ltp
2025-08-29 21:02 ` [LTP] [PATCH v5 1/4] lib: Add SAFE_LCHOWN Ricardo B. Marlière via ltp
2025-08-29 21:02 ` [LTP] [PATCH v5 2/4] syscalls: lchown01: Convert to new API Ricardo B. Marlière via ltp
2025-09-02 13:41 ` Cyril Hrubis
2025-08-29 21:02 ` [LTP] [PATCH v5 3/4] syscalls: lchown02: " Ricardo B. Marlière via ltp
2025-09-02 14:20 ` Cyril Hrubis
2025-08-29 21:02 ` [LTP] [PATCH v5 4/4] syscalls: lchown03: Merge into lchown02 Ricardo B. Marlière via ltp
2025-09-02 14:27 ` Cyril Hrubis
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).