diff options
Diffstat (limited to 'testcases/kernel/syscalls')
240 files changed, 5985 insertions, 8077 deletions
diff --git a/testcases/kernel/syscalls/access/access01.c b/testcases/kernel/syscalls/access/access01.c index c9a076dfe..391c8d44b 100644 --- a/testcases/kernel/syscalls/access/access01.c +++ b/testcases/kernel/syscalls/access/access01.c @@ -1,11 +1,16 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. - * AUTHOR : William Roske + * Copyright (c) Linux Test Project, 2003-2023 + * Author: William Roske */ -/* + +/*\ + * [Description] + * * Basic test for access(2) using F_OK, R_OK, W_OK and X_OK */ + #include <errno.h> #include <unistd.h> #include <sys/types.h> diff --git a/testcases/kernel/syscalls/access/access02.c b/testcases/kernel/syscalls/access/access02.c index bf636f9f4..c8fe0d0dc 100644 --- a/testcases/kernel/syscalls/access/access02.c +++ b/testcases/kernel/syscalls/access/access02.c @@ -1,21 +1,19 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) Guangwen Feng <fenggw-fnst@cn.fujitsu.com>, 2016 + * Copyright (c) Linux Test Project, 2002-2023 + * Ported to LTP: Wayne Boyer */ -/* - * Test Description: - * Verify that access() succeeds to check the existence or read/write/execute - * permissions on a file if the mode argument passed was F_OK/R_OK/W_OK/X_OK. +/*\ + * [Description] * - * Also verify that, access() succeeds to test the accessibility of the file - * referred to by symbolic link if the pathname points to a symbolic link. + * Test access(2) syscall * - * As well as verify that, these test files can be - * stat/read/written/executed indeed as root and nobody respectively. - * - * Ported to LTP: Wayne Boyer - * 06/2016 Modified by Guangwen Feng <fenggw-fnst@cn.fujitsu.com> + * - check the existence or read/write/execute permissions on a file (mode argument: F_OK/R_OK/W_OK/X_OK) + * - test the accessibility of the file referred to by symbolic link if the pathname points to a symbolic link + * - file can be stat/read/written/executed as root and nobody */ #include <sys/types.h> diff --git a/testcases/kernel/syscalls/access/access03.c b/testcases/kernel/syscalls/access/access03.c index ae3f676b1..7cae1ec2e 100644 --- a/testcases/kernel/syscalls/access/access03.c +++ b/testcases/kernel/syscalls/access/access03.c @@ -1,9 +1,12 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) Linux Test Project, 2003-2023 */ -/* +/*\ + * [Description] + * * access(2) test for errno(s) EFAULT as root and nobody respectively. */ diff --git a/testcases/kernel/syscalls/access/access04.c b/testcases/kernel/syscalls/access/access04.c index 2d6dd70e8..b5764a5dd 100644 --- a/testcases/kernel/syscalls/access/access04.c +++ b/testcases/kernel/syscalls/access/access04.c @@ -2,26 +2,27 @@ /* * Copyright (c) International Business Machines Corp., 2001 * Copyright (c) 2013 Fujitsu Ltd. + * Copyright (c) Linux Test Project, 2003-2023 + * Ported to LTP: Wayne Boyer + * 11/2013 Ported by Xiaoguang Wang <wangxg.fnst@cn.fujitsu.com> + * 11/2016 Modified by Guangwen Feng <fenggw-fnst@cn.fujitsu.com> */ -/* - * Verify that, - * 1) access() fails with -1 return value and sets errno to EINVAL - * if the specified access mode argument is invalid. - * 2) access() fails with -1 return value and sets errno to ENOENT - * if the specified file doesn't exist (or pathname is NULL). - * 3) access() fails with -1 return value and sets errno to ENAMETOOLONG - * if the pathname size is > PATH_MAX characters. - * 4) access() fails with -1 return value and sets errno to ENOTDIR - * if a component used as a directory in pathname is not a directory. - * 5) access() fails with -1 return value and sets errno to ELOOP - * if too many symbolic links were encountered in resolving pathname. - * 6) access() fails with -1 return value and sets errno to EROFS - * if write permission was requested for files on a read-only file system. +/*\ + * [Description] * - * Ported to LTP: Wayne Boyer - * 11/2013 Ported by Xiaoguang Wang <wangxg.fnst@cn.fujitsu.com> - * 11/2016 Modified by Guangwen Feng <fenggw-fnst@cn.fujitsu.com> + * - access() fails with -1 return value and sets errno to EINVAL + * if the specified access mode argument is invalid. + * - access() fails with -1 return value and sets errno to ENOENT + * if the specified file doesn't exist (or pathname is NULL). + * - access() fails with -1 return value and sets errno to ENAMETOOLONG + * if the pathname size is > PATH_MAX characters. + * - access() fails with -1 return value and sets errno to ENOTDIR + * if a component used as a directory in pathname is not a directory. + * - access() fails with -1 return value and sets errno to ELOOP + * if too many symbolic links were encountered in resolving pathname. + * - access() fails with -1 return value and sets errno to EROFS + * if write permission was requested for files on a read-only file system. */ #include <errno.h> @@ -39,26 +40,32 @@ #define SNAME1 "symlink1" #define SNAME2 "symlink2" #define MNT_POINT "mntpoint" +#define LONGPATHSIZE (PATH_MAX + 2) static uid_t uid; -static char longpathname[PATH_MAX + 2]; +static char *longpathname; +static char *fname1; +static char *fname2; +static char *sname1; +static char *empty_fname; +static char *mnt_point; static struct tcase { - const char *pathname; + char **pathname; int mode; int exp_errno; } tcases[] = { - {FNAME1, -1, EINVAL}, - {"", W_OK, ENOENT}, - {longpathname, R_OK, ENAMETOOLONG}, - {FNAME2, R_OK, ENOTDIR}, - {SNAME1, R_OK, ELOOP}, - {MNT_POINT, W_OK, EROFS} + {&fname1, -1, EINVAL}, + {&empty_fname, W_OK, ENOENT}, + {&longpathname, R_OK, ENAMETOOLONG}, + {&fname2, R_OK, ENOTDIR}, + {&sname1, R_OK, ELOOP}, + {&mnt_point, W_OK, EROFS} }; static void access_test(struct tcase *tc, const char *user) { - TST_EXP_FAIL(access(tc->pathname, tc->mode), tc->exp_errno, + TST_EXP_FAIL(access(*tc->pathname, tc->mode), tc->exp_errno, "access as %s", user); } @@ -86,7 +93,8 @@ static void setup(void) uid = pw->pw_uid; - memset(longpathname, 'a', sizeof(longpathname) - 1); + memset(longpathname, 'a', LONGPATHSIZE - 1); + longpathname[LONGPATHSIZE-1] = 0; SAFE_TOUCH(FNAME1, 0333, NULL); SAFE_TOUCH(DNAME, 0644, NULL); @@ -103,4 +111,13 @@ static struct tst_test test = { .mntpoint = MNT_POINT, .setup = setup, .test = verify_access, + .bufs = (struct tst_buffers []) { + {&fname1, .str = FNAME1}, + {&fname2, .str = FNAME2}, + {&sname1, .str = SNAME1}, + {&empty_fname, .str = ""}, + {&longpathname, .size = LONGPATHSIZE}, + {&mnt_point, .str = MNT_POINT}, + {} + } }; diff --git a/testcases/kernel/syscalls/acct/acct01.c b/testcases/kernel/syscalls/acct/acct01.c index 254d7b503..52c4d41da 100644 --- a/testcases/kernel/syscalls/acct/acct01.c +++ b/testcases/kernel/syscalls/acct/acct01.c @@ -27,17 +27,25 @@ #define DIR_MODE (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP| \ S_IXGRP|S_IROTH|S_IXOTH) #define FILE_EISDIR "." -#define FILE_EACCES "/dev/null" +#define FILE_EACCESS "/dev/null" #define FILE_ENOENT "/tmp/does/not/exist" #define FILE_ENOTDIR "./tmpfile/" -#define TEST_TMPFILE "./tmpfile" -#define TEST_ELOOP "test_file_eloop1" -#define TEST_ENAMETOOLONG nametoolong -#define TEST_EROFS "mntpoint/file" +#define FILE_TMPFILE "./tmpfile" +#define FILE_ELOOP "test_file_eloop1" +#define FILE_EROFS "ro_mntpoint/file" -static char nametoolong[PATH_MAX+2]; static struct passwd *ltpuser; +static char *file_eisdir; +static char *file_eaccess; +static char *file_enoent; +static char *file_enotdir; +static char *file_tmpfile; +static char *file_eloop; +static char *file_enametoolong; +static char *file_erofs; +static char *file_null; + static void setup_euid(void) { SAFE_SETEUID(ltpuser->pw_uid); @@ -49,21 +57,21 @@ static void cleanup_euid(void) } static struct test_case { - char *filename; - char *exp_errval; + char **filename; + char *desc; int exp_errno; void (*setupfunc) (); void (*cleanfunc) (); } tcases[] = { - {FILE_EISDIR, "EISDIR", EISDIR, NULL, NULL}, - {FILE_EACCES, "EACCES", EACCES, NULL, NULL}, - {FILE_ENOENT, "ENOENT", ENOENT, NULL, NULL}, - {FILE_ENOTDIR, "ENOTDIR", ENOTDIR, NULL, NULL}, - {TEST_TMPFILE, "EPERM", EPERM, setup_euid, cleanup_euid}, - {NULL, "EPERM", EPERM, setup_euid, cleanup_euid}, - {TEST_ELOOP, "ELOOP", ELOOP, NULL, NULL}, - {TEST_ENAMETOOLONG, "ENAMETOOLONG", ENAMETOOLONG, NULL, NULL}, - {TEST_EROFS, "EROFS", EROFS, NULL, NULL}, + {&file_eisdir, FILE_EISDIR, EISDIR, NULL, NULL}, + {&file_eaccess, FILE_EACCESS, EACCES, NULL, NULL}, + {&file_enoent, FILE_ENOENT, ENOENT, NULL, NULL}, + {&file_enotdir, FILE_ENOTDIR, ENOTDIR, NULL, NULL}, + {&file_tmpfile, FILE_TMPFILE, EPERM, setup_euid, cleanup_euid}, + {&file_null, "NULL", EPERM, setup_euid, cleanup_euid}, + {&file_eloop, FILE_ELOOP, ELOOP, NULL, NULL}, + {&file_enametoolong, "aaaa...", ENAMETOOLONG, NULL, NULL}, + {&file_erofs, FILE_EROFS, EROFS, NULL, NULL}, }; static void setup(void) @@ -76,10 +84,10 @@ static void setup(void) ltpuser = SAFE_GETPWNAM("nobody"); - fd = SAFE_CREAT(TEST_TMPFILE, 0777); + fd = SAFE_CREAT(FILE_TMPFILE, 0777); SAFE_CLOSE(fd); - TEST(acct(TEST_TMPFILE)); + TEST(acct(FILE_TMPFILE)); if (TST_RET == -1) tst_brk(TBROK | TTERRNO, "acct failed unexpectedly"); @@ -89,11 +97,11 @@ static void setup(void) tst_brk(TBROK | TTERRNO, "acct(NULL) failed"); /* ELOOP SETTING */ - SAFE_SYMLINK(TEST_ELOOP, "test_file_eloop2"); - SAFE_SYMLINK("test_file_eloop2", TEST_ELOOP); + SAFE_SYMLINK(FILE_ELOOP, "test_file_eloop2"); + SAFE_SYMLINK("test_file_eloop2", FILE_ELOOP); - /* ENAMETOOLONG SETTING */ - memset(nametoolong, 'a', PATH_MAX+1); + memset(file_enametoolong, 'a', PATH_MAX+1); + file_enametoolong[PATH_MAX+1] = 0; } static void verify_acct(unsigned int nr) @@ -103,31 +111,29 @@ static void verify_acct(unsigned int nr) if (tcase->setupfunc) tcase->setupfunc(); - TEST(acct(tcase->filename)); + TST_EXP_FAIL(acct(*tcase->filename), tcase->exp_errno, + "acct(%s)", tcase->desc); if (tcase->cleanfunc) tcase->cleanfunc(); - - if (TST_RET != -1) { - tst_res(TFAIL, "acct(%s) succeeded unexpectedly", - tcase->filename); - return; - } - - if (TST_ERR == tcase->exp_errno) { - tst_res(TPASS | TTERRNO, "acct() failed as expected"); - } else { - tst_res(TFAIL | TTERRNO, - "acct() failed, expected: %s", - tst_strerrno(tcase->exp_errno)); - } } static struct tst_test test = { .needs_root = 1, - .mntpoint = "mntpoint", + .mntpoint = "ro_mntpoint", .needs_rofs = 1, .tcnt = ARRAY_SIZE(tcases), .setup = setup, .test = verify_acct, + .bufs = (struct tst_buffers []) { + {&file_eisdir, .str = FILE_EISDIR}, + {&file_eaccess, .str = FILE_EACCESS}, + {&file_enoent, .str = FILE_ENOENT}, + {&file_enotdir, .str = FILE_ENOTDIR}, + {&file_tmpfile, .str = FILE_TMPFILE}, + {&file_eloop, .str = FILE_ELOOP}, + {&file_enametoolong, .size = PATH_MAX+2}, + {&file_erofs, .str = FILE_EROFS}, + {} + } }; diff --git a/testcases/kernel/syscalls/adjtimex/adjtimex02.c b/testcases/kernel/syscalls/adjtimex/adjtimex02.c index dab640ff3..e66ba2a5c 100644 --- a/testcases/kernel/syscalls/adjtimex/adjtimex02.c +++ b/testcases/kernel/syscalls/adjtimex/adjtimex02.c @@ -14,11 +14,6 @@ * - EFAULT with SET_MODE and invalid timex pointer * - EINVAL with ADJ_TICK greater than max tick * - EINVAL with ADJ_TICK smaller than min tick - * - * On kernels older than 2.6.26: - * - * - EINVAL with AJD_OFFSET smaller than min offset - * - EINVAL with AJD_OFFSET greater than max offset */ #include <errno.h> @@ -57,8 +52,6 @@ static struct test_case { {.modes = SET_MODE, .exp_err = EFAULT}, {.modes = ADJ_TICK, .lowlimit = 900000, .delta = 1, .exp_err = EINVAL}, {.modes = ADJ_TICK, .highlimit = 1100000, .delta = 1, .exp_err = EINVAL}, - {.modes = ADJ_OFFSET, .highlimit = 512000L, .delta = 1, .exp_err = EINVAL}, - {.modes = ADJ_OFFSET, .lowlimit = -512000L, .delta = -1, .exp_err = EINVAL}, }; static struct test_variants @@ -93,12 +86,6 @@ static void verify_adjtimex(unsigned int i) if (tc[i].highlimit) buf->tick = tc[i].highlimit + tc[i].delta; } - if (tc[i].modes == ADJ_OFFSET) { - if (tc[i].lowlimit || tc[i].highlimit) { - tst_res(TCONF, "Newer kernels normalize offset value outside range"); - return; - } - } } if (tc[i].exp_err == EFAULT) { diff --git a/testcases/kernel/syscalls/adjtimex/adjtimex03.c b/testcases/kernel/syscalls/adjtimex/adjtimex03.c index 333cabf11..7056973cc 100644 --- a/testcases/kernel/syscalls/adjtimex/adjtimex03.c +++ b/testcases/kernel/syscalls/adjtimex/adjtimex03.c @@ -1,14 +1,16 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) Zilogic Systems Pvt. Ltd, 2020. All Rights Reserved. - * Email: <code@zilogic.com> + * Copyright (c) Zilogic Systems Pvt. Ltd <code@zilogic.com>, 2020 + * Copyright (c) Linux Test Project, 2021-2023 * * Based on testcases/kernel/syscalls/adjtimex/adjtimex01.c * Copyright (c) Wipro Technologies Ltd, 2002. + */ + +/*\ + * [Description] * - * CVE-2018-11508 - * - * Test 4-byte kernel data leak via adjtimex + * CVE-2018-11508: Test 4-byte kernel data leak via adjtimex. * * On calling the adjtimex() function call with invalid mode (let's say * 0x8000), ideally all the parameters should return with null data. But, @@ -64,6 +66,7 @@ void verify_adjtimex(void) break; } } + if (data_leak != 0) tst_res(TFAIL, "Data leak observed"); else diff --git a/testcases/kernel/syscalls/alarm/alarm02.c b/testcases/kernel/syscalls/alarm/alarm02.c index b2fde03c8..fcf70c5f3 100644 --- a/testcases/kernel/syscalls/alarm/alarm02.c +++ b/testcases/kernel/syscalls/alarm/alarm02.c @@ -9,6 +9,7 @@ * [Description] * * Verify that alarm() returns: + * * - zero when there was no previously scheduled alarm * - number of seconds remaining until any previously scheduled alarm */ diff --git a/testcases/kernel/syscalls/bind/bind03.c b/testcases/kernel/syscalls/bind/bind03.c index 37a040b29..8c95cd799 100644 --- a/testcases/kernel/syscalls/bind/bind03.c +++ b/testcases/kernel/syscalls/bind/bind03.c @@ -43,8 +43,12 @@ static void run(void) * locks the socket and does all the checks and the node is not removed * in the error path. For now we will unlink the node here so that the * test works fine when the run() function is executed in a loop. + * From v5.14-rc1 the kernel has fix above issue. */ - unlink(SNAME_B); + if (tst_kvercmp(5, 14, 0) >= 0) + TST_EXP_FAIL(unlink(SNAME_B), ENOENT, "check exist of SNAME_B"); + else + unlink(SNAME_B); } static void setup(void) diff --git a/testcases/kernel/syscalls/bpf/bpf_common.h b/testcases/kernel/syscalls/bpf/bpf_common.h index 39764ba1f..a0800d19b 100644 --- a/testcases/kernel/syscalls/bpf/bpf_common.h +++ b/testcases/kernel/syscalls/bpf/bpf_common.h @@ -13,6 +13,7 @@ #include "lapi/socket.h" #define BPF_MEMLOCK_ADD (2*1024*1024) +#define BUFSIZE 8192 /* map[array_indx] = reg_to_save * diff --git a/testcases/kernel/syscalls/bpf/bpf_prog01.c b/testcases/kernel/syscalls/bpf/bpf_prog01.c index e2fc80a9f..de4f68cef 100644 --- a/testcases/kernel/syscalls/bpf/bpf_prog01.c +++ b/testcases/kernel/syscalls/bpf/bpf_prog01.c @@ -63,7 +63,7 @@ int load_prog(int fd) BPF_EXIT_INSN(), /* return r0 */ }; - bpf_init_prog_attr(attr, PROG, sizeof(PROG), log, BUFSIZ); + bpf_init_prog_attr(attr, PROG, sizeof(PROG), log, BUFSIZE); return bpf_load_prog(attr, log); } diff --git a/testcases/kernel/syscalls/bpf/bpf_prog02.c b/testcases/kernel/syscalls/bpf/bpf_prog02.c index b40ea0f1d..fd3e535c1 100644 --- a/testcases/kernel/syscalls/bpf/bpf_prog02.c +++ b/testcases/kernel/syscalls/bpf/bpf_prog02.c @@ -64,7 +64,7 @@ static int load_prog(int fd) BPF_EXIT_INSN(), /* 26: return r0 */ }; - bpf_init_prog_attr(attr, insn, sizeof(insn), log, BUFSIZ); + bpf_init_prog_attr(attr, insn, sizeof(insn), log, BUFSIZE); return bpf_load_prog(attr, log); } @@ -117,7 +117,7 @@ static struct tst_test test = { .bufs = (struct tst_buffers []) { {&key, .size = sizeof(*key)}, {&val, .size = sizeof(*val)}, - {&log, .size = BUFSIZ}, + {&log, .size = BUFSIZE}, {&attr, .size = sizeof(*attr)}, {&msg, .size = sizeof(MSG)}, {}, diff --git a/testcases/kernel/syscalls/bpf/bpf_prog04.c b/testcases/kernel/syscalls/bpf/bpf_prog04.c index ebee26cbc..cf3bb1254 100644 --- a/testcases/kernel/syscalls/bpf/bpf_prog04.c +++ b/testcases/kernel/syscalls/bpf/bpf_prog04.c @@ -28,7 +28,6 @@ #include "tst_capability.h" #include "bpf_common.h" -#define BUFSIZE 8192 #define CHECK_BPF_RET(x) ((x) >= 0 || ((x) == -1 && errno != EACCES)) static const char MSG[] = "Ahoj!"; diff --git a/testcases/kernel/syscalls/bpf/bpf_prog05.c b/testcases/kernel/syscalls/bpf/bpf_prog05.c index 2be5a2cc9..742beab0b 100644 --- a/testcases/kernel/syscalls/bpf/bpf_prog05.c +++ b/testcases/kernel/syscalls/bpf/bpf_prog05.c @@ -52,8 +52,6 @@ #include "tst_capability.h" #include "bpf_common.h" -#define BUFSIZE 8192 - static const char MSG[] = "Ahoj!"; static char *msg; diff --git a/testcases/kernel/syscalls/bpf/bpf_prog06.c b/testcases/kernel/syscalls/bpf/bpf_prog06.c index c38dd8239..cee9616cf 100644 --- a/testcases/kernel/syscalls/bpf/bpf_prog06.c +++ b/testcases/kernel/syscalls/bpf/bpf_prog06.c @@ -46,8 +46,6 @@ #include "lapi/bpf.h" #include "bpf_common.h" -#define BUFSIZE 8192 - static const char MSG[] = "Ahoj!"; static char *msg; diff --git a/testcases/kernel/syscalls/bpf/bpf_prog07.c b/testcases/kernel/syscalls/bpf/bpf_prog07.c index 50ff6eed0..dab5bb8ad 100644 --- a/testcases/kernel/syscalls/bpf/bpf_prog07.c +++ b/testcases/kernel/syscalls/bpf/bpf_prog07.c @@ -46,8 +46,6 @@ #include "lapi/bpf.h" #include "bpf_common.h" -#define BUFSIZE 8192 - static const char MSG[] = "Ahoj!"; static char *msg; diff --git a/testcases/kernel/syscalls/capset/capset01.c b/testcases/kernel/syscalls/capset/capset01.c index a323fc5be..25db8112c 100644 --- a/testcases/kernel/syscalls/capset/capset01.c +++ b/testcases/kernel/syscalls/capset/capset01.c @@ -1,12 +1,20 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved. - * AUTHOR : Saji Kumar.V.R <saji.kumar@wipro.com> + * Author: Saji Kumar.V.R <saji.kumar@wipro.com> * - * CHANGES: - * 2005/01/01: add an hint to a possible solution when test fails - * - Ricky Ng-Adam <rngadam@yahoo.com> + * 2005/01/01: add an hint to a possible solution when test fails + * Ricky Ng-Adam <rngadam@yahoo.com> + * + * Copyright (c) Linux Test Project, 2003-2023 */ + +/*\ + * [Description] + * + * Test capset() with with LINUX_CAPABILITY_VERSION_{1,2,3}. + */ + #include <sys/types.h> #include <unistd.h> #include "tst_test.h" diff --git a/testcases/kernel/syscalls/capset/capset02.c b/testcases/kernel/syscalls/capset/capset02.c index 5173be09b..989f3e4ce 100644 --- a/testcases/kernel/syscalls/capset/capset02.c +++ b/testcases/kernel/syscalls/capset/capset02.c @@ -2,21 +2,27 @@ /* * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved. * Author: Saji Kumar.V.R <saji.kumar@wipro.com> - * + * Copyright (c) Linux Test Project, 2003-2023 + */ + +/*\ + * [Description] * Tests basic error handling of the capset syscall. - * 1) capset() fails with errno set to EFAULT if an invalid address + * + * 1. capset() fails with errno set to EFAULT if an invalid address * is given for header. - * 2) capset() fails with errno set to EFAULT if an invalid address + * 2. capset() fails with errno set to EFAULT if an invalid address * is given for data. - * 3) capset() fails with errno set to EINVAL if an invalid value + * 3. capset() fails with errno set to EINVAL if an invalid value * is given for header->version. - * 4) capset() fails with errno set to EPERM if the new_Effective is + * 4. capset() fails with errno set to EPERM if the new_Effective is * not a subset of the new_Permitted. - * 5) capset() fails with errno set to EPERM if the new_Permitted is + * 5. capset() fails with errno set to EPERM if the new_Permitted is * not a subset of the old_Permitted. - * 6) capset() fails with errno set ot EPERM if the new_Inheritable is + * 6. capset() fails with errno set ot EPERM if the new_Inheritable is * not a subset of the old_Inheritable and bounding set. */ + #include <stdlib.h> #include <sys/types.h> #include <unistd.h> diff --git a/testcases/kernel/syscalls/capset/capset03.c b/testcases/kernel/syscalls/capset/capset03.c index 074ab1f50..2b83e6ce9 100644 --- a/testcases/kernel/syscalls/capset/capset03.c +++ b/testcases/kernel/syscalls/capset/capset03.c @@ -1,11 +1,17 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) 2019 FUJITSU LIMITED. All rights reserved. - * Author: Yang Xu <xuyang2018.jy@cn.fujitsu.com + * Copyright (c) 2020 FUJITSU LIMITED. All rights reserved. + * Copyright (c) Linux Test Project, 2020-2023 + * Author: Yang Xu <xuyang2018.jy@cn.fujitsu.com> + */ + +/*\ + * [Description] * * capset() fails with errno set or EPERM if the new_Inheritable is * not a subset of old_Inheritable and old_Permitted without CAP_SETPCAP. */ + #include <stdlib.h> #include <sys/types.h> #include <unistd.h> diff --git a/testcases/kernel/syscalls/capset/capset04.c b/testcases/kernel/syscalls/capset/capset04.c index f929be555..13477a4a9 100644 --- a/testcases/kernel/syscalls/capset/capset04.c +++ b/testcases/kernel/syscalls/capset/capset04.c @@ -1,12 +1,18 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved. + * Copyright (c) Linux Test Project, 2020-2023 * Author: Saji Kumar.V.R <saji.kumar@wipro.com> + */ + +/*\ + * [Description] * - * Tests whether we can use capset() to modify the capabilities of a thread + * Test whether capset() can be used to modify the capabilities of a thread * other than itself. Now, most linux distributions with kernel supporting * VFS capabilities, this should be never permitted. */ + #include <stdlib.h> #include <sys/types.h> #include <unistd.h> diff --git a/testcases/kernel/syscalls/chdir/chdir01.c b/testcases/kernel/syscalls/chdir/chdir01.c index e4080e3f4..d50a8f50c 100644 --- a/testcases/kernel/syscalls/chdir/chdir01.c +++ b/testcases/kernel/syscalls/chdir/chdir01.c @@ -31,18 +31,27 @@ static char *workdir; static int skip_symlinks, skip_blocked; static struct passwd *ltpuser; +static char *file_name; +static char *blocked_name; +static char *dir_name; +static char *cwd_name; +static char *parent_name; +static char *root_name; +static char *missing_name; +static char *link_name; + static struct test_case { - const char *name; + char **name; int root_ret, root_err, nobody_ret, nobody_err; } testcase_list[] = { - {FILE_NAME, -1, ENOTDIR, -1, ENOTDIR}, - {BLOCKED_NAME, 0, 0, -1, EACCES}, - {DIR_NAME, 0, 0, 0, 0}, - {".", 0, 0, 0, 0}, - {"..", 0, 0, 0, 0}, - {"/", 0, 0, 0, 0}, - {"missing", -1, ENOENT, -1, ENOENT}, - {LINK_NAME1, -1, ELOOP, -1, ELOOP}, + {&file_name, -1, ENOTDIR, -1, ENOTDIR}, + {&blocked_name, 0, 0, -1, EACCES}, + {&dir_name, 0, 0, 0, 0}, + {&cwd_name, 0, 0, 0, 0}, + {&parent_name, 0, 0, 0, 0}, + {&root_name, 0, 0, 0, 0}, + {&missing_name, -1, ENOENT, -1, ENOENT}, + {&link_name, -1, ELOOP, -1, ELOOP}, }; static void setup(void) @@ -53,8 +62,6 @@ static void setup(void) umask(0); - SAFE_MOUNT(tst_device->dev, MNTPOINT, tst_device->fs_type, 0, NULL); - cwd = SAFE_GETCWD(NULL, 0); workdir = SAFE_MALLOC(strlen(cwd) + strlen(MNTPOINT) + 2); sprintf(workdir, "%s/%s", cwd, MNTPOINT); @@ -109,7 +116,7 @@ static void run(unsigned int n) { struct test_case *tc = testcase_list + n; - tst_res(TINFO, "Testing '%s'", tc->name); + tst_res(TINFO, "Testing '%s'", *tc->name); if (tc->root_err == ELOOP && skip_symlinks) { tst_res(TCONF, "Skipping symlink loop test, not supported"); @@ -119,8 +126,8 @@ static void run(unsigned int n) /* Reset current directory to mountpoint */ SAFE_CHDIR(workdir); - TEST(chdir(tc->name)); - check_result("root", tc->name, tc->root_ret, tc->root_err); + TEST(chdir(*tc->name)); + check_result("root", *tc->name, tc->root_ret, tc->root_err); if (tc->nobody_err == EACCES && skip_blocked) { tst_res(TCONF, "Skipping unprivileged permission test, " @@ -130,25 +137,35 @@ static void run(unsigned int n) SAFE_CHDIR(workdir); SAFE_SETEUID(ltpuser->pw_uid); - TEST(chdir(tc->name)); + TEST(chdir(*tc->name)); SAFE_SETEUID(0); - check_result(TESTUSER, tc->name, tc->nobody_ret, tc->nobody_err); + check_result(TESTUSER, *tc->name, tc->nobody_ret, tc->nobody_err); } static void cleanup(void) { SAFE_CHDIR(".."); - tst_umount(workdir); free(workdir); } static struct tst_test test = { .needs_root = 1, - .format_device = 1, + .mount_device = 1, .mntpoint = MNTPOINT, .all_filesystems = 1, .test = run, .tcnt = ARRAY_SIZE(testcase_list), .setup = setup, - .cleanup = cleanup + .cleanup = cleanup, + .bufs = (struct tst_buffers []) { + {&file_name, .str = FILE_NAME}, + {&blocked_name, .str = BLOCKED_NAME}, + {&dir_name, .str = DIR_NAME}, + {&cwd_name, .str = "."}, + {&parent_name, .str = ".."}, + {&root_name, .str = "/"}, + {&missing_name, .str = "does_not_exist"}, + {&link_name, .str = LINK_NAME1}, + {} + } }; diff --git a/testcases/kernel/syscalls/chmod/chmod01.c b/testcases/kernel/syscalls/chmod/chmod01.c index 9f5ec4c67..b3b828ac3 100644 --- a/testcases/kernel/syscalls/chmod/chmod01.c +++ b/testcases/kernel/syscalls/chmod/chmod01.c @@ -19,13 +19,16 @@ static int modes[] = {0, 07, 070, 0700, 0777, 02777, 04777, 06777}; +static char *test_dir; +static char *test_file; + static struct variant { - char *name; + char **name; unsigned int mode_mask; char *desc; } variants[] = { - {TESTFILE, S_IFREG, "verify permissions of file"}, - {TESTDIR, S_IFDIR, "verify permissions of directory"}, + {&test_file, S_IFREG, "verify permissions of file"}, + {&test_dir, S_IFDIR, "verify permissions of directory"}, }; static void verify_chmod(unsigned int n) @@ -34,21 +37,21 @@ static void verify_chmod(unsigned int n) int mode = modes[n]; struct variant *tc = &variants[tst_variant]; - TST_EXP_PASS(chmod(tc->name, mode), "chmod(%s, %04o)", - tc->name, mode); + TST_EXP_PASS(chmod(*tc->name, mode), "chmod(%s, %04o)", + *tc->name, mode); if (!TST_PASS) return; - SAFE_STAT(tc->name, &stat_buf); + SAFE_STAT(*tc->name, &stat_buf); stat_buf.st_mode &= ~tc->mode_mask; if (stat_buf.st_mode == (unsigned int)mode) { tst_res(TPASS, "stat(%s) mode=%04o", - tc->name, stat_buf.st_mode); + *tc->name, stat_buf.st_mode); } else { tst_res(TFAIL, "stat(%s) mode=%04o", - tc->name, stat_buf.st_mode); + *tc->name, stat_buf.st_mode); } } @@ -57,9 +60,9 @@ static void setup(void) tst_res(TINFO, "Testing variant: %s", variants[tst_variant].desc); if (tst_variant) - SAFE_MKDIR(variants[tst_variant].name, MODE); + SAFE_MKDIR(*variants[tst_variant].name, MODE); else - SAFE_TOUCH(variants[tst_variant].name, MODE, NULL); + SAFE_TOUCH(*variants[tst_variant].name, MODE, NULL); } static struct tst_test test = { @@ -68,4 +71,9 @@ static struct tst_test test = { .tcnt = ARRAY_SIZE(modes), .test = verify_chmod, .needs_tmpdir = 1, + .bufs = (struct tst_buffers []) { + {&test_file, .str = TESTFILE}, + {&test_dir, .str = TESTDIR}, + {} + } }; diff --git a/testcases/kernel/syscalls/chown/chown02.c b/testcases/kernel/syscalls/chown/chown02.c index 7c96832a4..467185831 100644 --- a/testcases/kernel/syscalls/chown/chown02.c +++ b/testcases/kernel/syscalls/chown/chown02.c @@ -9,6 +9,7 @@ * [Description] * * Verify that chown(2) invoked by super-user: + * * - clears setuid and setgid bits set on an executable file * - preserves setgid bit set on a non-group-executable file */ diff --git a/testcases/kernel/syscalls/chroot/chroot03.c b/testcases/kernel/syscalls/chroot/chroot03.c index ba8c1e9ac..87faec316 100644 --- a/testcases/kernel/syscalls/chroot/chroot03.c +++ b/testcases/kernel/syscalls/chroot/chroot03.c @@ -25,41 +25,42 @@ #include <stdio.h> #include "tst_test.h" -static char fname[255]; -static char nonexistent_dir[100] = "testdir"; -static char bad_dir[] = "abcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyz"; -static char symbolic_dir[] = "sym_dir1"; +#define FILE_NAME "test_file" +#define LOOP_DIR "sym_dir1" +#define NONEXISTENT_DIR "does_not_exist" + +static char *longname_dir; +static char *file_name; +static char *nonexistent_dir; +static char *bad_ptr; +static char *loop_dir; static struct tcase { - char *dir; + char **dir; int error; char *desc; } tcases[] = { - {bad_dir, ENAMETOOLONG, "chroot(longer than VFS_MAXNAMELEN)"}, - {fname, ENOTDIR, "chroot(not a directory)"}, - {nonexistent_dir, ENOENT, "chroot(does not exists)"}, - {(char *)-1, EFAULT, "chroot(an invalid address)"}, - {symbolic_dir, ELOOP, "chroot(symlink loop)"} + {&longname_dir, ENAMETOOLONG, "chroot(longer than VFS_MAXNAMELEN)"}, + {&file_name, ENOTDIR, "chroot(not a directory)"}, + {&nonexistent_dir, ENOENT, "chroot(does not exists)"}, + {&bad_ptr, EFAULT, "chroot(an invalid address)"}, + {&loop_dir, ELOOP, "chroot(symlink loop)"} }; static void verify_chroot(unsigned int n) { struct tcase *tc = &tcases[n]; - TST_EXP_FAIL(chroot(tc->dir), tc->error, "%s", tc->desc); + TST_EXP_FAIL(chroot(*tc->dir), tc->error, "%s", tc->desc); } static void setup(void) { - unsigned int i; - - (void)sprintf(fname, "tfile_%d", getpid()); - SAFE_TOUCH(fname, 0666, NULL); + SAFE_TOUCH(FILE_NAME, 0666, NULL); + bad_ptr = tst_get_bad_addr(NULL); - for (i = 0; i < ARRAY_SIZE(tcases); i++) { - if (tcases[i].error == EFAULT) - tcases[3].dir = tst_get_bad_addr(NULL); - } + memset(longname_dir, 'a', PATH_MAX + 1); + longname_dir[PATH_MAX+1] = 0; SAFE_SYMLINK("sym_dir1/", "sym_dir2"); SAFE_SYMLINK("sym_dir2/", "sym_dir1"); @@ -70,4 +71,11 @@ static struct tst_test test = { .tcnt = ARRAY_SIZE(tcases), .test = verify_chroot, .needs_tmpdir = 1, + .bufs = (struct tst_buffers []) { + {&file_name, .str = FILE_NAME}, + {&nonexistent_dir, .str = NONEXISTENT_DIR}, + {&loop_dir, .str = LOOP_DIR}, + {&longname_dir, .size = PATH_MAX+2}, + {} + } }; diff --git a/testcases/kernel/syscalls/clone/clone04.c b/testcases/kernel/syscalls/clone/clone04.c index 7af4fedd3..74347e2b4 100644 --- a/testcases/kernel/syscalls/clone/clone04.c +++ b/testcases/kernel/syscalls/clone/clone04.c @@ -2,6 +2,7 @@ /* * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved. * Copyright (c) 2012 Wanlong Gao <gaowanlong@cn.fujitsu.com> + * Copyright (c) Linux Test Project, 2003-2023 */ /*\ @@ -44,4 +45,8 @@ static void verify_clone(unsigned int nr) static struct tst_test test = { .tcnt = ARRAY_SIZE(tcases), .test = verify_clone, + .tags = (const struct tst_tag[]) { + {"musl-git", "fa4a8abd06a4"}, + {} + }, }; diff --git a/testcases/kernel/syscalls/clone3/.gitignore b/testcases/kernel/syscalls/clone3/.gitignore index 604cb903e..10369954b 100644 --- a/testcases/kernel/syscalls/clone3/.gitignore +++ b/testcases/kernel/syscalls/clone3/.gitignore @@ -1,2 +1,3 @@ clone301 clone302 +clone303 diff --git a/testcases/kernel/syscalls/clone3/clone302.c b/testcases/kernel/syscalls/clone3/clone302.c index b1b4ccebb..48b831554 100644 --- a/testcases/kernel/syscalls/clone3/clone302.c +++ b/testcases/kernel/syscalls/clone3/clone302.c @@ -12,6 +12,7 @@ #define _GNU_SOURCE #include <stdlib.h> +#include <assert.h> #include "tst_test.h" #include "lapi/sched.h" @@ -34,7 +35,7 @@ static struct tcase { } tcases[] = { {"invalid args", &invalid_args, sizeof(*valid_args), 0, NULL, SIGCHLD, 0, 0, 0, EFAULT}, {"zero size", &valid_args, 0, 0, NULL, SIGCHLD, 0, 0, 0, EINVAL}, - {"short size", &valid_args, sizeof(*valid_args) - 1, 0, NULL, SIGCHLD, 0, 0, 0, EINVAL}, + {"short size", &valid_args, sizeof(struct clone_args_minimal) - 1, 0, NULL, SIGCHLD, 0, 0, 0, EINVAL}, {"extra size", &valid_args, sizeof(*valid_args) + 1, 0, NULL, SIGCHLD, 0, 0, 0, EFAULT}, {"sighand-no-VM", &valid_args, sizeof(*valid_args), CLONE_SIGHAND, NULL, SIGCHLD, 0, 0, 0, EINVAL}, {"thread-no-sighand", &valid_args, sizeof(*valid_args), CLONE_THREAD, NULL, SIGCHLD, 0, 0, 0, EINVAL}, @@ -59,6 +60,8 @@ static void setup(void) { clone3_supported_by_kernel(); + TST_EXP_EQ_SZ(sizeof(struct clone_args_minimal), 64); + void *p = tst_get_bad_addr(NULL); invalid_args = p; diff --git a/testcases/kernel/syscalls/clone3/clone303.c b/testcases/kernel/syscalls/clone3/clone303.c new file mode 100644 index 000000000..04c41942a --- /dev/null +++ b/testcases/kernel/syscalls/clone3/clone303.c @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 SUSE LLC <wegao@suse.com> + */ + +/*\ + * [Description] + * + * This test case check clone3 CLONE_INTO_CGROUP flag + * + */ + +#define _GNU_SOURCE +#include <stdio.h> +#include <stdlib.h> +#include <sys/wait.h> + +#include "tst_test.h" +#include "lapi/sched.h" +#include "lapi/pidfd.h" + +#define BUF_LEN 20 + +static struct tst_cg_group *cg_child_test_simple; +static int fd; +static struct tst_clone_args *args; + +static pid_t clone_into_cgroup(int cgroup_fd) +{ + + args->flags = CLONE_INTO_CGROUP; + args->exit_signal = SIGCHLD; + args->cgroup = cgroup_fd; + + return tst_clone(args); +} + +static void run(void) +{ + pid_t pid; + + pid = clone_into_cgroup(fd); + + if (!pid) { + TST_CHECKPOINT_WAIT(0); + return; + } + + char buf[BUF_LEN]; + + SAFE_CG_READ(cg_child_test_simple, "cgroup.procs", buf, BUF_LEN); + + if (atoi(buf) == pid) + tst_res(TPASS, "clone3 case pass!"); + else + tst_brk(TFAIL | TTERRNO, "clone3() failed !"); + + TST_CHECKPOINT_WAKE(0); + + SAFE_WAITPID(pid, NULL, 0); + +} + +static void setup(void) +{ + clone3_supported_by_kernel(); + + cg_child_test_simple = tst_cg_group_mk(tst_cg, "cg_test_simple"); + + fd = tst_cg_group_unified_dir_fd(cg_child_test_simple); + + if (fd < 0) + tst_brk(TBROK, "get dir fd failed!"); +} + +static void cleanup(void) +{ + cg_child_test_simple = tst_cg_group_rm(cg_child_test_simple); +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .forks_child = 1, + .needs_cgroup_ctrls = (const char *const []){ "base", NULL }, + .needs_cgroup_ver = TST_CG_V2, + .needs_checkpoints = 1, + .min_kver = "5.7", + .bufs = (struct tst_buffers []) { + {&args, .size = sizeof(*args)}, + {}, + } +}; diff --git a/testcases/kernel/syscalls/delete_module/delete_module01.c b/testcases/kernel/syscalls/delete_module/delete_module01.c index 476551233..90d8b5289 100644 --- a/testcases/kernel/syscalls/delete_module/delete_module01.c +++ b/testcases/kernel/syscalls/delete_module/delete_module01.c @@ -2,38 +2,39 @@ /* * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved. * Copyright (c) 2018 Xiao Yang <yangx.jy@cn.fujitsu.com> + * Copyright (c) Linux Test Project, 2002-2023 + * Author: Madhu T L <madhu.tarikere@wipro.com> */ -/* - * AUTHOR: Madhu T L <madhu.tarikere@wipro.com> +/*\ + * [Description] + * + * Basic test for delete_module(2). * - * DESCRIPTION: - * Basic tests for delete_module(2) - * 1) insmod dummy_del_mod.ko - * 2) call delete_module(2) to remove dummy_del_mod.ko + * Install dummy_del_mod.ko and delete it with delete_module(2). */ -#include <errno.h> #include "tst_test.h" #include "tst_module.h" #include "lapi/syscalls.h" #define MODULE_NAME "dummy_del_mod" -#define MODULE_NAME_KO "dummy_del_mod.ko" +#define MODULE_NAME_KO MODULE_NAME ".ko" static int module_loaded; static void do_delete_module(void) { - if (module_loaded == 0) { + if (!module_loaded) { tst_module_load(MODULE_NAME_KO, NULL); module_loaded = 1; } TEST(tst_syscall(__NR_delete_module, MODULE_NAME, 0)); if (TST_RET == -1) { - tst_res(TFAIL | TTERRNO, "delete_module() failed to " - "remove module entry for %s ", MODULE_NAME); + tst_res(TFAIL | TTERRNO, + "delete_module() failed to remove module entry for %s", + MODULE_NAME); return; } @@ -43,14 +44,15 @@ static void do_delete_module(void) static void cleanup(void) { - if (module_loaded == 1) + if (module_loaded) tst_module_unload(MODULE_NAME_KO); } static struct tst_test test = { .needs_root = 1, - /* lockdown requires signed modules */ + /* lockdown and SecureBoot requires signed modules */ .skip_in_lockdown = 1, + .skip_in_secureboot = 1, .cleanup = cleanup, .test_all = do_delete_module, }; diff --git a/testcases/kernel/syscalls/delete_module/delete_module03.c b/testcases/kernel/syscalls/delete_module/delete_module03.c index 863d36188..7e92fc2af 100644 --- a/testcases/kernel/syscalls/delete_module/delete_module03.c +++ b/testcases/kernel/syscalls/delete_module/delete_module03.c @@ -72,8 +72,9 @@ static void cleanup(void) static struct tst_test test = { .needs_root = 1, - /* lockdown requires signed modules */ + /* lockdown and SecureBoot requires signed modules */ .skip_in_lockdown = 1, + .skip_in_secureboot = 1, .setup = setup, .cleanup = cleanup, .test_all = do_delete_module, diff --git a/testcases/kernel/syscalls/dup/dup01.c b/testcases/kernel/syscalls/dup/dup01.c index 74e24cc02..f5cd058e8 100644 --- a/testcases/kernel/syscalls/dup/dup01.c +++ b/testcases/kernel/syscalls/dup/dup01.c @@ -7,27 +7,32 @@ * */ +/*\ + * [Description] + * + * Verify that dup(2) syscall executes successfully and allocates + * a new file descriptor which refers to the same open file as oldfd. + */ + #include "tst_test.h" static int fd; +static struct stat buf1, buf2; static void verify_dup(void) { - TEST(dup(fd)); - - if (TST_RET < -1) { - tst_res(TFAIL, "Invalid dup() return value %ld", TST_RET); - } else if (TST_RET == -1) { - tst_res(TFAIL | TTERRNO, "dup(%d) Failed", fd); - } else { - tst_res(TPASS, "dup(%d) returned %ld", fd, TST_RET); - SAFE_CLOSE(TST_RET); - } + TST_EXP_FD(dup(fd)); + + SAFE_FSTAT(TST_RET, &buf2); + TST_EXP_EQ_LU(buf1.st_ino, buf2.st_ino); + + SAFE_CLOSE(TST_RET); } static void setup(void) { fd = SAFE_OPEN("dupfile", O_RDWR | O_CREAT, 0700); + SAFE_FSTAT(fd, &buf1); } static void cleanup(void) diff --git a/testcases/kernel/syscalls/dup/dup02.c b/testcases/kernel/syscalls/dup/dup02.c index 528bcdbc1..5391738a4 100644 --- a/testcases/kernel/syscalls/dup/dup02.c +++ b/testcases/kernel/syscalls/dup/dup02.c @@ -2,24 +2,21 @@ /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. * Copyright (c) 2020 SUSE LLC - * * 03/30/1992 AUTHOR: Richard Logan CO-PILOT: William Roske - * */ + /*\ * [Description] - * Negative test for dup(2) with bad fds. * - * [Algorithm] - * Call dup(2) with invalid argument and make sure it returns -1 with errno set - * to EBADF. + * Verify that dup(2) syscall fails with errno EBADF when called with + * invalid value for oldfd argument. */ #include "tst_test.h" static struct tcase { int fd; - int expected_errno; + int exp_err; } tcases[] = { {-1, EBADF}, {1500, EBADF}, @@ -29,27 +26,10 @@ static void run(unsigned int n) { struct tcase *tc = &tcases[n]; - TEST(dup(tc->fd)); - - if (TST_RET < -1) { - tst_res(TFAIL | TTERRNO, "Invalid dup() return value %ld", - TST_RET); - return; - } - - if (TST_RET == -1) { - if (tc->expected_errno == TST_ERR) { - tst_res(TPASS | TTERRNO, "dup(%d) failed as expected", - tc->fd); - } else { - tst_res(TFAIL | TTERRNO, "dup(%d) failed unexpectedly", - tc->fd); - } - return; - } + TST_EXP_FAIL2(dup(tc->fd), tc->exp_err, "dup(%d)", tc->fd); - tst_res(TFAIL, "dup(%d) succeeded unexpectedly", tc->fd); - SAFE_CLOSE(TST_RET); + if (TST_RET != -1) + SAFE_CLOSE(TST_RET); } static struct tst_test test = { diff --git a/testcases/kernel/syscalls/dup/dup03.c b/testcases/kernel/syscalls/dup/dup03.c index 0e99813f4..d59e61f2b 100644 --- a/testcases/kernel/syscalls/dup/dup03.c +++ b/testcases/kernel/syscalls/dup/dup03.c @@ -6,48 +6,30 @@ */ /*\ * [Description] - * Negative test for dup(2) (too many fds). * - * [Algorithm] - * Open the maximum allowed number of file descriptors and then try to call - * dup() once more and verify it fails with EMFILE. + * Verify that dup(2) syscall fails with errno EMFILE when the per-process + * limit on the number of open file descriptors has been reached. */ #include <stdlib.h> #include "tst_test.h" -int *fd; -int nfds; +static int *fd; +static int nfds; static void run(void) { - TEST(dup(fd[0])); + TST_EXP_FAIL2(dup(fd[0]), EMFILE, "dup(%d)", fd[0]); - if (TST_RET < -1) { - tst_res(TFAIL, "Invalid dup() return value %ld", TST_RET); - return; - } - - if (TST_RET == -1) { - if (TST_ERR == EMFILE) - tst_res(TPASS | TTERRNO, "dup() failed as expected"); - else - tst_res(TFAIL | TTERRNO, "dup() failed unexpectedly"); - return; - } - - tst_res(TFAIL, "dup() succeeded unexpectedly"); - SAFE_CLOSE(TST_RET); + if (TST_RET != -1) + SAFE_CLOSE(TST_RET); } static void setup(void) { long maxfds; - maxfds = sysconf(_SC_OPEN_MAX); - if (maxfds == -1) - tst_brk(TBROK, "sysconf(_SC_OPEN_MAX) failed"); - + maxfds = SAFE_SYSCONF(_SC_OPEN_MAX); fd = SAFE_MALLOC(maxfds * sizeof(int)); fd[0] = SAFE_OPEN("dupfile", O_RDWR | O_CREAT, 0700); diff --git a/testcases/kernel/syscalls/dup/dup04.c b/testcases/kernel/syscalls/dup/dup04.c index 8d45f7a9c..053fb40c2 100644 --- a/testcases/kernel/syscalls/dup/dup04.c +++ b/testcases/kernel/syscalls/dup/dup04.c @@ -1,12 +1,12 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. - * * 06/1994 AUTHOR: Richard Logan CO-PILOT: William Roske + * Copyright (c) 2023 SUSE LLC */ /*\ - * [DESCRIPTION] + * [Description] * * Basic test for dup(2) of a system pipe descriptor. */ @@ -17,38 +17,18 @@ #include "tst_test.h" -int fd[2]; +static int fd[2]; static void run(void) { - TEST(dup(fd[0])); - - if (TST_RET == -1) - tst_res(TFAIL | TTERRNO, - "dup of read side of pipe failed"); - else { - tst_res(TPASS, - "dup(%d) read side of syspipe returned %ld", - fd[0], TST_RET); - - SAFE_CLOSE(TST_RET); - } - - TEST(dup(fd[1])); - - if (TST_RET == -1) { - tst_res(TFAIL | TTERRNO, - "dup of write side of pipe failed"); - } else { - tst_res(TPASS, - "dup(%d) write side of syspipe returned %ld", - fd[1], TST_RET); - - SAFE_CLOSE(TST_RET); - } + TST_EXP_FD(dup(fd[0]), "dup(%d) read end of the pipe", fd[0]); + SAFE_CLOSE(TST_RET); + + TST_EXP_FD(dup(fd[1]), "dup(%d) write end of the pipe", fd[1]); + SAFE_CLOSE(TST_RET); } -void setup(void) +static void setup(void) { fd[0] = -1; @@ -56,7 +36,7 @@ void setup(void) } static struct tst_test test = { - .test_all = run, - .setup = setup, - .needs_tmpdir = 1, + .test_all = run, + .setup = setup, + .needs_tmpdir = 1, }; diff --git a/testcases/kernel/syscalls/dup/dup05.c b/testcases/kernel/syscalls/dup/dup05.c index 362f3e170..619b4861e 100644 --- a/testcases/kernel/syscalls/dup/dup05.c +++ b/testcases/kernel/syscalls/dup/dup05.c @@ -1,55 +1,43 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. - * * 06/1994 AUTHOR: Richard Logan CO-PILOT: William Roske + * Copyright (c) 2012-2023 SUSE LLC */ /*\ - * [DESCRIPTION] + * [Description] * - * Basic test for dup(2) of a named pipe descriptor + * Basic test for dup(2) of a named pipe descriptor. */ -#include <stdio.h> + #include "tst_test.h" -char Fname[255]; -int fd; +#define FNAME "dupfile" + +static int fd = -1; static void run(void) { - TEST(dup(fd)); - - if (TST_RET == -1) { - tst_res(TFAIL | TTERRNO, "dup failed"); - } else { - tst_res(TPASS, "dup returned %ld", - TST_RET); - - SAFE_CLOSE(TST_RET); - } + TST_EXP_FD(dup(fd), "dup(%d)", fd); + SAFE_CLOSE(TST_RET); } -void setup(void) +static void setup(void) { - fd = -1; - - sprintf(Fname, "dupfile"); - SAFE_MKFIFO(Fname, 0777); - if ((fd = open(Fname, O_RDWR, 0700)) == -1) - tst_brk(TBROK, "open failed"); + SAFE_MKFIFO(FNAME, 0777); + fd = SAFE_OPEN(FNAME, O_RDWR, 0700); } -void cleanup(void) +static void cleanup(void) { if (fd != -1) - if (close(fd) == -1) - tst_res(TWARN | TERRNO, "close failed"); + SAFE_CLOSE(fd); } static struct tst_test test = { - .test_all = run, - .setup = setup, - .cleanup = cleanup, + .test_all = run, + .setup = setup, + .cleanup = cleanup, .needs_tmpdir = 1, }; diff --git a/testcases/kernel/syscalls/epoll_ctl/epoll_ctl02.c b/testcases/kernel/syscalls/epoll_ctl/epoll_ctl02.c index fe16ad1cb..dcf74bf77 100644 --- a/testcases/kernel/syscalls/epoll_ctl/epoll_ctl02.c +++ b/testcases/kernel/syscalls/epoll_ctl/epoll_ctl02.c @@ -67,7 +67,7 @@ static void setup(void) events[1].data.fd = fd[1]; if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd[0], &events[0])) - tst_brk(TBROK | TERRNO, "epoll_clt(..., EPOLL_CTL_ADD, ...)"); + tst_brk(TBROK | TERRNO, "epoll_ctl(..., EPOLL_CTL_ADD, ...)"); } static void cleanup(void) @@ -85,7 +85,7 @@ static void cleanup(void) static void verify_epoll_ctl(unsigned int n) { TST_EXP_FAIL(epoll_ctl(*tc[n].epfd, tc[n].opt, *tc[n].fd, tc[n].event), - tc[n].exp_err, "epoll_clt(...) if %s", tc[n].desc); + tc[n].exp_err, "epoll_ctl(...) if %s", tc[n].desc); } static struct tst_test test = { diff --git a/testcases/kernel/syscalls/epoll_ctl/epoll_ctl03.c b/testcases/kernel/syscalls/epoll_ctl/epoll_ctl03.c index c92b0b62e..f617295cc 100644 --- a/testcases/kernel/syscalls/epoll_ctl/epoll_ctl03.c +++ b/testcases/kernel/syscalls/epoll_ctl/epoll_ctl03.c @@ -55,7 +55,7 @@ static void setup(void) events.data.fd = fds[0]; if (epoll_ctl(epfd, EPOLL_CTL_ADD, fds[0], &events)) - tst_brk(TBROK | TERRNO, "epoll_clt(..., EPOLL_CTL_ADD, ...)"); + tst_brk(TBROK | TERRNO, "epoll_ctl(..., EPOLL_CTL_ADD, ...)"); } static void cleanup(void) diff --git a/testcases/kernel/syscalls/epoll_ctl/epoll_ctl04.c b/testcases/kernel/syscalls/epoll_ctl/epoll_ctl04.c index 5173755f7..bc015c01b 100644 --- a/testcases/kernel/syscalls/epoll_ctl/epoll_ctl04.c +++ b/testcases/kernel/syscalls/epoll_ctl/epoll_ctl04.c @@ -36,7 +36,7 @@ static void setup(void) events.data.fd = epfd; if (epoll_ctl(new_epfd, EPOLL_CTL_ADD, epfd, &events)) - tst_brk(TBROK | TERRNO, "epoll_clt(..., EPOLL_CTL_ADD, ...)"); + tst_brk(TBROK | TERRNO, "epoll_ctl(..., EPOLL_CTL_ADD, ...)"); epfd = new_epfd; } @@ -59,7 +59,7 @@ static void verify_epoll_ctl(void) events.data.fd = epfd; TST_EXP_FAIL(epoll_ctl(new_epfd, EPOLL_CTL_ADD, epfd, &events), EINVAL, - "epoll_clt(..., EPOLL_CTL_ADD, ...) with number of nesting is 5"); + "epoll_ctl(..., EPOLL_CTL_ADD, ...) with number of nesting is 5"); SAFE_CLOSE(new_epfd); } diff --git a/testcases/kernel/syscalls/epoll_ctl/epoll_ctl05.c b/testcases/kernel/syscalls/epoll_ctl/epoll_ctl05.c index d03009cf3..71e300daa 100644 --- a/testcases/kernel/syscalls/epoll_ctl/epoll_ctl05.c +++ b/testcases/kernel/syscalls/epoll_ctl/epoll_ctl05.c @@ -40,12 +40,12 @@ static void setup(void) events.data.fd = epfd; if (epoll_ctl(new_epfd, EPOLL_CTL_ADD, epfd, &events)) - tst_brk(TBROK | TERRNO, "epoll_clt(..., EPOLL_CTL_ADD, ...)"); + tst_brk(TBROK | TERRNO, "epoll_ctl(..., EPOLL_CTL_ADD, ...)"); } events.data.fd = fd[0]; if (epoll_ctl(origin_epfd, EPOLL_CTL_DEL, fd[0], &events)) - tst_brk(TBROK | TERRNO, "epoll_clt(..., EPOLL_CTL_DEL, ...)"); + tst_brk(TBROK | TERRNO, "epoll_ctl(..., EPOLL_CTL_DEL, ...)"); } static void cleanup(void) @@ -61,7 +61,7 @@ static void verify_epoll_ctl(void) { events.data.fd = epfd; TST_EXP_FAIL(epoll_ctl(origin_epfd, EPOLL_CTL_ADD, epfd, &events), - ELOOP, "epoll_clt(..., EPOLL_CTL_ADD, ...)"); + ELOOP, "epoll_ctl(..., EPOLL_CTL_ADD, ...)"); } static struct tst_test test = { diff --git a/testcases/kernel/syscalls/epoll_pwait/epoll_pwait01.c b/testcases/kernel/syscalls/epoll_pwait/epoll_pwait01.c index f4a55e008..928d57803 100644 --- a/testcases/kernel/syscalls/epoll_pwait/epoll_pwait01.c +++ b/testcases/kernel/syscalls/epoll_pwait/epoll_pwait01.c @@ -102,7 +102,7 @@ static void setup(void) e.events = EPOLLIN; if (epoll_ctl(efd, EPOLL_CTL_ADD, sfd[0], &e)) - tst_brk(TBROK | TERRNO, "epoll_clt(..., EPOLL_CTL_ADD, ...)"); + tst_brk(TBROK | TERRNO, "epoll_ctl(..., EPOLL_CTL_ADD, ...)"); } static void cleanup(void) diff --git a/testcases/kernel/syscalls/epoll_pwait/epoll_pwait02.c b/testcases/kernel/syscalls/epoll_pwait/epoll_pwait02.c index 7914f1c50..2ae32519f 100644 --- a/testcases/kernel/syscalls/epoll_pwait/epoll_pwait02.c +++ b/testcases/kernel/syscalls/epoll_pwait/epoll_pwait02.c @@ -42,7 +42,7 @@ static void setup(void) e.events = EPOLLIN; if (epoll_ctl(efd, EPOLL_CTL_ADD, sfd[0], &e)) - tst_brk(TBROK | TERRNO, "epoll_clt(..., EPOLL_CTL_ADD, ...)"); + tst_brk(TBROK | TERRNO, "epoll_ctl(..., EPOLL_CTL_ADD, ...)"); SAFE_WRITE(SAFE_WRITE_ALL, sfd[1], "w", 1); } diff --git a/testcases/kernel/syscalls/epoll_pwait/epoll_pwait03.c b/testcases/kernel/syscalls/epoll_pwait/epoll_pwait03.c index 2ad1a6abc..aa08daa1b 100644 --- a/testcases/kernel/syscalls/epoll_pwait/epoll_pwait03.c +++ b/testcases/kernel/syscalls/epoll_pwait/epoll_pwait03.c @@ -50,7 +50,7 @@ static void setup(void) e.events = EPOLLIN; if (epoll_ctl(efd, EPOLL_CTL_ADD, sfd[0], &e)) - tst_brk(TBROK | TERRNO, "epoll_clt(..., EPOLL_CTL_ADD, ...)"); + tst_brk(TBROK | TERRNO, "epoll_ctl(..., EPOLL_CTL_ADD, ...)"); } static void cleanup(void) diff --git a/testcases/kernel/syscalls/epoll_pwait/epoll_pwait04.c b/testcases/kernel/syscalls/epoll_pwait/epoll_pwait04.c index 54b9be975..4be33488d 100644 --- a/testcases/kernel/syscalls/epoll_pwait/epoll_pwait04.c +++ b/testcases/kernel/syscalls/epoll_pwait/epoll_pwait04.c @@ -38,7 +38,7 @@ static void setup(void) e.events = EPOLLIN; if (epoll_ctl(efd, EPOLL_CTL_ADD, sfd[0], &e)) - tst_brk(TBROK | TERRNO, "epoll_clt(..., EPOLL_CTL_ADD, ...)"); + tst_brk(TBROK | TERRNO, "epoll_ctl(..., EPOLL_CTL_ADD, ...)"); SAFE_WRITE(SAFE_WRITE_ALL, sfd[1], "w", 1); bad_addr = tst_get_bad_addr(NULL); diff --git a/testcases/kernel/syscalls/epoll_pwait/epoll_pwait05.c b/testcases/kernel/syscalls/epoll_pwait/epoll_pwait05.c index 4c4aeb77d..ed8f3e4f8 100644 --- a/testcases/kernel/syscalls/epoll_pwait/epoll_pwait05.c +++ b/testcases/kernel/syscalls/epoll_pwait/epoll_pwait05.c @@ -46,7 +46,7 @@ static void setup(void) e.events = EPOLLIN; if (epoll_ctl(efd, EPOLL_CTL_ADD, sfd[0], &e)) - tst_brk(TBROK | TERRNO, "epoll_clt(..., EPOLL_CTL_ADD, ...)"); + tst_brk(TBROK | TERRNO, "epoll_ctl(..., EPOLL_CTL_ADD, ...)"); SAFE_WRITE(SAFE_WRITE_ALL, sfd[1], "w", 1); } diff --git a/testcases/kernel/syscalls/epoll_wait/.gitignore b/testcases/kernel/syscalls/epoll_wait/.gitignore index 222955dd2..66ac18ae2 100644 --- a/testcases/kernel/syscalls/epoll_wait/.gitignore +++ b/testcases/kernel/syscalls/epoll_wait/.gitignore @@ -2,3 +2,6 @@ epoll_wait01 epoll_wait02 epoll_wait03 epoll_wait04 +epoll_wait05 +epoll_wait06 +epoll_wait07 diff --git a/testcases/kernel/syscalls/epoll_wait/epoll_wait02.c b/testcases/kernel/syscalls/epoll_wait/epoll_wait02.c index d2c0b6ef4..93ada1cf3 100644 --- a/testcases/kernel/syscalls/epoll_wait/epoll_wait02.c +++ b/testcases/kernel/syscalls/epoll_wait/epoll_wait02.c @@ -50,7 +50,7 @@ static void setup(void) epevs[0].data.fd = fds[0]; if (epoll_ctl(epfd, EPOLL_CTL_ADD, fds[0], &epevs[0])) - tst_brk(TBROK | TERRNO, "epoll_clt(..., EPOLL_CTL_ADD, ...)"); + tst_brk(TBROK | TERRNO, "epoll_ctl(..., EPOLL_CTL_ADD, ...)"); } static void cleanup(void) diff --git a/testcases/kernel/syscalls/epoll_wait/epoll_wait03.c b/testcases/kernel/syscalls/epoll_wait/epoll_wait03.c index 4b21aba4c..d31e49864 100644 --- a/testcases/kernel/syscalls/epoll_wait/epoll_wait03.c +++ b/testcases/kernel/syscalls/epoll_wait/epoll_wait03.c @@ -57,7 +57,7 @@ static void setup(void) epevs[0].data.fd = fds[1]; if (epoll_ctl(epfd, EPOLL_CTL_ADD, fds[1], &epevs[0])) - tst_brk(TBROK | TERRNO, "epoll_clt(..., EPOLL_CTL_ADD, ...)"); + tst_brk(TBROK | TERRNO, "epoll_ctl(..., EPOLL_CTL_ADD, ...)"); } static void verify_epoll_wait(unsigned int n) diff --git a/testcases/kernel/syscalls/epoll_wait/epoll_wait04.c b/testcases/kernel/syscalls/epoll_wait/epoll_wait04.c index dc62e9202..bd8baca22 100644 --- a/testcases/kernel/syscalls/epoll_wait/epoll_wait04.c +++ b/testcases/kernel/syscalls/epoll_wait/epoll_wait04.c @@ -49,7 +49,7 @@ static void setup(void) epevs[0].data.fd = fds[0]; if (epoll_ctl(epfd, EPOLL_CTL_ADD, fds[0], &epevs[0])) - tst_brk(TBROK | TERRNO, "epoll_clt(..., EPOLL_CTL_ADD, ...)"); + tst_brk(TBROK | TERRNO, "epoll_ctl(..., EPOLL_CTL_ADD, ...)"); } static void cleanup(void) diff --git a/testcases/kernel/syscalls/epoll_wait/epoll_wait05.c b/testcases/kernel/syscalls/epoll_wait/epoll_wait05.c new file mode 100644 index 000000000..d06a024ff --- /dev/null +++ b/testcases/kernel/syscalls/epoll_wait/epoll_wait05.c @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +/*\ + * [Description] + * + * Verify that epoll receives EPOLLRDHUP event when we hang a reading + * half-socket we are polling on. + */ + +#include "tst_test.h" +#include "tst_net.h" +#include "tst_epoll.h" + +static int epfd; +static int sockfd_client; +static int sockfd_server; +static in_port_t *sock_port; + +static void create_server(void) +{ + int sockfd_server; + socklen_t len; + struct sockaddr_in serv_addr; + struct sockaddr_in sin; + + tst_init_sockaddr_inet_bin(&serv_addr, INADDR_ANY, 0); + + sockfd_server = SAFE_SOCKET(AF_INET, SOCK_STREAM, 0); + SAFE_BIND(sockfd_server, (struct sockaddr *)&serv_addr, sizeof(serv_addr)); + SAFE_LISTEN(sockfd_server, 10); + + len = sizeof(sin); + memset(&sin, 0, sizeof(struct sockaddr_in)); + SAFE_GETSOCKNAME(sockfd_server, (struct sockaddr *)&sin, &len); + + *sock_port = ntohs(sin.sin_port); + + tst_res(TINFO, "Listening on port %d", *sock_port); + + TST_CHECKPOINT_WAKE_AND_WAIT(0); + + SAFE_CLOSE(sockfd_server); +} + +static void run(void) +{ + struct sockaddr_in client_addr; + struct epoll_event evt_req; + struct epoll_event evt_rec; + int ret; + + if (!SAFE_FORK()) { + create_server(); + return; + } + + TST_CHECKPOINT_WAIT(0); + + tst_res(TINFO, "Connecting to port %d", *sock_port); + + sockfd_client = SAFE_SOCKET(AF_INET, SOCK_STREAM, 0); + + tst_init_sockaddr_inet(&client_addr, "127.0.0.1", *sock_port); + + SAFE_CONNECT(sockfd_client, + (struct sockaddr *)&client_addr, + sizeof(client_addr)); + + tst_res(TINFO, "Polling on socket"); + + epfd = SAFE_EPOLL_CREATE1(0); + evt_req.events = EPOLLRDHUP; + SAFE_EPOLL_CTL(epfd, EPOLL_CTL_ADD, sockfd_client, &evt_req); + + tst_res(TINFO, "Hang socket"); + + TST_EXP_PASS_SILENT(shutdown(sockfd_client, SHUT_RD)); + ret = SAFE_EPOLL_WAIT(epfd, &evt_rec, 1, 2000); + if (ret != 1) { + tst_res(TFAIL, "Wrong number of events reported %i", ret); + goto exit; + } + + if (evt_rec.events & EPOLLRDHUP) + tst_res(TPASS, "Received EPOLLRDHUP"); + else + tst_res(TFAIL, "EPOLLRDHUP has not been received"); + +exit: + SAFE_CLOSE(epfd); + SAFE_CLOSE(sockfd_client); + + TST_CHECKPOINT_WAKE(0); +} + +static void setup(void) +{ + sock_port = SAFE_MMAP(NULL, sizeof(in_port_t), PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, 0); +} + +static void cleanup(void) +{ + if (sock_port) + SAFE_MUNMAP(sock_port, sizeof(in_port_t)); + + if (fcntl(sockfd_client, F_GETFD) > 0) + SAFE_CLOSE(sockfd_client); + + if (fcntl(sockfd_server, F_GETFD) > 0) + SAFE_CLOSE(sockfd_server); + + if (fcntl(epfd, F_GETFD) > 0) + SAFE_CLOSE(epfd); +} + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test_all = run, + .forks_child = 1, + .needs_checkpoints = 1, +}; diff --git a/testcases/kernel/syscalls/epoll_wait/epoll_wait06.c b/testcases/kernel/syscalls/epoll_wait/epoll_wait06.c new file mode 100644 index 000000000..f35e0423a --- /dev/null +++ b/testcases/kernel/syscalls/epoll_wait/epoll_wait06.c @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +/*\ + * [Description] + * + * Verify that edge triggering is correctly handled by epoll, for both EPOLLIN + * and EPOLLOUT. + * + * [Algorithm] + * + * - The file descriptors for non-blocking pipe are registered on an epoll + * instance. + * - A pipe writer writes data on the write side of the pipe. + * - A call to epoll_wait() is done that will return a EPOLLIN event. + * - The pipe reader reads half of data from rfd. + * - A call to epoll_wait() should hang because there's data left to read. + * - The pipe reader reads remaining data from rfd. + * - A call to epoll_wait() should return a EPOLLOUT event. + */ + +#define _GNU_SOURCE + +#include <fcntl.h> +#include "tst_test.h" +#include "tst_epoll.h" + +static size_t write_size; +static size_t read_size; +static int fds[2]; +static int epfd; + +static void setup(void) +{ + write_size = getpagesize(); + read_size = write_size / 2; + + SAFE_PIPE2(fds, O_NONBLOCK); + + /* EPOLLOUT will be raised when buffer became empty after becoming full */ + SAFE_FCNTL(fds[1], F_SETPIPE_SZ, write_size); +} + +static void cleanup(void) +{ + if (epfd > 0) + SAFE_CLOSE(epfd); + + if (fds[0] > 0) + SAFE_CLOSE(fds[0]); + + if (fds[1] > 0) + SAFE_CLOSE(fds[1]); +} + +static void run(void) +{ + char buff[write_size]; + struct epoll_event evt_receive; + + tst_res(TINFO, "Polling on channel with EPOLLET"); + + epfd = SAFE_EPOLL_CREATE1(0); + + SAFE_EPOLL_CTL(epfd, EPOLL_CTL_ADD, fds[0], &((struct epoll_event) { + .events = EPOLLIN | EPOLLET, + .data.fd = fds[0], + })); + SAFE_EPOLL_CTL(epfd, EPOLL_CTL_ADD, fds[1], &((struct epoll_event) { + .events = EPOLLOUT | EPOLLET, + .data.fd = fds[1], + })); + + tst_res(TINFO, "Write bytes on channel: %zu bytes", write_size); + + memset(buff, 'a', write_size); + SAFE_WRITE(SAFE_WRITE_ANY, fds[1], buff, write_size); + TST_EXP_FAIL(write(fds[1], buff, write_size), EAGAIN, "write() failed"); + + TST_EXP_EQ_LI(SAFE_EPOLL_WAIT(epfd, &evt_receive, 1, 0), 1); + TST_EXP_EQ_LI(evt_receive.data.fd, fds[0]); + TST_EXP_EQ_LI(evt_receive.events & EPOLLIN, EPOLLIN); + + tst_res(TINFO, "Read half bytes from channel: %zu bytes", read_size); + + memset(buff, 0, write_size); + SAFE_READ(1, fds[0], buff, read_size); + + TST_EXP_EQ_LI(SAFE_EPOLL_WAIT(epfd, &evt_receive, 1, 0), 0); + + tst_res(TINFO, "Read remaining bytes from channel: %zu bytes", read_size); + + SAFE_READ(1, fds[0], buff + read_size, read_size); + TST_EXP_FAIL(read(fds[0], buff, read_size), EAGAIN, "read() failed"); + + TST_EXP_EQ_LI(SAFE_EPOLL_WAIT(epfd, &evt_receive, 1, 0), 1); + TST_EXP_EQ_LI(evt_receive.data.fd, fds[1]); + TST_EXP_EQ_LI(evt_receive.events & EPOLLOUT, EPOLLOUT); +} + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test_all = run, +}; diff --git a/testcases/kernel/syscalls/epoll_wait/epoll_wait07.c b/testcases/kernel/syscalls/epoll_wait/epoll_wait07.c new file mode 100644 index 000000000..dfabd0d87 --- /dev/null +++ b/testcases/kernel/syscalls/epoll_wait/epoll_wait07.c @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +/*\ + * [Description] + * + * Verify that EPOLLONESHOT is correctly handled by epoll_wait. + * We open a channel, write in it two times and verify that EPOLLIN has been + * received only once. + */ + +#include <poll.h> +#include <sys/epoll.h> +#include "tst_test.h" +#include "tst_epoll.h" + +static int fds[2]; +static int epfd; + +static void cleanup(void) +{ + if (epfd > 0) + SAFE_CLOSE(epfd); + + if (fds[0] > 0) + SAFE_CLOSE(fds[0]); + + if (fds[1] > 0) + SAFE_CLOSE(fds[1]); +} + +static void run(void) +{ + struct epoll_event evt_receive; + char buff = 'a'; + + SAFE_PIPE(fds); + + tst_res(TINFO, "Polling on channel with EPOLLONESHOT"); + + epfd = SAFE_EPOLL_CREATE1(0); + + SAFE_EPOLL_CTL(epfd, EPOLL_CTL_ADD, fds[0], &((struct epoll_event) { + .events = EPOLLIN | EPOLLONESHOT, + .data.fd = fds[0], + })); + + tst_res(TINFO, "Write channel for the 1st time. EPOLLIN expected"); + + SAFE_WRITE(0, fds[1], &buff, 1); + TST_EXP_EQ_LI(SAFE_EPOLL_WAIT(epfd, &evt_receive, 10, 0), 1); + TST_EXP_EQ_LI(evt_receive.events & EPOLLIN, EPOLLIN); + TST_EXP_EQ_LI(evt_receive.data.fd, fds[0]); + + SAFE_READ(1, fds[0], &buff, 1); + TST_EXP_EQ_LI(SAFE_EPOLL_WAIT(epfd, &evt_receive, 10, 0), 0); + + tst_res(TINFO, "Write channel for the 2nd time. No events expected"); + + SAFE_WRITE(0, fds[1], &buff, 1); + TST_EXP_EQ_LI(SAFE_EPOLL_WAIT(epfd, &evt_receive, 10, 0), 0); + + SAFE_CLOSE(epfd); + SAFE_CLOSE(fds[0]); + SAFE_CLOSE(fds[1]); +} + +static struct tst_test test = { + .cleanup = cleanup, + .test_all = run, +}; diff --git a/testcases/kernel/syscalls/eventfd/.gitignore b/testcases/kernel/syscalls/eventfd/.gitignore index db45c67cf..4f577370c 100644 --- a/testcases/kernel/syscalls/eventfd/.gitignore +++ b/testcases/kernel/syscalls/eventfd/.gitignore @@ -1 +1,6 @@ /eventfd01 +/eventfd02 +/eventfd03 +/eventfd04 +/eventfd05 +/eventfd06 diff --git a/testcases/kernel/syscalls/eventfd/eventfd01.c b/testcases/kernel/syscalls/eventfd/eventfd01.c index 9b60434a2..b66d6a55c 100644 --- a/testcases/kernel/syscalls/eventfd/eventfd01.c +++ b/testcases/kernel/syscalls/eventfd/eventfd01.c @@ -1,738 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) 2008 Vijay Kumar B. <vijaykumar@bravegnu.org> - * Copyright (c) Linux Test Project, 2008-2022 - * - * Based on testcases/kernel/syscalls/waitpid/waitpid01.c - * Original copyright message: - * - * 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 + * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) 2008 Vijay Kumar B. <vijaykumar@bravegnu.org> + * Copyright (c) Linux Test Project, 2008-2022 + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> */ -/* - * NAME - * eventfd01.c - * - * DESCRIPTION - * Test cases for eventfd syscall. +/*\ + * [Description] * - * USAGE: <for command-line> - * eventfd01 [-c n] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * - * History - * 07/2008 Vijay Kumar - * Initial Version. - * - * Restrictions - * None - */ - -#include "config.h" - -#include <sys/types.h> -#include <sys/select.h> -#include <sys/wait.h> -#include <errno.h> -#include <fcntl.h> -#include <inttypes.h> -#include <poll.h> -#include <signal.h> -#include <stdint.h> -#include <string.h> -#include <unistd.h> - -#include "test.h" -#define CLEANUP cleanup -#include "lapi/syscalls.h" - -TCID_DEFINE(eventfd01); -int TST_TOTAL = 15; - -#ifdef HAVE_LIBAIO -#include <libaio.h> - -static void setup(void); - -static int myeventfd(unsigned int initval, int flags) -{ - /* eventfd2 uses FLAGS but eventfd doesn't take FLAGS. */ - return tst_syscall(__NR_eventfd, initval); -} - -/* - * clear_counter() - clears the counter by performing a dummy read - * @fd: the eventfd + * Verify read operation for eventfd fail with: * - * RETURNS: - * 0 on success, and -1 on failure - */ -static int clear_counter(int fd) -{ - uint64_t dummy; - int ret; - - ret = read(fd, &dummy, sizeof(dummy)); - if (ret == -1) { - if (errno != EAGAIN) { - tst_resm(TINFO | TERRNO, "error clearing counter"); - return -1; - } - } - - return 0; -} - -/* - * set_counter() - sets the count to specified value - * @fd: the eventfd - * @val: the value to be set - * - * Clears the counter and sets the counter to @val. - * - * RETURNS: - * 0 on success, -1 on failure - */ -static int set_counter(int fd, uint64_t val) -{ - int ret; - - ret = clear_counter(fd); - if (ret == -1) - return -1; - - ret = write(fd, &val, sizeof(val)); - if (ret == -1) { - tst_resm(TINFO | TERRNO, "error setting counter value"); - return -1; - } - - return 0; -} - -/* - * Test whether the current value of the counter matches @required. - */ -static void read_test(int fd, uint64_t required) -{ - int ret; - uint64_t val; - - ret = read(fd, &val, sizeof(val)); - if (ret == -1) { - tst_resm(TBROK | TERRNO, "error reading eventfd"); - return; - } - - if (val == required) - tst_resm(TPASS, "counter value matches required"); - else - tst_resm(TFAIL, "counter value mismatch: " - "required: %" PRIu64 ", got: %" PRIu64, required, val); -} - -/* - * Test whether read returns with error EAGAIN when counter is at 0. - */ -static void read_eagain_test(int fd) -{ - int ret; - uint64_t val; - - ret = clear_counter(fd); - if (ret == -1) { - tst_resm(TBROK, "error clearing counter"); - return; - } - - ret = read(fd, &val, sizeof(val)); - if (ret == -1) { - if (errno == EAGAIN) - tst_resm(TPASS, "read failed with EAGAIN as expected"); - else - tst_resm(TFAIL | TERRNO, "read failed (wanted EAGAIN)"); - } else - tst_resm(TFAIL, "read returned with %d", ret); -} - -/* - * Test whether writing to counter works. + * - EAGAIN when counter is zero on non blocking fd + * - EINVAL when buffer size is less than 8 bytes */ -static void write_test(int fd) -{ - int ret; - uint64_t val; - - val = 12; - ret = set_counter(fd, val); - if (ret == -1) { - tst_resm(TBROK, "error setting counter value to %" PRIu64, val); - return; - } +#include <stdlib.h> +#include <sys/eventfd.h> +#include "tst_test.h" - read_test(fd, val); -} +#define EVENT_COUNT 10 -/* - * Test whether write returns with error EAGAIN when counter is at - * (UINT64_MAX - 1). - */ -static void write_eagain_test(int fd) +static void run(void) { - int ret; + int fd; uint64_t val; - - ret = set_counter(fd, UINT64_MAX - 1); - if (ret == -1) { - tst_resm(TBROK, "error setting counter value to UINT64_MAX-1"); - return; - } - - val = 1; - ret = write(fd, &val, sizeof(val)); - if (ret == -1) { - if (errno == EAGAIN) - tst_resm(TPASS, "write failed with EAGAIN as expected"); - else - tst_resm(TFAIL, "write failed (wanted EAGAIN)"); - } else - tst_resm(TFAIL, "write returned with %d", ret); -} - -/* - * Test whether read returns with error EINVAL, if buffer size is less - * than 8 bytes. - */ -static void read_einval_test(int fd) -{ uint32_t invalid; - int ret; - ret = read(fd, &invalid, sizeof(invalid)); - if (ret == -1) { - if (errno == EINVAL) - tst_resm(TPASS, "read failed with EINVAL as expected"); - else - tst_resm(TFAIL | TERRNO, "read failed (wanted EINVAL)"); - } else - tst_resm(TFAIL, "read returned with %d", ret); -} + fd = TST_EXP_FD(eventfd(EVENT_COUNT, EFD_NONBLOCK)); -/* - * Test whether write returns with error EINVAL, if buffer size is - * less than 8 bytes. - */ -static void write_einval_test(int fd) -{ - uint32_t invalid; - int ret; + SAFE_READ(0, fd, &val, sizeof(val)); + TST_EXP_EQ_LI(val, EVENT_COUNT); - ret = write(fd, &invalid, sizeof(invalid)); - if (ret == -1) { - if (errno == EINVAL) - tst_resm(TPASS, "write failed with EINVAL as expected"); - else - tst_resm(TFAIL | TERRNO, - "write failed (wanted EINVAL)"); - } else - tst_resm(TFAIL, "write returned with %d", ret); -} + TST_EXP_FAIL(read(fd, &val, sizeof(val)), EAGAIN); + TST_EXP_FAIL(read(fd, &invalid, sizeof(invalid)), EINVAL); -/* - * Test wheter write returns with error EINVAL, when the written value - * is 0xFFFFFFFFFFFFFFFF. - */ -static void write_einval2_test(int fd) -{ - int ret; - uint64_t val; - - ret = clear_counter(fd); - if (ret == -1) { - tst_resm(TBROK, "error clearing counter"); - return; - } - - val = 0xffffffffffffffffLL; - ret = write(fd, &val, sizeof(val)); - if (ret == -1) { - if (errno == EINVAL) - tst_resm(TPASS, "write failed with EINVAL as expected"); - else - tst_resm(TFAIL | TERRNO, - "write failed (wanted EINVAL)"); - } else { - tst_resm(TFAIL, "write returned with %d", ret); - } + SAFE_CLOSE(fd); } -/* - * Test whether readfd is set by select when counter value is - * non-zero. - */ -static void readfd_set_test(int fd) -{ - int ret; - fd_set readfds; - struct timeval timeout = { 0, 0 }; - uint64_t non_zero = 10; - - FD_ZERO(&readfds); - FD_SET(fd, &readfds); - - ret = set_counter(fd, non_zero); - if (ret == -1) { - tst_resm(TBROK, "error setting counter value to %" PRIu64, - non_zero); - return; - } - - ret = select(fd + 1, &readfds, NULL, NULL, &timeout); - if (ret == -1) { - /* EINTR cannot occur, since we don't block. */ - tst_resm(TBROK | TERRNO, "select() failed"); - return; - } - - if (FD_ISSET(fd, &readfds)) - tst_resm(TPASS, "fd is set in readfds"); - else - tst_resm(TFAIL, "fd is not set in readfds"); -} - -/* - * Test whether readfd is not set by select when counter value is - * zero. - */ -static void readfd_not_set_test(int fd) -{ - int ret; - fd_set readfds; - struct timeval timeout = { 0, 0 }; - - FD_ZERO(&readfds); - FD_SET(fd, &readfds); - - ret = clear_counter(fd); - if (ret == -1) { - tst_resm(TBROK, "error clearing counter"); - return; - } - - ret = select(fd + 1, &readfds, NULL, NULL, &timeout); - if (ret == -1) { - /* EINTR cannot occur, since we don't block. */ - tst_resm(TBROK | TERRNO, "select() failed"); - return; - } - - if (!FD_ISSET(fd, &readfds)) - tst_resm(TPASS, "fd is not set in readfds"); - else - tst_resm(TFAIL, "fd is set in readfds"); -} - -/* - * Test whether writefd is set by select when counter value is not the - * maximum counter value. - */ -static void writefd_set_test(int fd) -{ - int ret; - fd_set writefds; - struct timeval timeout = { 0, 0 }; - uint64_t non_max = 10; - - FD_ZERO(&writefds); - FD_SET(fd, &writefds); - - ret = set_counter(fd, non_max); - if (ret == -1) { - tst_resm(TBROK, "error setting counter value to %" PRIu64, - non_max); - return; - } - - ret = select(fd + 1, NULL, &writefds, NULL, &timeout); - if (ret == -1) { - /* EINTR cannot occur, since we don't block. */ - tst_resm(TBROK | TERRNO, "select: error getting fd status"); - return; - } - - if (FD_ISSET(fd, &writefds)) - tst_resm(TPASS, "fd is set in writefds"); - else - tst_resm(TFAIL, "fd is not set in writefds"); -} - -/* - * Test whether writefd is not set by select when counter value is at - * (UINT64_MAX - 1). - */ -static void writefd_not_set_test(int fd) -{ - int ret; - fd_set writefds; - struct timeval timeout = { 0, 0 }; - - FD_ZERO(&writefds); - FD_SET(fd, &writefds); - - ret = set_counter(fd, UINT64_MAX - 1); - if (ret == -1) { - tst_resm(TBROK, "error setting counter value to UINT64_MAX-1"); - return; - } - - ret = select(fd + 1, NULL, &writefds, NULL, &timeout); - if (ret == -1) { - /* EINTR cannot occur, since we don't block. */ - tst_resm(TBROK | TERRNO, "select: error getting fd status"); - return; - } - - if (!FD_ISSET(fd, &writefds)) - tst_resm(TPASS, "fd is not set in writefds"); - else - tst_resm(TFAIL, "fd is set in writefds"); -} - -/* - * Test whether counter update in child is reflected in the parent. - */ -static void child_inherit_test(int fd) -{ - uint64_t val; - pid_t cpid; - int ret; - int status; - uint64_t to_parent = 0xdeadbeef; - uint64_t dummy; - - cpid = fork(); - if (cpid == -1) - tst_resm(TBROK | TERRNO, "fork failed"); - else if (cpid != 0) { - ret = wait(&status); - if (ret == -1) { - tst_resm(TBROK, "error getting child exit status"); - return; - } - - if (WEXITSTATUS(status) == 1) { - tst_resm(TBROK, "counter value write not " - "successful in child"); - return; - } - - ret = read(fd, &val, sizeof(val)); - if (ret == -1) { - tst_resm(TBROK | TERRNO, "error reading eventfd"); - return; - } - - if (val == to_parent) - tst_resm(TPASS, "counter value write from " - "child successful"); - else - tst_resm(TFAIL, "counter value write in child " - "failed"); - } else { - /* Child */ - ret = read(fd, &dummy, sizeof(dummy)); - if (ret == -1 && errno != EAGAIN) { - tst_resm(TWARN | TERRNO, "error clearing counter"); - exit(1); - } - - ret = write(fd, &to_parent, sizeof(to_parent)); - if (ret == -1) { - tst_resm(TWARN | TERRNO, "error writing eventfd"); - exit(1); - } - - exit(0); - } -} - -#ifdef HAVE_IO_SET_EVENTFD -/* - * Test whether counter overflow is detected and handled correctly. - * - * It is not possible to directly overflow the counter using the - * write() syscall. Overflows occur when the counter is incremented - * from kernel space, in an irq context, when it is not possible to - * block the calling thread of execution. - * - * The AIO subsystem internally uses eventfd mechanism for - * notification of completion of read or write requests. In this test - * we trigger a counter overflow, by setting the counter value to the - * max possible value initially. When the AIO subsystem notifies - * through the eventfd counter, the counter overflows. - * - * NOTE: If the the counter starts from an initial value of 0, it will - * take decades for an overflow to occur. But since we set the initial - * value to the max possible counter value, we are able to cause it to - * overflow with a single increment. - * - * When the counter overflows, the following are tested - * 1. Check whether POLLERR event occurs in poll() for the eventfd. - * 2. Check whether readfd_set/writefd_set is set in select() for the - eventfd. - * 3. The counter value is UINT64_MAX. - */ -static int trigger_eventfd_overflow(int evfd, int *fd, io_context_t * ctx) -{ - int ret; - struct iocb iocb; - struct iocb *iocbap[1]; - struct io_event ioev; - static char buf[4 * 1024]; - - *ctx = 0; - ret = io_setup(16, ctx); - if (ret < 0) { - errno = -ret; - if (errno == ENOSYS) { - tst_brkm(TCONF | TERRNO, cleanup, - "io_setup(): AIO not supported by kernel"); - } - - tst_resm(TINFO | TERRNO, "io_setup error"); - return -1; - } - - *fd = open("testfile", O_RDWR | O_CREAT, 0644); - if (*fd == -1) { - tst_resm(TINFO | TERRNO, "open(testfile) failed"); - goto err_io_destroy; - } - - ret = set_counter(evfd, UINT64_MAX - 1); - if (ret == -1) { - tst_resm(TINFO, "error setting counter to UINT64_MAX-1"); - goto err_close_file; - } - - io_prep_pwrite(&iocb, *fd, buf, sizeof(buf), 0); - io_set_eventfd(&iocb, evfd); - - iocbap[0] = &iocb; - ret = io_submit(*ctx, 1, iocbap); - if (ret < 0) { - errno = -ret; - tst_resm(TINFO | TERRNO, "error submitting iocb"); - goto err_close_file; - } - - ret = io_getevents(*ctx, 1, 1, &ioev, NULL); - if (ret < 0) { - errno = -ret; - tst_resm(TINFO | TERRNO, "error waiting for event"); - goto err_close_file; - } - - return 0; - -err_close_file: - close(*fd); - -err_io_destroy: - io_destroy(*ctx); - - return -1; -} - -static void cleanup_overflow(int fd, io_context_t ctx) -{ - close(fd); - io_destroy(ctx); -} - -static void overflow_select_test(int evfd) -{ - struct timeval timeout = { 10, 0 }; - fd_set readfds; - int fd; - io_context_t ctx; - int ret; - - ret = trigger_eventfd_overflow(evfd, &fd, &ctx); - if (ret == -1) { - tst_resm(TBROK, "error triggering eventfd overflow"); - return; - } - - FD_ZERO(&readfds); - FD_SET(evfd, &readfds); - ret = select(evfd + 1, &readfds, NULL, NULL, &timeout); - if (ret == -1) - tst_resm(TBROK | TERRNO, - "error getting evfd status with select"); - else { - if (FD_ISSET(evfd, &readfds)) - tst_resm(TPASS, "read fd set as expected"); - else - tst_resm(TFAIL, "read fd not set"); - } - cleanup_overflow(fd, ctx); -} - -static void overflow_poll_test(int evfd) -{ - struct pollfd pollfd; - int fd; - io_context_t ctx; - int ret; - - ret = trigger_eventfd_overflow(evfd, &fd, &ctx); - if (ret == -1) { - tst_resm(TBROK, "error triggering eventfd overflow"); - return; - } - - pollfd.fd = evfd; - pollfd.events = POLLIN; - pollfd.revents = 0; - ret = poll(&pollfd, 1, 10000); - if (ret == -1) - tst_resm(TBROK | TERRNO, "error getting evfd status with poll"); - else { - if (pollfd.revents & POLLERR) - tst_resm(TPASS, "POLLERR occurred as expected"); - else - tst_resm(TFAIL, "POLLERR did not occur"); - } - cleanup_overflow(fd, ctx); -} - -static void overflow_read_test(int evfd) -{ - uint64_t count; - io_context_t ctx; - int fd; - int ret; - - ret = trigger_eventfd_overflow(evfd, &fd, &ctx); - if (ret == -1) { - tst_resm(TBROK, "error triggering eventfd overflow"); - return; - } - - ret = read(evfd, &count, sizeof(count)); - if (ret == -1) - tst_resm(TBROK | TERRNO, "error reading eventfd"); - else { - - if (count == UINT64_MAX) - tst_resm(TPASS, "overflow occurred as expected"); - else - tst_resm(TFAIL, "overflow did not occur"); - } - cleanup_overflow(fd, ctx); -} -#else -static void overflow_select_test(int evfd) -{ - tst_resm(TCONF, "eventfd support is not available in AIO subsystem"); -} - -static void overflow_poll_test(int evfd) -{ - tst_resm(TCONF, "eventfd support is not available in AIO subsystem"); -} - -static void overflow_read_test(int evfd) -{ - tst_resm(TCONF, "eventfd support is not available in AIO subsystem"); -} -#endif - -int main(int argc, char **argv) -{ - int lc; - int fd; - - tst_parse_opts(argc, argv, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - int ret; - uint64_t einit = 10; - - tst_count = 0; - - fd = myeventfd(einit, 0); - if (fd == -1) - tst_brkm(TBROK | TERRNO, CLEANUP, - "error creating eventfd"); - - ret = fcntl(fd, F_SETFL, O_NONBLOCK); - if (ret == -1) - tst_brkm(TBROK | TERRNO, CLEANUP, - "error setting non-block mode"); - - read_test(fd, einit); - read_eagain_test(fd); - write_test(fd); - write_eagain_test(fd); - read_einval_test(fd); - write_einval_test(fd); - write_einval2_test(fd); - readfd_set_test(fd); - readfd_not_set_test(fd); - writefd_set_test(fd); - writefd_not_set_test(fd); - child_inherit_test(fd); - overflow_select_test(fd); - overflow_poll_test(fd); - overflow_read_test(fd); - - close(fd); - } - - cleanup(); - - tst_exit(); -} - -static void setup(void) -{ - - tst_sig(FORK, DEF_HANDLER, cleanup); - - tst_tmpdir(); - - TEST_PAUSE; -} - -static void cleanup(void) -{ - tst_rmdir(); -} - -#else -int main(void) -{ - tst_brkm(TCONF, NULL, "test requires libaio and it's development packages"); -} -#endif +static struct tst_test test = { + .test_all = run, + .needs_kconfigs = (const char *[]) { + "CONFIG_EVENTFD", + NULL + }, +}; diff --git a/testcases/kernel/syscalls/eventfd/eventfd02.c b/testcases/kernel/syscalls/eventfd/eventfd02.c new file mode 100644 index 000000000..f028961c7 --- /dev/null +++ b/testcases/kernel/syscalls/eventfd/eventfd02.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) 2008 Vijay Kumar B. <vijaykumar@bravegnu.org> + * Copyright (c) Linux Test Project, 2008-2022 + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +/*\ + * [Description] + * + * Verify write operation for eventfd fail with: + * + * - EAGAIN when counter is zero on non blocking fd + * - EINVAL when buffer size is less than 8 bytes, or if an attempt is made to + * write the value 0xffffffffffffffff + */ + +#include <stdlib.h> +#include <sys/eventfd.h> +#include "tst_test.h" + +static void run(void) +{ + int fd; + uint64_t val = 12; + uint64_t buf; + uint32_t invalid; + + fd = TST_EXP_FD(eventfd(0, EFD_NONBLOCK)); + + SAFE_WRITE(0, fd, &val, sizeof(val)); + SAFE_READ(0, fd, &buf, sizeof(buf)); + TST_EXP_EQ_LI(buf, val); + + val = UINT64_MAX - 1; + SAFE_WRITE(0, fd, &val, sizeof(val)); + TST_EXP_FAIL(write(fd, &val, sizeof(val)), EAGAIN); + TST_EXP_FAIL(write(fd, &invalid, sizeof(invalid)), EINVAL); + + val = 0xffffffffffffffffLL; + TST_EXP_FAIL(write(fd, &val, sizeof(val)), EINVAL); + + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .test_all = run, + .needs_kconfigs = (const char *[]) { + "CONFIG_EVENTFD", + NULL + }, +}; diff --git a/testcases/kernel/syscalls/eventfd/eventfd03.c b/testcases/kernel/syscalls/eventfd/eventfd03.c new file mode 100644 index 000000000..452264cad --- /dev/null +++ b/testcases/kernel/syscalls/eventfd/eventfd03.c @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) 2008 Vijay Kumar B. <vijaykumar@bravegnu.org> + * Copyright (c) Linux Test Project, 2008-2022 + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +/*\ + * [Description] + * + * Test whether readfd is set by select() when eventfd() counter value is + * non-zero, then check if readfd is not set when eventfd() counter value is + * zero. + */ + +#include <stdlib.h> +#include <sys/eventfd.h> +#include "tst_test.h" + +static void run(void) +{ + int fd; + uint64_t val; + fd_set readfds; + uint64_t non_zero = 10; + struct timeval timeout = { 0, 0 }; + + fd = TST_EXP_FD(eventfd(0, EFD_NONBLOCK)); + + FD_ZERO(&readfds); + FD_SET(fd, &readfds); + + SAFE_WRITE(0, fd, &non_zero, sizeof(non_zero)); + TEST(select(fd + 1, &readfds, NULL, NULL, &timeout)); + if (TST_RET == -1) + tst_brk(TBROK | TERRNO, "select"); + + TST_EXP_EQ_LI(FD_ISSET(fd, &readfds), 1); + + SAFE_READ(0, fd, &val, sizeof(val)); + TEST(select(fd + 1, &readfds, NULL, NULL, &timeout)); + if (TST_RET == -1) + tst_brk(TBROK | TERRNO, "select"); + + TST_EXP_EQ_LI(FD_ISSET(fd, &readfds), 0); + + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .test_all = run, + .needs_kconfigs = (const char *[]) { + "CONFIG_EVENTFD", + NULL + }, +}; diff --git a/testcases/kernel/syscalls/eventfd/eventfd04.c b/testcases/kernel/syscalls/eventfd/eventfd04.c new file mode 100644 index 000000000..c7186ae64 --- /dev/null +++ b/testcases/kernel/syscalls/eventfd/eventfd04.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) 2008 Vijay Kumar B. <vijaykumar@bravegnu.org> + * Copyright (c) Linux Test Project, 2008-2022 + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +/*\ + * [Description] + * + * Test whether writefd is set by select() when eventfd() counter value is + * not the maximum value, then check if writefd is not set when eventfd() + * counter value is maximum value. + */ + +#include <stdlib.h> +#include <sys/eventfd.h> +#include "tst_test.h" + +static void run(void) +{ + int fd; + fd_set writefds; + uint64_t val; + uint64_t non_max = 10; + uint64_t max = UINT64_MAX - 1; + struct timeval timeout = { 0, 0 }; + + fd = TST_EXP_FD(eventfd(0, EFD_NONBLOCK)); + + FD_ZERO(&writefds); + FD_SET(fd, &writefds); + + SAFE_WRITE(0, fd, &non_max, sizeof(non_max)); + TEST(select(fd + 1, NULL, &writefds, NULL, &timeout)); + if (TST_RET == -1) + tst_brk(TBROK | TERRNO, "select"); + + TST_EXP_EQ_LI(FD_ISSET(fd, &writefds), 1); + + SAFE_READ(0, fd, &val, sizeof(val)); + SAFE_WRITE(0, fd, &max, sizeof(max)); + + TEST(select(fd + 1, NULL, &writefds, NULL, &timeout)); + if (TST_RET == -1) + tst_brk(TBROK | TERRNO, "select"); + + TST_EXP_EQ_LI(FD_ISSET(fd, &writefds), 0); + + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .test_all = run, + .needs_kconfigs = (const char *[]) { + "CONFIG_EVENTFD", + NULL + }, +}; diff --git a/testcases/kernel/syscalls/eventfd/eventfd05.c b/testcases/kernel/syscalls/eventfd/eventfd05.c new file mode 100644 index 000000000..6ea2c4138 --- /dev/null +++ b/testcases/kernel/syscalls/eventfd/eventfd05.c @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) 2008 Vijay Kumar B. <vijaykumar@bravegnu.org> + * Copyright (c) Linux Test Project, 2008-2022 + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +/*\ + * [Description] + * + * Test whether eventfd() counter update in child is reflected in the parent. + */ + +#include <stdlib.h> +#include <sys/eventfd.h> +#include "tst_test.h" + +static void run(void) +{ + int fd; + uint64_t val; + uint64_t to_parent = 0xdeadbeef; + + fd = TST_EXP_FD(eventfd(0, EFD_NONBLOCK)); + + if (!SAFE_FORK()) { + SAFE_WRITE(0, fd, &to_parent, sizeof(to_parent)); + exit(0); + } + + tst_reap_children(); + + SAFE_READ(0, fd, &val, sizeof(val)); + TST_EXP_EQ_LI(val, to_parent); + + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .test_all = run, + .forks_child = 1, + .needs_kconfigs = (const char *[]) { + "CONFIG_EVENTFD", + NULL + }, +}; diff --git a/testcases/kernel/syscalls/eventfd/eventfd06.c b/testcases/kernel/syscalls/eventfd/eventfd06.c new file mode 100644 index 000000000..7339dd471 --- /dev/null +++ b/testcases/kernel/syscalls/eventfd/eventfd06.c @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) 2008 Vijay Kumar B. <vijaykumar@bravegnu.org> + * Copyright (c) Linux Test Project, 2008-2022 + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +/*\ + * [Description] + * + * Test whether counter overflow is detected and handled correctly. + * + * It is not possible to directly overflow the counter using the + * write() syscall. Overflows occur when the counter is incremented + * from kernel space, in an IRQ context, when it is not possible to + * block the calling thread of execution. + * + * The AIO subsystem internally uses eventfd mechanism for + * notification of completion of read or write requests. In this test + * we trigger a counter overflow, by setting the counter value to the + * max possible value initially. When the AIO subsystem notifies + * through the eventfd counter, the counter overflows. + * + * If the counter starts from an initial value of 0, it will + * take decades for an overflow to occur. But since we set the initial + * value to the max possible counter value, we are able to cause it to + * overflow with a single increment. + * + * When the counter overflows, the following is tested: + * + * - POLLERR event occurs in poll() for the eventfd + * - readfd_set/writefd_set is set in select() for the eventfd + * - the counter value is UINT64_MAX + */ + +#include "tst_test.h" + +#ifdef HAVE_LIBAIO +#ifdef HAVE_IO_SET_EVENTFD + +#include <poll.h> +#include <libaio.h> +#include <stdlib.h> +#include <sys/eventfd.h> + +#define MAXEVENTS 16 +#define BUFSIZE 1024 + +static int fd; +static int evfd; +static io_context_t ctx; + +static void async_write(void) +{ + struct iocb iocb; + struct iocb *iocbap[1]; + struct io_event ioev; + static char buf[BUFSIZE]; + + memset(buf, 1, BUFSIZE); + + io_prep_pwrite(&iocb, fd, buf, sizeof(buf), 0); + io_set_eventfd(&iocb, evfd); + + iocbap[0] = &iocb; + TEST(io_submit(ctx, 1, iocbap)); + if (TST_RET < 0) + tst_brk(TBROK, "io_submit() failed: %s", tst_strerrno(-TST_RET)); + + TEST(io_getevents(ctx, 1, 1, &ioev, NULL)); + if (TST_RET < 0) + tst_brk(TBROK, "io_getevents() failed: %s", tst_strerrno(-TST_RET)); +} + +static void clear_counter(void) +{ + uint64_t val; + uint64_t max = UINT64_MAX - 1; + + TEST(read(evfd, &val, sizeof(val))); + if (TST_RET == -1 && TST_ERR != EAGAIN) + tst_brk(TBROK | TERRNO, "read"); + + SAFE_WRITE(0, evfd, &max, sizeof(max)); +} + +static void test_select(void) +{ + fd_set readfds; + uint64_t count; + struct timeval timeout = { 10, 0 }; + + clear_counter(); + async_write(); + + FD_ZERO(&readfds); + FD_SET(fd, &readfds); + + tst_res(TINFO, "Checking if select() detects counter overflow"); + + TEST(select(fd + 1, NULL, &readfds, NULL, &timeout)); + if (TST_RET == -1) + tst_brk(TBROK | TERRNO, "select"); + + TST_EXP_EQ_LI(FD_ISSET(fd, &readfds), 1); + + SAFE_READ(0, evfd, &count, sizeof(count)); + TST_EXP_EQ_LI(count, UINT64_MAX); +} + +static void test_poll(void) +{ + uint64_t count; + struct pollfd pollfd; + + clear_counter(); + async_write(); + + pollfd.fd = evfd; + pollfd.events = POLLIN; + pollfd.revents = 0; + + tst_res(TINFO, "Checking if poll() detects counter overflow"); + + TEST(poll(&pollfd, 1, 10000)); + if (TST_RET == -1) + tst_brk(TBROK | TERRNO, "poll"); + + TST_EXP_EQ_LI(pollfd.revents & POLLERR, POLLERR); + + SAFE_READ(0, evfd, &count, sizeof(count)); + TST_EXP_EQ_LI(count, UINT64_MAX); +} + +static void setup(void) +{ + TEST(io_setup(MAXEVENTS, &ctx)); + if (TST_RET < 0) + tst_brk(TBROK, "io_setup() failed: %s", tst_strerrno(-TST_RET)); + + fd = SAFE_OPEN("testfile", O_RDWR | O_CREAT, 0644); + evfd = TST_EXP_FD(eventfd(0, EFD_NONBLOCK)); +} + +static void cleanup(void) +{ + SAFE_CLOSE(evfd); + io_destroy(ctx); +} + +static void run(void) +{ + test_select(); + test_poll(); +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .needs_tmpdir = 1, + .needs_kconfigs = (const char *[]) { + "CONFIG_EVENTFD", + NULL + }, +}; + +#else /* HAVE_IO_SET_EVENTFD */ +TST_TEST_TCONF("eventfd support is not available in AIO subsystem"); +#endif +#else /* HAVE_LIBAIO */ +TST_TEST_TCONF("libaio is not available"); +#endif diff --git a/testcases/kernel/syscalls/eventfd2/eventfd2.h b/testcases/kernel/syscalls/eventfd2/eventfd2.h new file mode 100644 index 000000000..5350820b8 --- /dev/null +++ b/testcases/kernel/syscalls/eventfd2/eventfd2.h @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +#include "tst_test.h" +#include "lapi/syscalls.h" + +static inline int eventfd2(unsigned int count, unsigned int flags) +{ + int ret; + + ret = tst_syscall(__NR_eventfd2, count, flags); + if (ret == -1) + tst_brk(TBROK | TERRNO, "eventfd2"); + + return ret; +} diff --git a/testcases/kernel/syscalls/eventfd2/eventfd2_01.c b/testcases/kernel/syscalls/eventfd2/eventfd2_01.c index 85ad86d42..3a80379a3 100644 --- a/testcases/kernel/syscalls/eventfd2/eventfd2_01.c +++ b/testcases/kernel/syscalls/eventfd2/eventfd2_01.c @@ -1,119 +1,37 @@ -/******************************************************************************/ -/* */ -/* Copyright (c) Ulrich Drepper <drepper@redhat.com> */ -/* Copyright (c) International Business Machines Corp., 2009 */ -/* */ -/* 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 */ -/* */ -/******************************************************************************/ -/******************************************************************************/ -/* */ -/* File: eventfd2_01.c */ -/* */ -/* Description: This Program tests the new system call introduced in 2.6.27. */ -/* Ulrich´s comment as in: */ -/* http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=b087498eb5605673b0f260a7620d91818cd72304 */ -/* says: */ -/* This patch adds the new eventfd2 syscall. It extends the old eventfd */ -/* syscall by one parameter which is meant to hold a flag value. In this */ -/* patch the only flag support is EFD_CLOEXEC which causes the close-on-exec */ -/* flag for the returned file descriptor to be set. A new name EFD_CLOEXEC is */ -/* introduced which in this implementation must have the same value as */ -/* O_CLOEXEC. The following test must be adjusted for architectures other than*/ -/* x86 and x86-64 and in case the syscall numbers changed. */ -/* */ -/* Usage: <for command-line> */ -/* eventfd2_01 [-c n] [-e][-i n] [-I x] [-p x] [-t] */ -/* where, -c n : Run n copies concurrently. */ -/* -e : Turn on errno logging. */ -/* -i n : Execute test n times. */ -/* -I x : Execute test for x seconds. */ -/* -P x : Pause for x seconds between iterations. */ -/* -t : Turn on syscall timing. */ -/* */ -/* Total Tests: 1 */ -/* */ -/* Test Name: eventfd2_01 */ -/* */ -/* Author: Ulrich Drepper <drepper@redhat.com> */ -/* */ -/* History: Created - Jan 08 2009 - Ulrich Drepper <drepper@redhat.com> */ -/* Ported to LTP */ -/* - Jan 08 2009 - Subrata <subrata@linux.vnet.ibm.com> */ -/******************************************************************************/ -#include <stdio.h> -#include <unistd.h> -#include <sys/syscall.h> -#include <errno.h> - -#include "test.h" -#include "lapi/fcntl.h" -#include "lapi/syscalls.h" - -#define EFD_CLOEXEC O_CLOEXEC - -char *TCID = "eventfd2_01"; -int testno; -int TST_TOTAL = 1; - -void cleanup(void) +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) Ulrich Drepper <drepper@redhat.com> + * Copyright (c) International Business Machines Corp., 2009 + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +/*\ + * [Description] + * + * This test verifies that eventfd2 correctly set FD_CLOEXEC flag on file when + * EFD_CLOEXEC flag is used. + */ + +#include <fcntl.h> +#include <sys/eventfd.h> +#include "tst_test.h" +#include "eventfd2.h" + +static void run(void) { - tst_rmdir(); -} + int fd, flags; -void setup(void) -{ - TEST_PAUSE; - tst_tmpdir(); -} + fd = eventfd2(1, 0); + flags = SAFE_FCNTL(fd, F_GETFD); + TST_EXP_EXPR(!(flags & FD_CLOEXEC), "FD_CLOEXEC is not set"); + SAFE_CLOSE(fd); -int main(int argc, char *argv[]) -{ - int fd, coe; - - tst_parse_opts(argc, argv, NULL, NULL); - - setup(); - - fd = tst_syscall(__NR_eventfd2, 1, 0); - if (fd == -1) { - tst_brkm(TFAIL, cleanup, "eventfd2(0) failed"); - } - coe = fcntl(fd, F_GETFD); - if (coe == -1) { - tst_brkm(TBROK, cleanup, "fcntl failed"); - } - if (coe & FD_CLOEXEC) { - tst_brkm(TFAIL, cleanup, "eventfd2(0) set close-on-exec flag"); - } - close(fd); - - fd = tst_syscall(__NR_eventfd2, 1, EFD_CLOEXEC); - if (fd == -1) { - tst_brkm(TFAIL, cleanup, "eventfd2(EFD_CLOEXEC) failed"); - } - coe = fcntl(fd, F_GETFD); - if (coe == -1) { - tst_brkm(TBROK, cleanup, "fcntl failed"); - } - if ((coe & FD_CLOEXEC) == 0) { - tst_brkm(TFAIL, cleanup, - "eventfd2(EFD_CLOEXEC) does not set close-on-exec flag"); - } - close(fd); - tst_resm(TPASS, "eventfd2(EFD_CLOEXEC) Passed"); - cleanup(); - tst_exit(); + fd = eventfd2(1, EFD_CLOEXEC); + flags = SAFE_FCNTL(fd, F_GETFD); + TST_EXP_EXPR((flags & FD_CLOEXEC), "FD_CLOEXEC is set"); + SAFE_CLOSE(fd); } + +static struct tst_test test = { + .test_all = run, +}; diff --git a/testcases/kernel/syscalls/eventfd2/eventfd2_02.c b/testcases/kernel/syscalls/eventfd2/eventfd2_02.c index 5f3b6ee67..430cdb33c 100644 --- a/testcases/kernel/syscalls/eventfd2/eventfd2_02.c +++ b/testcases/kernel/syscalls/eventfd2/eventfd2_02.c @@ -1,118 +1,37 @@ -/******************************************************************************/ -/* */ -/* Copyright (c) Ulrich Drepper <drepper@redhat.com> */ -/* Copyright (c) International Business Machines Corp., 2009 */ -/* */ -/* 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 */ -/* */ -/******************************************************************************/ -/******************************************************************************/ -/* */ -/* File: eventfd2_02.c */ -/* */ -/* Description: This Program tests the new system call introduced in 2.6.27. */ -/* Ulrich´s comment as in: */ -/* http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=e7d476dfdf0bcfed478a207aecfdc84f81efecaf */ -/* which says: */ -/* This patch adds support for the EFD_NONBLOCK flag to eventfd2. The */ -/* additional changes needed are minimal. The following test must be adjusted */ -/* or architectures other than x86 and x86-64 and in case the syscall numbers */ -/* changed. */ -/* */ -/* Usage: <for command-line> */ -/* eventfd2_02 [-c n] [-e][-i n] [-I x] [-p x] [-t] */ -/* where, -c n : Run n copies concurrently. */ -/* -e : Turn on errno logging. */ -/* -i n : Execute test n times. */ -/* -I x : Execute test for x seconds. */ -/* -P x : Pause for x seconds between iterations. */ -/* -t : Turn on syscall timing. */ -/* */ -/* Total Tests: 1 */ -/* */ -/* Test Name: eventfd2_02 */ -/* */ -/* Author: Ulrich Drepper <drepper@redhat.com> */ -/* */ -/* History: Created - Jan 13 2009 - Ulrich Drepper <drepper@redhat.com> */ -/* Ported to LTP */ -/* - Jan 13 2009 - Subrata <subrata@linux.vnet.ibm.com> */ -/******************************************************************************/ -#include <stdio.h> -#include <unistd.h> -#include <sys/syscall.h> -#include <errno.h> - -#include "test.h" -#include "lapi/fcntl.h" -#include "lapi/syscalls.h" - -#define EFD_NONBLOCK O_NONBLOCK - -char *TCID = "eventfd2_02"; -int testno; -int TST_TOTAL = 1; - -void cleanup(void) -{ - tst_rmdir(); -} - -void setup(void) +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) Ulrich Drepper <drepper@redhat.com> + * Copyright (c) International Business Machines Corp., 2009 + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +/*\ + * [Description] + * + * This test verifies that eventfd2 correctly set O_NONBLOCK flag on file when + * EFD_NONBLOCK flag is used. + */ + +#include <fcntl.h> +#include <sys/eventfd.h> +#include "tst_test.h" +#include "eventfd2.h" + +static void run(void) { - TEST_PAUSE; - tst_tmpdir(); -} - -int main(int argc, char *argv[]) -{ - int fd, fl; - - tst_parse_opts(argc, argv, NULL, NULL); + int fd, flags; - setup(); + fd = eventfd2(1, 0); + flags = SAFE_FCNTL(fd, F_GETFL); + TST_EXP_EXPR(!(flags & O_NONBLOCK), "O_NONBLOCK is not set"); + SAFE_CLOSE(fd); - tst_count = 0; - fd = tst_syscall(__NR_eventfd2, 1, 0); - if (fd == -1) { - tst_brkm(TFAIL, cleanup, "eventfd2(0) failed"); - } - fl = fcntl(fd, F_GETFL); - if (fl == -1) { - tst_brkm(TBROK, cleanup, "fcntl failed"); - } - if (fl & O_NONBLOCK) { - tst_brkm(TFAIL, cleanup, "eventfd2(0) sets non-blocking mode"); - } - close(fd); - - fd = tst_syscall(__NR_eventfd2, 1, EFD_NONBLOCK); - if (fd == -1) { - tst_brkm(TFAIL, cleanup, "eventfd2(EFD_NONBLOCK) failed"); - } - fl = fcntl(fd, F_GETFL); - if (fl == -1) { - tst_brkm(TBROK, cleanup, "fcntl failed"); - } - if ((fl & O_NONBLOCK) == 0) { - tst_brkm(TFAIL, cleanup, - "eventfd2(EFD_NONBLOCK) didn't set non-blocking mode"); - } - close(fd); - tst_resm(TPASS, "eventfd2(EFD_NONBLOCK) PASSED"); - - cleanup(); - tst_exit(); + fd = eventfd2(1, EFD_NONBLOCK); + flags = SAFE_FCNTL(fd, F_GETFL); + TST_EXP_EXPR((flags & O_NONBLOCK), "O_NONBLOCK is set"); + SAFE_CLOSE(fd); } + +static struct tst_test test = { + .test_all = run, +}; diff --git a/testcases/kernel/syscalls/eventfd2/eventfd2_03.c b/testcases/kernel/syscalls/eventfd2/eventfd2_03.c index 909004edb..e1949fd32 100644 --- a/testcases/kernel/syscalls/eventfd2/eventfd2_03.c +++ b/testcases/kernel/syscalls/eventfd2/eventfd2_03.c @@ -1,139 +1,81 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * eventfd-sem by Davide Libenzi (Simple test for eventfd sempahore) - * Copyright (C) 2009 Davide Libenzi - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Davide Libenzi <davidel@xmailserver.org> - * Reference: http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=bcd0b235bf3808dec5115c381cd55568f63b85f0 - * Reference: http://www.xmailserver.org/eventfd-sem.c - * eventfd: testing improved support for semaphore-like behavior in linux-2.6.30 + * Copyright (c) Ulrich Drepper <drepper@redhat.com> + * Copyright (c) International Business Machines Corp., 2009 + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +/*\ + * [Description] * + * This test verifies that eventfd2 semaphore-like support is properly working. */ -#include <sys/types.h> -#include <sys/syscall.h> -#include <sys/stat.h> -#include <sys/wait.h> #include <fcntl.h> #include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <errno.h> -#include <inttypes.h> - -#include "test.h" -#include "lapi/syscalls.h" - -char *TCID = "eventfd2_03"; -int TST_TOTAL = 1; - -#ifndef EFD_SEMLIKE -#define EFD_SEMLIKE (1 << 0) -#endif - -/* Dummy function as syscall from linux_syscall_numbers.h uses cleanup(). */ -void cleanup(void) -{ -} - -static int eventfd2(int count, int flags) -{ - return tst_syscall(__NR_eventfd2, count, flags); -} +#include <sys/eventfd.h> +#include "tst_test.h" +#include "eventfd2.h" static void xsem_wait(int fd) { u_int64_t cntr; - if (read(fd, &cntr, sizeof(cntr)) != sizeof(cntr)) { - perror("reading eventfd"); - exit(1); - } - fprintf(stdout, "[%u] wait completed on %d: count=%" PRIu64 "\n", - getpid(), fd, cntr); + SAFE_READ(0, fd, &cntr, sizeof(cntr)); } static void xsem_post(int fd, int count) { u_int64_t cntr = count; - if (write(fd, &cntr, sizeof(cntr)) != sizeof(cntr)) { - perror("writing eventfd"); - exit(1); - } + SAFE_WRITE(0, fd, &cntr, sizeof(cntr)); } static void sem_player(int fd1, int fd2) { - fprintf(stdout, "[%u] posting 1 on %d\n", getpid(), fd1); - xsem_post(fd1, 1); + pid_t pid = getpid(); - fprintf(stdout, "[%u] waiting on %d\n", getpid(), fd2); - xsem_wait(fd2); - - fprintf(stdout, "[%u] posting 1 on %d\n", getpid(), fd1); + tst_res(TINFO, "[%u] posting 1 on fd=%d", pid, fd1); xsem_post(fd1, 1); - fprintf(stdout, "[%u] waiting on %d\n", getpid(), fd2); + tst_res(TINFO, "[%u] waiting on fd=%d", pid, fd2); xsem_wait(fd2); - fprintf(stdout, "[%u] posting 5 on %d\n", getpid(), fd1); + tst_res(TINFO, "[%u] posting 5 on fd=%d", pid, fd1); xsem_post(fd1, 5); - fprintf(stdout, "[%u] waiting 5 times on %d\n", getpid(), fd2); + tst_res(TINFO, "[%u] waiting 5 times on fd=%d", pid, fd2); xsem_wait(fd2); xsem_wait(fd2); xsem_wait(fd2); xsem_wait(fd2); xsem_wait(fd2); -} -static void usage(char const *prg) -{ - fprintf(stderr, "use: %s [-h]\n", prg); + tst_res(TPASS, "[%u] received all events", pid); } -int main(int argc, char **argv) +static void run(void) { - int c, fd1, fd2, status; pid_t cpid_poster, cpid_waiter; + int fd1, fd2; - while ((c = getopt(argc, argv, "h")) != -1) { - switch (c) { - default: - usage(argv[0]); - return 1; - } - } - if ((fd1 = eventfd2(0, EFD_SEMLIKE)) == -1 || - (fd2 = eventfd2(0, EFD_SEMLIKE)) == -1) { - perror("eventfd2"); - return 1; - } - if ((cpid_poster = fork()) == 0) { + fd1 = eventfd2(0, EFD_SEMAPHORE); + fd2 = eventfd2(0, EFD_SEMAPHORE); + + cpid_poster = SAFE_FORK(); + if (!cpid_poster) { sem_player(fd1, fd2); exit(0); } - if ((cpid_waiter = fork()) == 0) { + + cpid_waiter = SAFE_FORK(); + if (!cpid_waiter) { sem_player(fd2, fd1); exit(0); } - waitpid(cpid_poster, &status, 0); - waitpid(cpid_waiter, &status, 0); - - tst_exit(); } + +static struct tst_test test = { + .test_all = run, + .forks_child = 1, +}; diff --git a/testcases/kernel/syscalls/execve/execve01.c b/testcases/kernel/syscalls/execve/execve01.c index 2b12c7666..53f0475e3 100644 --- a/testcases/kernel/syscalls/execve/execve01.c +++ b/testcases/kernel/syscalls/execve/execve01.c @@ -34,7 +34,7 @@ static void verify_execve(void) pid = SAFE_FORK(); if (pid == 0) { execve(path, args, envp); - tst_brk(TFAIL | TERRNO, "Failed to execute execl01_child"); + tst_brk(TFAIL | TERRNO, "Failed to execute execve01_child"); } } diff --git a/testcases/kernel/syscalls/execve/execve06.c b/testcases/kernel/syscalls/execve/execve06.c index afbfcfa9e..a00089265 100644 --- a/testcases/kernel/syscalls/execve/execve06.c +++ b/testcases/kernel/syscalls/execve/execve06.c @@ -35,7 +35,7 @@ static void verify_execve(void) pid = SAFE_FORK(); if (pid == 0) { execve(path, argv, envp); - tst_brk(TFAIL | TERRNO, "Failed to execute execl01_child"); + tst_brk(TFAIL | TERRNO, "Failed to execute execve06_child"); } } diff --git a/testcases/kernel/syscalls/faccessat/.gitignore b/testcases/kernel/syscalls/faccessat/.gitignore index 9551ab97e..276caca45 100644 --- a/testcases/kernel/syscalls/faccessat/.gitignore +++ b/testcases/kernel/syscalls/faccessat/.gitignore @@ -1 +1,2 @@ /faccessat01 +/faccessat02 diff --git a/testcases/kernel/syscalls/faccessat/faccessat01.c b/testcases/kernel/syscalls/faccessat/faccessat01.c index d11e8cf12..557d7eb4c 100644 --- a/testcases/kernel/syscalls/faccessat/faccessat01.c +++ b/testcases/kernel/syscalls/faccessat/faccessat01.c @@ -1,151 +1,88 @@ -/****************************************************************************** +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) International Business Machines Corp., 2006 + * Copyright (c) Linux Test Project, 2003-2023 + * Author: Yi Yang <yyangcdl@cn.ibm.com> + */ + +/*\ + * [Description] * - * Copyright (c) International Business Machines Corp., 2006 + * Check the basic functionality of the faccessat() system call. * - * 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. + * - faccessat() passes if dir_fd is file descriptor to the directory + * where the file is located and pathname is relative path of the file. * - * 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. + * - faccessat() passes if dir_fd is a bad file descriptor and pathname is + * absolute path of the file. * - * 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 - * - * NAME - * faccessat01.c - * - * DESCRIPTION - * This test case will verify basic function of faccessat - * added by kernel 2.6.16 or up. - * - * Author - * Yi Yang <yyangcdl@cn.ibm.com> - * - * History - * 08/28/2006 Created first by Yi Yang <yyangcdl@cn.ibm.com> - * - *****************************************************************************/ - -#define _GNU_SOURCE + * - faccessat() passes if dir_fd is AT_FDCWD and pathname is interpreted + * relative to the current working directory of the calling process. + */ -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> #include <stdlib.h> -#include <errno.h> -#include <string.h> -#include <signal.h> -#include "test.h" -#include "safe_macros.h" -#include "lapi/syscalls.h" - -#define TEST_CASES 6 -#ifndef AT_FDCWD -#define AT_FDCWD -100 -#endif -void setup(); -void cleanup(); - -char *TCID = "faccessat01"; -int TST_TOTAL = TEST_CASES; -static char pathname[256]; -static char testfile[256]; -static char testfile2[256]; -static char testfile3[256]; -static int fds[TEST_CASES]; -static char *filenames[TEST_CASES]; -static int expected_errno[TEST_CASES] = { 0, 0, ENOTDIR, EBADF, 0, 0 }; - -int myfaccessat(int dirfd, const char *filename, int mode) +#include <stdio.h> +#include "tst_test.h" + +#define TESTDIR "faccessatdir" +#define TESTFILE "faccessatfile" +#define FILEPATH "faccessatdir/faccessatfile" + +static int dir_fd, file_fd; +static int atcwd_fd = AT_FDCWD; +static char *abs_path; +static char *test_file; +static char *file_path; + +static struct tcase { + int *fd; + char **filename; + int exp_errno; +} tcases[] = { + {&dir_fd, &test_file, 0}, + {&dir_fd, &abs_path, 0}, + {&atcwd_fd, &file_path, 0}, +}; + +static void verify_faccessat(unsigned int i) { - return tst_syscall(__NR_faccessat, dirfd, filename, mode); -} - -int main(int ac, char **av) -{ - int lc; - int i; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); + struct tcase *tc = &tcases[i]; - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - - /* - * Call faccessat - */ - for (i = 0; i < TST_TOTAL; i++) { - TEST(myfaccessat(fds[i], filenames[i], R_OK)); - - /* check return code */ - if (TEST_ERRNO == expected_errno[i]) { - tst_resm(TPASS, - "faccessat() returned the expected errno %d: %s", - TEST_ERRNO, - strerror(TEST_ERRNO)); - } else { - tst_resm(TFAIL, - "faccessdat() Failed, errno=%d : %s", - TEST_ERRNO, strerror(TEST_ERRNO)); - } - } - } - - cleanup(); - tst_exit(); + TST_EXP_PASS(faccessat(*tc->fd, *tc->filename, R_OK, 0), + "faccessat(%d, %s, R_OK, 0)", + *tc->fd, *tc->filename); } -void setup(void) +static void setup(void) { - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - tst_tmpdir(); - - char *abs_path = tst_get_tmpdir(); - int p = getpid(); - - /* Initialize test dir and file names */ - sprintf(pathname, "faccessattestdir%d", p); - sprintf(testfile, "faccessattestfile%d.txt", p); - sprintf(testfile2, "%s/faccessattestfile%d.txt", abs_path, p); - sprintf(testfile3, "faccessattestdir%d/faccessattestfile%d.txt", p, p); - - free(abs_path); + char *tmpdir_path = tst_get_tmpdir(); - SAFE_MKDIR(cleanup, pathname, 0700); + abs_path = tst_aprintf("%s/%s", tmpdir_path, FILEPATH); + free(tmpdir_path); - fds[0] = SAFE_OPEN(cleanup, pathname, O_DIRECTORY); - fds[1] = fds[4] = fds[0]; - - SAFE_FILE_PRINTF(cleanup, testfile, "%s", testfile); - SAFE_FILE_PRINTF(cleanup, testfile2, "%s", testfile2); - - fds[2] = SAFE_OPEN(cleanup, testfile3, O_CREAT | O_RDWR, 0600); - - fds[3] = 100; - fds[5] = AT_FDCWD; - - filenames[0] = filenames[2] = filenames[3] = filenames[4] = testfile; - filenames[1] = testfile2; - filenames[5] = testfile3; - - TEST_PAUSE; + SAFE_MKDIR(TESTDIR, 0700); + dir_fd = SAFE_OPEN(TESTDIR, O_DIRECTORY); + file_fd = SAFE_OPEN(FILEPATH, O_CREAT | O_RDWR, 0600); } -void cleanup(void) +static void cleanup(void) { - if (fds[0] > 0) - close(fds[0]); - if (fds[2] > 0) - close(fds[2]); + if (dir_fd > -1) + SAFE_CLOSE(dir_fd); - tst_rmdir(); + if (file_fd > -1) + SAFE_CLOSE(file_fd); } + +static struct tst_test test = { + .test = verify_faccessat, + .tcnt = ARRAY_SIZE(tcases), + .setup = setup, + .cleanup = cleanup, + .bufs = (struct tst_buffers []) { + {&test_file, .str = TESTFILE}, + {&file_path, .str = FILEPATH}, + {}, + }, + .needs_tmpdir = 1, +}; diff --git a/testcases/kernel/syscalls/faccessat/faccessat02.c b/testcases/kernel/syscalls/faccessat/faccessat02.c new file mode 100644 index 000000000..1add695c1 --- /dev/null +++ b/testcases/kernel/syscalls/faccessat/faccessat02.c @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) International Business Machines Corp., 2006 + * Copyright (c) Linux Test Project, 2003-2023 + * Author: Yi Yang <yyangcdl@cn.ibm.com> + */ + +/*\ + * [Description] + * + * - faccessat() fails with ENOTDIR if dir_fd is file descriptor to the file + * and pathname is relative path of the file. + * + * - faccessat() fails with EBADF if dir_fd is invalid. + */ + +#include <stdlib.h> +#include <stdio.h> +#include "tst_test.h" + +#define TESTDIR "faccessatdir" +#define TESTFILE "faccessatfile" +#define FILEPATH "faccessatdir/faccessatfile" + +static int dir_fd, file_fd; +static int bad_fd = -1; + +static struct tcase { + int *fd; + int exp_errno; +} tcases[] = { + {&file_fd, ENOTDIR}, + {&bad_fd, EBADF}, +}; + +static void verify_faccessat(unsigned int i) +{ + struct tcase *tc = &tcases[i]; + + TST_EXP_FAIL(faccessat(*tc->fd, TESTFILE, R_OK, 0), + tc->exp_errno, "faccessat(%d, TESTFILE, R_OK, 0)", + *tc->fd); +} + +static void setup(void) +{ + SAFE_MKDIR(TESTDIR, 0700); + dir_fd = SAFE_OPEN(TESTDIR, O_DIRECTORY); + file_fd = SAFE_OPEN(FILEPATH, O_CREAT | O_RDWR, 0600); +} + +static void cleanup(void) +{ + if (dir_fd > -1) + SAFE_CLOSE(dir_fd); + + if (file_fd > -1) + SAFE_CLOSE(file_fd); +} + +static struct tst_test test = { + .test = verify_faccessat, + .tcnt = ARRAY_SIZE(tcases), + .setup = setup, + .cleanup = cleanup, + .needs_tmpdir = 1, +}; diff --git a/testcases/kernel/syscalls/faccessat2/.gitignore b/testcases/kernel/syscalls/faccessat2/.gitignore new file mode 100644 index 000000000..f58f045f4 --- /dev/null +++ b/testcases/kernel/syscalls/faccessat2/.gitignore @@ -0,0 +1,2 @@ +/faccessat201 +/faccessat202 diff --git a/testcases/kernel/syscalls/faccessat2/Makefile b/testcases/kernel/syscalls/faccessat2/Makefile new file mode 100644 index 000000000..aaac6b703 --- /dev/null +++ b/testcases/kernel/syscalls/faccessat2/Makefile @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2023 FUJITSU LIMITED. All rights reserved. +# Author: Yang Xu <xuyang2018.jy@fujitsu.com> + +top_srcdir ?= ../../../.. + +include $(top_srcdir)/include/mk/testcases.mk + +include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/syscalls/faccessat2/faccessat201.c b/testcases/kernel/syscalls/faccessat2/faccessat201.c new file mode 100644 index 000000000..012091752 --- /dev/null +++ b/testcases/kernel/syscalls/faccessat2/faccessat201.c @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 FUJITSU LIMITED. All rights reserved. + * Copyright (c) Linux Test Project, 2003-2023 + * Author: Yang Xu <xuyang2018.jy@fujitsu.com> + */ + +/*\ + * [Description] + * + * Check the basic functionality of faccessat2(). + * + * Minimum Linux version required is v5.8. + */ + +#include <stdlib.h> + +#include "tst_test.h" +#include "lapi/syscalls.h" +#include "lapi/faccessat.h" + +#define TESTDIR "faccessat2dir" +#define TESTFILE "faccessat2file" +#define RELPATH "faccessat2dir/faccessat2file" +#define TESTSYMLINK "faccessat2symlink" + +static int dir_fd, bad_fd = -1; +static int atcwd_fd = AT_FDCWD; +static char *testfile; +static char *abs_path; +static char *rel_path; +static char *sym_path; + +static struct tcase { + int *fd; + char **filename; + int flags; +} tcases[] = { + {&dir_fd, &testfile, 0}, + {&bad_fd, &abs_path, 0}, + {&atcwd_fd, &rel_path, 0}, + {&dir_fd, &testfile, AT_EACCESS}, + {&bad_fd, &abs_path, AT_EACCESS}, + {&atcwd_fd, &rel_path, AT_EACCESS}, + {&atcwd_fd, &sym_path, AT_SYMLINK_NOFOLLOW}, +}; + +static void verify_faccessat2(unsigned int i) +{ + struct tcase *tc = &tcases[i]; + + TST_EXP_PASS(faccessat2(*tc->fd, *tc->filename, R_OK, tc->flags), + "faccessat2(%d, %s, R_OK, %d)", + *tc->fd, *tc->filename, tc->flags); +} + +static void setup(void) +{ + char *tmpdir_path = tst_get_tmpdir(); + + abs_path = tst_aprintf("%s/%s", tmpdir_path, RELPATH); + free(tmpdir_path); + + SAFE_MKDIR(TESTDIR, 0777); + dir_fd = SAFE_OPEN(TESTDIR, O_DIRECTORY); + SAFE_TOUCH(abs_path, 0444, NULL); + SAFE_SYMLINK(abs_path, TESTSYMLINK); +} + +static void cleanup(void) +{ + if (dir_fd > -1) + SAFE_CLOSE(dir_fd); +} + +static struct tst_test test = { + .test = verify_faccessat2, + .tcnt = ARRAY_SIZE(tcases), + .setup = setup, + .cleanup = cleanup, + .bufs = (struct tst_buffers []) { + {&testfile, .str = TESTFILE}, + {&rel_path, .str = RELPATH}, + {&sym_path, .str = TESTSYMLINK}, + {}, + }, + .needs_tmpdir = 1, +}; diff --git a/testcases/kernel/syscalls/faccessat2/faccessat202.c b/testcases/kernel/syscalls/faccessat2/faccessat202.c new file mode 100644 index 000000000..a60db2bf8 --- /dev/null +++ b/testcases/kernel/syscalls/faccessat2/faccessat202.c @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 FUJITSU LIMITED. All rights reserved. + * Copyright (c) Linux Test Project, 2003-2023 + * Author: Yang Xu <xuyang2018.jy@fujitsu.com> + */ + +/*\ + * [Description] + * + * Test basic error handling of faccessat2 syscall: + * + * - faccessat2() fails with EFAULT if pathname is a bad pathname point. + * - faccessat2() fails with EINVAL if flags is -1. + * - faccessat2() fails with EINVAL if mode is -1. + * - faccessat2() fails with EBADF if dirfd is -1. + * - faccessat2() fails with ENOTDIR if pathname is relative path to a + * file and dir_fd is file descriptor for this file. + * - faccessat2() fails with EACCES if flags is AT_EACCESS and not using + * the effective user and group IDs. + * + * Minimum Linux version required is v5.8. + */ + +#include <pwd.h> + +#include "tst_test.h" +#include "lapi/syscalls.h" +#include "lapi/faccessat.h" + +#define TESTUSER "nobody" +#define TESTDIR "faccessat2dir" +#define RELPATH "faccessat2dir/faccessat2file" + +static int fd; +static int bad_fd = -1; +static int atcwd_fd = AT_FDCWD; +static char *bad_path; +static char *rel_path; + +static struct passwd *ltpuser; + +static struct tcase { + int *fd; + char **filename; + int mode; + int flags; + int exp_errno; + const char *desc; +} tcases[] = { + {&atcwd_fd, &bad_path, R_OK, 0, EFAULT, "invalid address"}, + {&atcwd_fd, &rel_path, R_OK, -1, EINVAL, "invalid flags"}, + {&atcwd_fd, &rel_path, -1, 0, EINVAL, "invalid mode"}, + {&bad_fd, &rel_path, R_OK, 0, EBADF, "invalid fd"}, + {&fd, &rel_path, R_OK, 0, ENOTDIR, "fd pointing to file"}, + {&atcwd_fd, &rel_path, R_OK, AT_EACCESS, EACCES, + "AT_EACCESS and unprivileged EUID"}, +}; + +static void verify_faccessat2(unsigned int i) +{ + struct tcase *tc = &tcases[i]; + + if (tc->exp_errno == EACCES) + SAFE_SETEUID(ltpuser->pw_uid); + + TST_EXP_FAIL(faccessat2(*tc->fd, *tc->filename, tc->mode, tc->flags), + tc->exp_errno, "faccessat2() with %s", tc->desc); + + if (tc->exp_errno == EACCES) + SAFE_SETEUID(0); +} + +static void setup(void) +{ + SAFE_MKDIR(TESTDIR, 0666); + SAFE_TOUCH(RELPATH, 0444, NULL); + + fd = SAFE_OPEN(RELPATH, O_RDONLY); + bad_path = tst_get_bad_addr(NULL); + + ltpuser = SAFE_GETPWNAM(TESTUSER); +} + +static void cleanup(void) +{ + if (fd > -1) + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .test = verify_faccessat2, + .tcnt = ARRAY_SIZE(tcases), + .setup = setup, + .cleanup = cleanup, + .bufs = (struct tst_buffers []) { + {&rel_path, .str = RELPATH}, + {}, + }, + .needs_tmpdir = 1, + .needs_root = 1, +}; diff --git a/testcases/kernel/syscalls/fanotify/fanotify.h b/testcases/kernel/syscalls/fanotify/fanotify.h index 51078103e..75a081dc9 100644 --- a/testcases/kernel/syscalls/fanotify/fanotify.h +++ b/testcases/kernel/syscalls/fanotify/fanotify.h @@ -72,6 +72,10 @@ static inline int safe_fanotify_mark(const char *file, const int lineno, #define MAX_HANDLE_SZ 128 #endif +#ifndef AT_HANDLE_FID +#define AT_HANDLE_FID 0x200 +#endif + /* * Helper function used to obtain fsid and file_handle for a given path. * Used by test files correlated to FAN_REPORT_FID functionality. @@ -260,10 +264,27 @@ static inline int fanotify_mark_supported_by_kernel(uint64_t flag) return rval; } +static inline int fanotify_handle_supported_by_kernel(int flag) +{ + /* + * On Kernel that does not support AT_HANDLE_FID this will result + * with EINVAL. On older kernels, this will result in EBADF. + */ + if (name_to_handle_at(-1, "", NULL, NULL, AT_EMPTY_PATH | flag)) { + if (errno == EINVAL) + return -1; + } + return 0; +} + #define REQUIRE_MARK_TYPE_SUPPORTED_BY_KERNEL(mark_type) \ fanotify_init_flags_err_msg(#mark_type, __FILE__, __LINE__, tst_brk_, \ fanotify_mark_supported_by_kernel(mark_type)) +#define REQUIRE_HANDLE_TYPE_SUPPORTED_BY_KERNEL(handle_type) \ + fanotify_init_flags_err_msg(#handle_type, __FILE__, __LINE__, tst_brk_, \ + fanotify_handle_supported_by_kernel(handle_type)) + #define REQUIRE_FANOTIFY_EVENTS_SUPPORTED_ON_FS(init_flags, mark_type, mask, fname) do { \ if (mark_type) \ REQUIRE_MARK_TYPE_SUPPORTED_BY_KERNEL(mark_type); \ diff --git a/testcases/kernel/syscalls/fanotify/fanotify13.c b/testcases/kernel/syscalls/fanotify/fanotify13.c index c3daaf3a2..a25a360fd 100644 --- a/testcases/kernel/syscalls/fanotify/fanotify13.c +++ b/testcases/kernel/syscalls/fanotify/fanotify13.c @@ -25,6 +25,7 @@ #include <sys/statfs.h> #include <sys/types.h> #include <sys/stat.h> +#include <sys/mount.h> #include <errno.h> #include <unistd.h> #include "tst_test.h" @@ -37,7 +38,7 @@ #define DIR_ONE "dir_one" #define FILE_ONE "file_one" #define FILE_TWO "file_two" -#define MOUNT_PATH "mntpoint" +#define MOUNT_PATH "tstmnt" #define EVENT_MAX ARRAY_SIZE(objects) #define DIR_PATH_ONE MOUNT_PATH"/"DIR_ONE #define FILE_PATH_ONE MOUNT_PATH"/"FILE_ONE @@ -88,6 +89,8 @@ static struct test_case_t { } }; +static int ovl_mounted; +static int bind_mounted; static int nofid_fd; static int fanotify_fd; static int filesystem_mark_unsupported; @@ -143,8 +146,13 @@ static void do_test(unsigned int number) struct fanotify_mark_type *mark = &tc->mark; tst_res(TINFO, - "Test #%d: FAN_REPORT_FID with mark flag: %s", - number, mark->name); + "Test #%d.%d: FAN_REPORT_FID with mark flag: %s", + number, tst_variant, mark->name); + + if (tst_variant && !ovl_mounted) { + tst_res(TCONF, "overlayfs not supported on %s", tst_device->fs_type); + return; + } if (filesystem_mark_unsupported && mark->flag & FAN_MARK_FILESYSTEM) { tst_res(TCONF, "FAN_MARK_FILESYSTEM not supported in kernel?"); @@ -160,6 +168,15 @@ static void do_test(unsigned int number) if (setup_marks(fanotify_fd, tc) != 0) goto out; + /* Variant #1: watching upper fs - open files on overlayfs */ + if (tst_variant == 1) { + if (mark->flag & FAN_MARK_MOUNT) { + tst_res(TCONF, "overlayfs upper fs cannot be watched with mount mark"); + goto out; + } + SAFE_MOUNT(OVL_MNT, MOUNT_PATH, "none", MS_BIND, NULL); + } + /* Generate sequence of FAN_OPEN events on objects */ for (i = 0; i < ARRAY_SIZE(objects); i++) fds[i] = SAFE_OPEN(objects[i].path, O_RDONLY); @@ -174,6 +191,9 @@ static void do_test(unsigned int number) SAFE_CLOSE(fds[i]); } + if (tst_variant == 1) + SAFE_UMOUNT(MOUNT_PATH); + /* Read events from event queue */ len = SAFE_READ(0, fanotify_fd, events_buf, BUF_SIZE); @@ -261,7 +281,32 @@ out: static void do_setup(void) { - REQUIRE_FANOTIFY_INIT_FLAGS_SUPPORTED_ON_FS(FAN_REPORT_FID, MOUNT_PATH); + const char *mnt; + + /* + * Bind mount to either base fs or to overlayfs over base fs: + * Variant #0: watch base fs - open files on base fs + * Variant #1: watch upper fs - open files on overlayfs + * + * Variant #1 tests a bug whose fix bc2473c90fca ("ovl: enable fsnotify + * events on underlying real files") in kernel 6.5 is not likely to be + * backported to older kernels. + * To avoid waiting for events that won't arrive when testing old kernels, + * require that kernel supports encoding fid with new flag AT_HADNLE_FID, + * also merged to 6.5 and not likely to be backported to older kernels. + */ + if (tst_variant) { + REQUIRE_HANDLE_TYPE_SUPPORTED_BY_KERNEL(AT_HANDLE_FID); + ovl_mounted = TST_MOUNT_OVERLAY(); + mnt = OVL_UPPER; + } else { + mnt = OVL_BASE_MNTPOINT; + + } + REQUIRE_FANOTIFY_INIT_FLAGS_SUPPORTED_ON_FS(FAN_REPORT_FID, mnt); + SAFE_MKDIR(MOUNT_PATH, 0755); + SAFE_MOUNT(mnt, MOUNT_PATH, "none", MS_BIND, NULL); + bind_mounted = 1; filesystem_mark_unsupported = fanotify_mark_supported_by_kernel(FAN_MARK_FILESYSTEM); @@ -287,19 +332,27 @@ static void do_cleanup(void) SAFE_CLOSE(nofid_fd); if (fanotify_fd > 0) SAFE_CLOSE(fanotify_fd); + if (bind_mounted) { + SAFE_UMOUNT(MOUNT_PATH); + SAFE_RMDIR(MOUNT_PATH); + } + if (ovl_mounted) + SAFE_UMOUNT(OVL_MNT); } static struct tst_test test = { .test = do_test, .tcnt = ARRAY_SIZE(test_cases), + .test_variants = 2, .setup = do_setup, .cleanup = do_cleanup, .needs_root = 1, .mount_device = 1, - .mntpoint = MOUNT_PATH, + .mntpoint = OVL_BASE_MNTPOINT, .all_filesystems = 1, .tags = (const struct tst_tag[]) { {"linux-git", "c285a2f01d69"}, + {"linux-git", "bc2473c90fca"}, {} } }; diff --git a/testcases/kernel/syscalls/fanotify/fanotify14.c b/testcases/kernel/syscalls/fanotify/fanotify14.c index bfa0349fe..4596511f0 100644 --- a/testcases/kernel/syscalls/fanotify/fanotify14.c +++ b/testcases/kernel/syscalls/fanotify/fanotify14.c @@ -19,6 +19,9 @@ * * ceaf69f8eadc fanotify: do not allow setting dirent events in mask of non-dir * 8698e3bab4dd fanotify: refine the validation checks on non-dir inode mask + * + * The pipes test cases are regression tests for commit: + * 69562eb0bd3e fanotify: disallow mount/sb marks on kernel internal pseudo fs */ #define _GNU_SOURCE @@ -40,6 +43,7 @@ #define FLAGS_DESC(flags) {(flags), (#flags)} +static int pipes[2] = {-1, -1}; static int fanotify_fd; static int fan_report_target_fid_unsupported; static int ignore_mark_unsupported; @@ -60,94 +64,179 @@ static struct test_case_t { /* when mask.flags == 0, fanotify_init() is expected to fail */ struct test_case_flags_t mask; int expected_errno; + int *pfd; } test_cases[] = { /* FAN_REPORT_FID without class FAN_CLASS_NOTIF is not valid */ - {FLAGS_DESC(FAN_CLASS_CONTENT | FAN_REPORT_FID), {}, {}, EINVAL}, + { + .init = FLAGS_DESC(FAN_CLASS_CONTENT | FAN_REPORT_FID), + .expected_errno = EINVAL, + }, /* FAN_REPORT_FID without class FAN_CLASS_NOTIF is not valid */ - {FLAGS_DESC(FAN_CLASS_PRE_CONTENT | FAN_REPORT_FID), {}, {}, EINVAL}, + { + .init = FLAGS_DESC(FAN_CLASS_PRE_CONTENT | FAN_REPORT_FID), + .expected_errno = EINVAL, + }, /* INODE_EVENTS in mask without class FAN_REPORT_FID are not valid */ - {FLAGS_DESC(FAN_CLASS_NOTIF), FLAGS_DESC(0), FLAGS_DESC(INODE_EVENTS), - EINVAL}, + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF), + .mark = FLAGS_DESC(FAN_MARK_INODE), + .mask = FLAGS_DESC(INODE_EVENTS), + .expected_errno = EINVAL, + }, /* INODE_EVENTS in mask with FAN_MARK_MOUNT are not valid */ - {FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_FID), - FLAGS_DESC(FAN_MARK_MOUNT), FLAGS_DESC(INODE_EVENTS), EINVAL}, + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_FID), + .mark = FLAGS_DESC(FAN_MARK_MOUNT), + .mask = FLAGS_DESC(INODE_EVENTS), + .expected_errno = EINVAL, + }, /* FAN_REPORT_NAME without FAN_REPORT_DIR_FID is not valid */ - {FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_NAME), {}, {}, EINVAL}, + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_NAME), + .expected_errno = EINVAL, + }, /* FAN_REPORT_NAME without FAN_REPORT_DIR_FID is not valid */ - {FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_FID | FAN_REPORT_NAME), {}, - {}, EINVAL}, + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_FID | FAN_REPORT_NAME), + .expected_errno = EINVAL, + }, /* FAN_REPORT_TARGET_FID without FAN_REPORT_FID is not valid */ - {FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_TARGET_FID | FAN_REPORT_DFID_NAME), - {}, {}, EINVAL}, + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_TARGET_FID | FAN_REPORT_DFID_NAME), + .expected_errno = EINVAL, + }, /* FAN_REPORT_TARGET_FID without FAN_REPORT_NAME is not valid */ - {FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_TARGET_FID | FAN_REPORT_DFID_FID), - {}, {}, EINVAL}, + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_TARGET_FID | FAN_REPORT_DFID_FID), + .expected_errno = EINVAL, + }, /* FAN_RENAME without FAN_REPORT_NAME is not valid */ - {FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_FID), FLAGS_DESC(0), - FLAGS_DESC(FAN_RENAME), EINVAL}, + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_FID), + .mark = FLAGS_DESC(FAN_MARK_INODE), + .mask = FLAGS_DESC(FAN_RENAME), + .expected_errno = EINVAL, + }, /* With FAN_MARK_ONLYDIR on non-dir is not valid */ - {FLAGS_DESC(FAN_CLASS_NOTIF), FLAGS_DESC(FAN_MARK_ONLYDIR), - FLAGS_DESC(FAN_OPEN), ENOTDIR}, + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF), + .mark = FLAGS_DESC(FAN_MARK_ONLYDIR), + .mask = FLAGS_DESC(FAN_OPEN), + .expected_errno = ENOTDIR, + }, /* With FAN_REPORT_TARGET_FID, FAN_DELETE on non-dir is not valid */ - {FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME_TARGET), - FLAGS_DESC(0), FLAGS_DESC(FAN_DELETE), ENOTDIR}, + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME_TARGET), + .mark = FLAGS_DESC(FAN_MARK_INODE), + .mask = FLAGS_DESC(FAN_DELETE), + .expected_errno = ENOTDIR, + }, /* With FAN_REPORT_TARGET_FID, FAN_RENAME on non-dir is not valid */ - {FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME_TARGET), - FLAGS_DESC(0), FLAGS_DESC(FAN_RENAME), ENOTDIR}, + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME_TARGET), + .mark = FLAGS_DESC(FAN_MARK_INODE), + .mask = FLAGS_DESC(FAN_RENAME), + .expected_errno = ENOTDIR, + }, /* With FAN_REPORT_TARGET_FID, FAN_ONDIR on non-dir is not valid */ - {FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME_TARGET), - FLAGS_DESC(0), FLAGS_DESC(FAN_OPEN | FAN_ONDIR), ENOTDIR}, + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME_TARGET), + .mark = FLAGS_DESC(FAN_MARK_INODE), + .mask = FLAGS_DESC(FAN_OPEN | FAN_ONDIR), + .expected_errno = ENOTDIR, + }, /* With FAN_REPORT_TARGET_FID, FAN_EVENT_ON_CHILD on non-dir is not valid */ - {FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME_TARGET), - FLAGS_DESC(0), FLAGS_DESC(FAN_OPEN | FAN_EVENT_ON_CHILD), - ENOTDIR}, + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME_TARGET), + .mark = FLAGS_DESC(FAN_MARK_INODE), + .mask = FLAGS_DESC(FAN_OPEN | FAN_EVENT_ON_CHILD), + .expected_errno = ENOTDIR, + }, /* FAN_MARK_IGNORE_SURV with FAN_DELETE on non-dir is not valid */ - {FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME), - FLAGS_DESC(FAN_MARK_IGNORE_SURV), FLAGS_DESC(FAN_DELETE), - ENOTDIR}, + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME), + .mark = FLAGS_DESC(FAN_MARK_IGNORE_SURV), + .mask = FLAGS_DESC(FAN_DELETE), + .expected_errno = ENOTDIR, + }, /* FAN_MARK_IGNORE_SURV with FAN_RENAME on non-dir is not valid */ - {FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME), - FLAGS_DESC(FAN_MARK_IGNORE_SURV), FLAGS_DESC(FAN_RENAME), - ENOTDIR}, + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME), + .mark = FLAGS_DESC(FAN_MARK_IGNORE_SURV), + .mask = FLAGS_DESC(FAN_RENAME), + .expected_errno = ENOTDIR, + }, /* FAN_MARK_IGNORE_SURV with FAN_ONDIR on non-dir is not valid */ - {FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME), - FLAGS_DESC(FAN_MARK_IGNORE_SURV), - FLAGS_DESC(FAN_OPEN | FAN_ONDIR), ENOTDIR}, + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME), + .mark = FLAGS_DESC(FAN_MARK_IGNORE_SURV), + .mask = FLAGS_DESC(FAN_OPEN | FAN_ONDIR), + .expected_errno = ENOTDIR, + }, /* FAN_MARK_IGNORE_SURV with FAN_EVENT_ON_CHILD on non-dir is not valid */ - {FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME), - FLAGS_DESC(FAN_MARK_IGNORE_SURV), - FLAGS_DESC(FAN_OPEN | FAN_EVENT_ON_CHILD), ENOTDIR}, + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME), + .mark = FLAGS_DESC(FAN_MARK_IGNORE_SURV), + .mask = FLAGS_DESC(FAN_OPEN | FAN_EVENT_ON_CHILD), + .expected_errno = ENOTDIR, + }, /* FAN_MARK_IGNORE without FAN_MARK_IGNORED_SURV_MODIFY on directory is not valid */ - {FLAGS_DESC(FAN_CLASS_NOTIF), FLAGS_DESC(FAN_MARK_IGNORE), - FLAGS_DESC(FAN_OPEN), EISDIR}, + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF), + .mark = FLAGS_DESC(FAN_MARK_IGNORE), + .mask = FLAGS_DESC(FAN_OPEN), + .expected_errno = EISDIR, + }, /* FAN_MARK_IGNORE without FAN_MARK_IGNORED_SURV_MODIFY on mount mark is not valid */ - {FLAGS_DESC(FAN_CLASS_NOTIF), - FLAGS_DESC(FAN_MARK_MOUNT | FAN_MARK_IGNORE), - FLAGS_DESC(FAN_OPEN), EINVAL}, + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF), + .mark = FLAGS_DESC(FAN_MARK_MOUNT | FAN_MARK_IGNORE), + .mask = FLAGS_DESC(FAN_OPEN), + .expected_errno = EINVAL, + }, /* FAN_MARK_IGNORE without FAN_MARK_IGNORED_SURV_MODIFY on filesystem mark is not valid */ - {FLAGS_DESC(FAN_CLASS_NOTIF), - FLAGS_DESC(FAN_MARK_FILESYSTEM | FAN_MARK_IGNORE), - FLAGS_DESC(FAN_OPEN), EINVAL}, + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF), + .mark = FLAGS_DESC(FAN_MARK_FILESYSTEM | FAN_MARK_IGNORE), + .mask = FLAGS_DESC(FAN_OPEN), + .expected_errno = EINVAL, + }, + /* mount mark on anonymous pipe is not valid */ + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF), + .mark = FLAGS_DESC(FAN_MARK_MOUNT), + .mask = { FAN_ACCESS, "anonymous pipe"}, + .pfd = pipes, + .expected_errno = EINVAL, + }, + /* filesystem mark on anonymous pipe is not valid */ + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF), + .mark = FLAGS_DESC(FAN_MARK_FILESYSTEM), + .mask = { FAN_ACCESS, "anonymous pipe"}, + .pfd = pipes, + .expected_errno = EINVAL, + }, }; static void do_test(unsigned int number) @@ -185,11 +274,17 @@ static void do_test(unsigned int number) /* Set mark on non-dir only when expecting error ENOTDIR */ const char *path = tc->expected_errno == ENOTDIR ? FILE1 : MNTPOINT; + int dirfd = AT_FDCWD; + + if (tc->pfd) { + dirfd = tc->pfd[0]; + path = NULL; + } - tst_res(TINFO, "Testing fanotify_mark(FAN_MARK_ADD | %s, %s)", + tst_res(TINFO, "Testing %s with %s", tc->mark.desc, tc->mask.desc); TST_EXP_FD_OR_FAIL(fanotify_mark(fanotify_fd, FAN_MARK_ADD | tc->mark.flags, - tc->mask.flags, AT_FDCWD, path), + tc->mask.flags, dirfd, path), tc->expected_errno); /* @@ -231,12 +326,18 @@ static void do_setup(void) /* Create temporary test file to place marks on */ SAFE_FILE_PRINTF(FILE1, "0"); + /* Create anonymous pipes to place marks on */ + SAFE_PIPE2(pipes, O_CLOEXEC); } static void do_cleanup(void) { if (fanotify_fd > 0) SAFE_CLOSE(fanotify_fd); + if (pipes[0] != -1) + SAFE_CLOSE(pipes[0]); + if (pipes[1] != -1) + SAFE_CLOSE(pipes[1]); } static struct tst_test test = { @@ -251,6 +352,7 @@ static struct tst_test test = { .tags = (const struct tst_tag[]) { {"linux-git", "ceaf69f8eadc"}, {"linux-git", "8698e3bab4dd"}, + {"linux-git", "69562eb0bd3e"}, {} } }; diff --git a/testcases/kernel/syscalls/fanotify/fanotify22.c b/testcases/kernel/syscalls/fanotify/fanotify22.c index 6596a69c9..a654e8912 100644 --- a/testcases/kernel/syscalls/fanotify/fanotify22.c +++ b/testcases/kernel/syscalls/fanotify/fanotify22.c @@ -41,6 +41,7 @@ #define MOUNT_PATH "test_mnt" #define BASE_DIR "internal_dir" #define BAD_DIR BASE_DIR"/bad_dir" +#define BAD_LINK BASE_DIR"/bad_link" #ifdef HAVE_NAME_TO_HANDLE_AT @@ -50,6 +51,7 @@ static int fd_notify; /* These expected FIDs are common to multiple tests */ static struct fanotify_fid_t null_fid; static struct fanotify_fid_t bad_file_fid; +static struct fanotify_fid_t bad_link_fid; static void trigger_fs_abort(void) { @@ -64,7 +66,7 @@ static void do_debugfs_request(const char *dev, char *request) SAFE_CMD(cmd, NULL, NULL); } -static void tcase2_trigger_lookup(void) +static void trigger_bad_file_lookup(void) { int ret; @@ -75,15 +77,27 @@ static void tcase2_trigger_lookup(void) ret, BAD_DIR, errno, EUCLEAN); } +static void trigger_bad_link_lookup(void) +{ + int ret; + + /* SAFE_OPEN cannot be used here because we expect it to fail. */ + ret = open(MOUNT_PATH"/"BAD_LINK, O_RDONLY, 0); + if (ret != -1 && errno != EUCLEAN) + tst_res(TFAIL, "Unexpected open result(%d) of %s (%d!=%d)", + ret, BAD_LINK, errno, EUCLEAN); +} + + static void tcase3_trigger(void) { - trigger_fs_abort(); - tcase2_trigger_lookup(); + trigger_bad_link_lookup(); + trigger_bad_file_lookup(); } static void tcase4_trigger(void) { - tcase2_trigger_lookup(); + trigger_bad_file_lookup(); trigger_fs_abort(); } @@ -103,7 +117,7 @@ static struct test_case { }, { .name = "Lookup of inode with invalid mode", - .trigger_error = &tcase2_trigger_lookup, + .trigger_error = &trigger_bad_file_lookup, .error_count = 1, .error = EFSCORRUPTED, .fid = &bad_file_fid, @@ -112,8 +126,8 @@ static struct test_case { .name = "Multiple error submission", .trigger_error = &tcase3_trigger, .error_count = 2, - .error = ESHUTDOWN, - .fid = &null_fid, + .error = EFSCORRUPTED, + .fid = &bad_link_fid, }, { .name = "Multiple error submission 2", @@ -247,6 +261,9 @@ static void do_test(unsigned int i) FAN_FS_ERROR, AT_FDCWD, MOUNT_PATH); check_event(event_buf, read_len, tcase); + /* Unmount and mount the filesystem to get it out of the error state */ + SAFE_UMOUNT(MOUNT_PATH); + SAFE_MOUNT(tst_device->dev, MOUNT_PATH, tst_device->fs_type, 0, NULL); } static void pre_corrupt_fs(void) @@ -255,9 +272,11 @@ static void pre_corrupt_fs(void) SAFE_MKDIR(MOUNT_PATH"/"BAD_DIR, 0777); fanotify_save_fid(MOUNT_PATH"/"BAD_DIR, &bad_file_fid); + fanotify_save_fid(MOUNT_PATH"/"BASE_DIR, &bad_link_fid); SAFE_UMOUNT(MOUNT_PATH); do_debugfs_request(tst_device->dev, "sif " BAD_DIR " mode 0xff"); + do_debugfs_request(tst_device->dev, "ln <1> " BAD_LINK); SAFE_MOUNT(tst_device->dev, MOUNT_PATH, tst_device->fs_type, 0, NULL); } diff --git a/testcases/kernel/syscalls/fanotify/fanotify23.c b/testcases/kernel/syscalls/fanotify/fanotify23.c index 89fd4f36a..fb812c51e 100644 --- a/testcases/kernel/syscalls/fanotify/fanotify23.c +++ b/testcases/kernel/syscalls/fanotify/fanotify23.c @@ -160,10 +160,16 @@ static void test_fanotify(void) } /* - * drop_caches should evict inode from cache and remove evictable mark + * drop_caches should evict inode from cache and remove evictable mark. + * We call drop_caches twice as once the dentries will just cycle + * through the LRU without being reclaimed and if there are no other + * objects to reclaim, the slab reclaim will just stop instead of + * retrying. Note that this relies on how reclaim of fs objects work + * for the filesystem but this test is restricted to ext2... */ fsync_file(TEST_FILE); SAFE_FILE_PRINTF(DROP_CACHES_FILE, "3"); + SAFE_FILE_PRINTF(DROP_CACHES_FILE, "3"); verify_mark_removed(TEST_FILE, "after drop_caches"); diff --git a/testcases/kernel/syscalls/fchmod/fchmod02.c b/testcases/kernel/syscalls/fchmod/fchmod02.c index e60cb33a6..d6abeffce 100644 --- a/testcases/kernel/syscalls/fchmod/fchmod02.c +++ b/testcases/kernel/syscalls/fchmod/fchmod02.c @@ -1,18 +1,18 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) International Business Machines Corp., 2001 + */ + +/*\ + * [Description] * - * Test Description: - * Verify that, fchmod() will succeed to change the mode of a file/directory - * set the sticky bit on it if invoked by root (uid = 0) process with - * the following constraints, - * - the process is not the owner of the file/directory. - * - the effective group ID or one of the supplementary group ID's of the - * process is equal to the group ID of the file/directory. + * Verify that, fchmod(2) will succeed to change the mode of a file/directory + * set the sticky bit on it if invoked by root (uid = 0) process with + * the following constraints: * - * Expected Result: - * fchmod() should return value 0 on success and succeeds to set sticky bit - * on the specified file. + * - the process is not the owner of the file/directory + * - the effective group ID or one of the supplementary group ID's of the + * process is equal to the group ID of the file/directory */ #include <pwd.h> diff --git a/testcases/kernel/syscalls/fchmod/fchmod03.c b/testcases/kernel/syscalls/fchmod/fchmod03.c index 12a6f5a93..bdd720c37 100644 --- a/testcases/kernel/syscalls/fchmod/fchmod03.c +++ b/testcases/kernel/syscalls/fchmod/fchmod03.c @@ -8,10 +8,11 @@ * * Verify that, fchmod(2) will succeed to change the mode of a file * and set the sticky bit on it if invoked by non-root (uid != 0) - * process with the following constraints, - * - the process is the owner of the file. - * - the effective group ID or one of the supplementary group ID's of the - * process is equal to the group ID of the file. + * process with the following constraints: + * + * - the process is the owner of the file + * - the effective group ID or one of the supplementary group ID's of the + * process is equal to the group ID of the file */ #include <pwd.h> diff --git a/testcases/kernel/syscalls/fchmod/fchmod04.c b/testcases/kernel/syscalls/fchmod/fchmod04.c index d60cb39b2..4fa69e227 100644 --- a/testcases/kernel/syscalls/fchmod/fchmod04.c +++ b/testcases/kernel/syscalls/fchmod/fchmod04.c @@ -8,10 +8,11 @@ * * Verify that, fchmod(2) will succeed to change the mode of a directory * and set the sticky bit on it if invoked by non-root (uid != 0) process - * with the following constraints, - * - the process is the owner of the directory. - * - the effective group ID or one of the supplementary group ID's of the - * process is equal to the group ID of the directory. + * with the following constraints: + * + * - the process is the owner of the directory + * - the effective group ID or one of the supplementary group ID's of the + * process is equal to the group ID of the directory */ #include <pwd.h> diff --git a/testcases/kernel/syscalls/fchown/fchown02.c b/testcases/kernel/syscalls/fchown/fchown02.c index d02f5bc92..bd1baf3bb 100644 --- a/testcases/kernel/syscalls/fchown/fchown02.c +++ b/testcases/kernel/syscalls/fchown/fchown02.c @@ -10,6 +10,7 @@ * [Description] * * Verify that fchown(2) invoked by super-user: + * * - clears setuid and setgid bits set on an executable file * - preserves setgid bit set on a non-group-executable file */ diff --git a/testcases/kernel/syscalls/fcntl/.gitignore b/testcases/kernel/syscalls/fcntl/.gitignore index 48b36ec34..10cb0995f 100644 --- a/testcases/kernel/syscalls/fcntl/.gitignore +++ b/testcases/kernel/syscalls/fcntl/.gitignore @@ -8,8 +8,6 @@ /fcntl04_64 /fcntl05 /fcntl05_64 -/fcntl06 -/fcntl06_64 /fcntl07 /fcntl07_64 /fcntl08 diff --git a/testcases/kernel/syscalls/fcntl/fcntl06.c b/testcases/kernel/syscalls/fcntl/fcntl06.c deleted file mode 100644 index 8dcc04866..000000000 --- a/testcases/kernel/syscalls/fcntl/fcntl06.c +++ /dev/null @@ -1,165 +0,0 @@ -/* - * - * 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 - */ - -/* - * NAME - * fcntl06.c - * - * DESCRIPTION - * Error checking conditions for remote locking of regions of a file. - * - * CALLS - * open(2), write(2), fcntl(2) - * - * ALGORITHM - * Test unlocking sections around a write lock using remote Lock/Unlock - * call which should all fail. - * - * USAGE - * fcntl06 - * - * HISTORY - * 07/2001 Ported by Wayne Boyer - * - * RESTRICTIONS - * Currently Linux kernel doesn't implement R_GETLK/R_SETLK facility, - * but this facility seems to be present in other standard flavours of - * Unix. Currently this program has all the testing done under - * "#ifdef LINUX_FILE_REGION_LOCK", when Linux implements the regions - * locking then, this testcase should be recompiled accordingly with the - * "ifdef" removed. - */ - -#include <fcntl.h> -#include <errno.h> -#include <signal.h> -#include <sys/types.h> -#include <sys/stat.h> -#include "test.h" - -#define F_RGETLK 10 /* kludge code */ -#define F_RSETLK 11 /* kludge code */ - -char *TCID = "fcntl06"; -int TST_TOTAL = 1; - -void setup(); -void cleanup(); - -#define STRINGSIZE 27 -#define STRING "abcdefghijklmnopqrstuvwxyz\n" - -int fd; -void unlock_file(); -int do_lock(int, short, short, int, int); - -int main(int ac, char **av) -{ - int fail = 0; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); /* global setup */ - - fail = 0; - -#ifdef LINUX_FILE_REGION_LOCK - if (fcntl(fd, F_RGETLK, &tl) == -1) { - if (errno == EINVAL) - tst_brkm(TCONF, cleanup, - "fcntl remote locking feature not implemented in " - "the kernel"); - else { - /* - * FIXME (garrcoop): having it always pass on - * non-EINVAL is a bad test. - */ - tst_resm(TPASS, "fcntl on file failed"); - } - } - - /* - * Add a write lock to the middle of the file and unlock a section - * just before the lock - */ - if (do_lock(F_RSETLK, F_WRLCK, 0, 10, 5) == -1) - tst_resm(TFAIL, "F_RSETLK WRLCK failed"); - - if (do_lock(F_RSETLK, F_UNLCK, 0, 5, 5) == -1) - tst_resm(TFAIL | TERRNO, "F_RSETLK UNLOCK failed"); - - unlock_file(); -#else - tst_resm(TCONF, "system doesn't have LINUX_LOCK_FILE_REGION support"); -#endif - - cleanup(); - tst_exit(); -} - -void setup(void) -{ - char *buf = STRING; - char template[PATH_MAX]; - - tst_sig(FORK, DEF_HANDLER, cleanup); - - umask(0); - - TEST_PAUSE; - - tst_tmpdir(); - - snprintf(template, PATH_MAX, "fcntl06XXXXXX"); - - if ((fd = mkstemp(template)) == -1) - tst_resm(TBROK | TERRNO, "mkstemp failed"); - - if (write(fd, buf, STRINGSIZE) == -1) - tst_resm(TBROK | TERRNO, "write failed"); -} - -int do_lock(int cmd, short type, short whence, int start, int len) -{ - struct flock fl; - - fl.l_type = type; - fl.l_whence = whence; - fl.l_start = start; - fl.l_len = len; - return (fcntl(fd, cmd, &fl)); -} - -void unlock_file(void) -{ - if (do_lock(F_RSETLK, (short)F_UNLCK, (short)0, 0, 0) == -1) { - /* Same as FIXME comment above. */ - tst_resm(TPASS | TERRNO, "fcntl on file failed"); - } -} - -void cleanup(void) -{ - - if (close(fd) == -1) - tst_resm(TWARN | TERRNO, "close failed"); - - tst_rmdir(); - -} diff --git a/testcases/kernel/syscalls/fcntl/fcntl11.c b/testcases/kernel/syscalls/fcntl/fcntl11.c index b66fa8421..d042c6b9b 100644 --- a/testcases/kernel/syscalls/fcntl/fcntl11.c +++ b/testcases/kernel/syscalls/fcntl/fcntl11.c @@ -189,11 +189,11 @@ char *str_type(int type) static char buf[20]; switch (type) { - case 0: + case F_RDLCK: return ("F_RDLCK"); - case 1: + case F_WRLCK: return ("F_WRLCK"); - case 2: + case F_UNLCK: return ("F_UNLCK"); default: sprintf(buf, "BAD VALUE: %d", type); diff --git a/testcases/kernel/syscalls/fcntl/fcntl19.c b/testcases/kernel/syscalls/fcntl/fcntl19.c index 88c91d6ea..f929aff99 100644 --- a/testcases/kernel/syscalls/fcntl/fcntl19.c +++ b/testcases/kernel/syscalls/fcntl/fcntl19.c @@ -215,11 +215,11 @@ char *str_type(int type) static char buf[20]; switch (type) { - case 1: + case F_RDLCK: return ("F_RDLCK"); - case 2: + case F_WRLCK: return ("F_WRLCK"); - case 3: + case F_UNLCK: return ("F_UNLCK"); default: sprintf(buf, "BAD VALUE: %d", type); diff --git a/testcases/kernel/syscalls/fcntl/fcntl20.c b/testcases/kernel/syscalls/fcntl/fcntl20.c index b671af8a9..4aa773451 100644 --- a/testcases/kernel/syscalls/fcntl/fcntl20.c +++ b/testcases/kernel/syscalls/fcntl/fcntl20.c @@ -214,11 +214,11 @@ char *str_type(int type) static char buf[20]; switch (type) { - case 1: + case F_RDLCK: return ("F_RDLCK"); - case 2: + case F_WRLCK: return ("F_WRLCK"); - case 3: + case F_UNLCK: return ("F_UNLCK"); default: sprintf(buf, "BAD VALUE: %d", type); diff --git a/testcases/kernel/syscalls/fcntl/fcntl21.c b/testcases/kernel/syscalls/fcntl/fcntl21.c index 8f1a67cf6..824b8c059 100644 --- a/testcases/kernel/syscalls/fcntl/fcntl21.c +++ b/testcases/kernel/syscalls/fcntl/fcntl21.c @@ -222,11 +222,11 @@ char *str_type(int type) static char buf[20]; switch (type) { - case 1: + case F_RDLCK: return ("F_RDLCK"); - case 2: + case F_WRLCK: return ("F_WRLCK"); - case 3: + case F_UNLCK: return ("F_UNLCK"); default: sprintf(buf, "BAD VALUE: %d", type); diff --git a/testcases/kernel/syscalls/fcntl/fcntl30.c b/testcases/kernel/syscalls/fcntl/fcntl30.c index c4c3f81f1..64bbb9e3a 100644 --- a/testcases/kernel/syscalls/fcntl/fcntl30.c +++ b/testcases/kernel/syscalls/fcntl/fcntl30.c @@ -1,103 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2014 Fujitsu Ltd. * Author: Xiaoguang Wang <wangxg.fnst@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. + * Copyright (c) 2023 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> */ -/* - * Description: - * Verify that, - * Basic test for fcntl(2) using F_SETPIPE_SZ, F_GETPIPE_SZ argument. +/*\ + * [Description] + * + * Verify that, fetching and changing the capacity of a pipe works as + * expected with fcntl(2) syscall using F_GETPIPE_SZ, F_SETPIPE_SZ arguments. */ - -#include <stdio.h> -#include <errno.h> -#include <unistd.h> -#include <string.h> -#include <signal.h> -#include <sys/types.h> -#include <pwd.h> - -#include "test.h" -#include "safe_macros.h" +#include "tst_test.h" #include "lapi/fcntl.h" -char *TCID = "fcntl30"; -int TST_TOTAL = 1; - -static void setup(void); -static void cleanup(void); +static int fds[2]; +static int max_size_unpriv; -int main(int ac, char **av) +static void run(void) { - int lc; - int pipe_fds[2], test_fd; - int orig_pipe_size, new_pipe_size; + SAFE_PIPE(fds); + TST_EXP_POSITIVE(fcntl(fds[1], F_GETPIPE_SZ)); - tst_parse_opts(ac, av, NULL, NULL); + TST_EXP_POSITIVE(fcntl(fds[1], F_SETPIPE_SZ, max_size_unpriv)); + TST_EXP_POSITIVE(fcntl(fds[1], F_GETPIPE_SZ)); + TST_EXP_EXPR(TST_RET >= max_size_unpriv, + "new pipe size (%ld) >= requested size (%d)", + TST_RET, max_size_unpriv); - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - - SAFE_PIPE(cleanup, pipe_fds); - test_fd = pipe_fds[1]; - - TEST(fcntl(test_fd, F_GETPIPE_SZ)); - if (TEST_RETURN < 0) { - tst_brkm(TFAIL | TTERRNO, cleanup, - "fcntl get pipe size failed"); - } - - orig_pipe_size = TEST_RETURN; - new_pipe_size = orig_pipe_size * 2; - TEST(fcntl(test_fd, F_SETPIPE_SZ, new_pipe_size)); - if (TEST_RETURN < 0) { - tst_brkm(TFAIL | TTERRNO, cleanup, - "fcntl test F_SETPIPE_SZ failed"); - } - - TEST(fcntl(test_fd, F_GETPIPE_SZ)); - if (TEST_RETURN < 0) { - tst_brkm(TFAIL | TTERRNO, cleanup, - "fcntl test F_GETPIPE_SZ failed"); - } - tst_resm(TINFO, "orig_pipe_size: %d new_pipe_size: %d", - orig_pipe_size, new_pipe_size); - if (TEST_RETURN >= new_pipe_size) { - tst_resm(TPASS, "fcntl test F_GETPIPE_SZ and F_SETPIPE_SZ passed"); - } else { - tst_resm(TFAIL, "fcntl test F_GETPIPE_SZ and F_SETPIPE_SZ failed"); - } - SAFE_CLOSE(cleanup, pipe_fds[0]); - SAFE_CLOSE(cleanup, pipe_fds[1]); - } - - cleanup(); - tst_exit(); + SAFE_CLOSE(fds[0]); + SAFE_CLOSE(fds[1]); } static void setup(void) { - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; + SAFE_FILE_SCANF("/proc/sys/fs/pipe-max-size", "%d", &max_size_unpriv); } static void cleanup(void) { + if (fds[0] > 0) + SAFE_CLOSE(fds[0]); + if (fds[1] > 0) + SAFE_CLOSE(fds[1]); } + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup +}; diff --git a/testcases/kernel/syscalls/fcntl/fcntl33.c b/testcases/kernel/syscalls/fcntl/fcntl33.c index 8d0d1a5a1..3c6a38b81 100644 --- a/testcases/kernel/syscalls/fcntl/fcntl33.c +++ b/testcases/kernel/syscalls/fcntl/fcntl33.c @@ -209,7 +209,7 @@ static void cleanup(void) SAFE_CLOSE(fd); /* Restore the lease-break-time. */ - FILE_PRINTF(PATH_LS_BRK_T, "%d", ls_brk_t); + SAFE_FILE_PRINTF(PATH_LS_BRK_T, "%d", ls_brk_t); } static struct tst_test test = { diff --git a/testcases/kernel/syscalls/finit_module/finit_module01.c b/testcases/kernel/syscalls/finit_module/finit_module01.c index f960b2e40..1929c30fa 100644 --- a/testcases/kernel/syscalls/finit_module/finit_module01.c +++ b/testcases/kernel/syscalls/finit_module/finit_module01.c @@ -49,6 +49,7 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .needs_root = 1, - /* lockdown requires signed modules */ + /* lockdown and SecureBoot requires signed modules */ .skip_in_lockdown = 1, + .skip_in_secureboot = 1, }; diff --git a/testcases/kernel/syscalls/finit_module/finit_module02.c b/testcases/kernel/syscalls/finit_module/finit_module02.c index a7434de7d..223d9b388 100644 --- a/testcases/kernel/syscalls/finit_module/finit_module02.c +++ b/testcases/kernel/syscalls/finit_module/finit_module02.c @@ -25,7 +25,7 @@ static char *mod_path; static int fd, fd_zero, fd_invalid = -1, fd_dir; -static int kernel_lockdown; +static int kernel_lockdown, secure_boot; static struct tst_cap cap_req = TST_CAP(TST_CAP_REQ, CAP_SYS_MODULE); static struct tst_cap cap_drop = TST_CAP(TST_CAP_DROP, CAP_SYS_MODULE); @@ -83,7 +83,9 @@ static void setup(void) tst_module_exists(MODULE_NAME, &mod_path); - kernel_lockdown = tst_lockdown_enabled(); + kernel_lockdown = tst_lockdown_enabled() > 0; + secure_boot = tst_secureboot_enabled() > 0; + SAFE_MKDIR(TEST_DIR, 0700); fd_dir = SAFE_OPEN(TEST_DIR, O_DIRECTORY); @@ -102,8 +104,8 @@ static void run(unsigned int n) { struct tcase *tc = &tcases[n]; - if (tc->skip_in_lockdown && kernel_lockdown) { - tst_res(TCONF, "Kernel is locked down, skipping %s", tc->name); + if (tc->skip_in_lockdown && (kernel_lockdown || secure_boot)) { + tst_res(TCONF, "Cannot load unsigned modules, skipping %s", tc->name); return; } diff --git a/testcases/kernel/syscalls/flistxattr/flistxattr01.c b/testcases/kernel/syscalls/flistxattr/flistxattr01.c index 98a6fa254..68c3948b7 100644 --- a/testcases/kernel/syscalls/flistxattr/flistxattr01.c +++ b/testcases/kernel/syscalls/flistxattr/flistxattr01.c @@ -47,7 +47,7 @@ static int has_attribute(const char *list, int llen, const char *attr) static void verify_flistxattr(void) { - char buf[64]; + char buf[128]; TEST(flistxattr(fd, buf, sizeof(buf))); if (TST_RET == -1) { diff --git a/testcases/kernel/syscalls/fork/fork03.c b/testcases/kernel/syscalls/fork/fork03.c index 25b36c897..c6381dd67 100644 --- a/testcases/kernel/syscalls/fork/fork03.c +++ b/testcases/kernel/syscalls/fork/fork03.c @@ -1,119 +1,59 @@ +// 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 + * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) Linux Test Project, 2003-2023 + * Author: 2001 Ported by Wayne Boyer */ -/* - * NAME - * fork03.c - * - * DESCRIPTION - * Check that child can use a large text space and do a large - * number of operations. - * - * ALGORITHM - * Fork one process, check for pid == 0 in child. - * Check for pid > 0 in parent after wait. +/*\ + *[Description] * - * USAGE - * fork03 - * - * HISTORY - * 07/2001 Ported by Wayne Boyer - * - * RESTRICTIONS - * None + * Check that child process can use a large text space and do a large number + * of operations. In this situation, check for pid == 0 in child and check + * for pid > 0 in parent after wait. */ -#include <sys/types.h> +#include <unistd.h> #include <sys/wait.h> -#include <stdio.h> -#include "test.h" - -char *TCID = "fork03"; -int TST_TOTAL = 1; +#include <stdlib.h> +#include "tst_test.h" -static void setup(void); -static void cleanup(void); - -int main(int ac, char **av) +static void verify_fork(void) { float fl1, fl2; - int i; - int pid1, pid2, status; - - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - pid1 = fork(); - if (pid1 == -1) - tst_brkm(TBROK, cleanup, "fork() failed"); - - if (pid1 == 0) { - /* child uses some cpu cycles */ - for (i = 1; i < 32767; i++) { - fl1 = 0.000001; - fl1 = fl2 = 0.000001; - fl1 = fl1 * 10.0; - fl2 = fl1 / 1.232323; - fl1 = fl2 - fl2; - fl1 = fl2; - } - - /* Pid must always be zero in child */ - if (pid1 != 0) - exit(1); - else - exit(0); - } else { - tst_resm(TINFO, "process id in parent of child from " - "fork : %d", pid1); - pid2 = wait(&status); /* wait for child */ - - if (pid1 != pid2) { - tst_resm(TFAIL, "pids don't match : %d vs %d", - pid1, pid2); - continue; - } + int pid1, pid2, status, i; + + pid1 = SAFE_FORK(); + if (!pid1) { + /* child uses some cpu time slices */ + for (i = 1; i < 32767; i++) { + fl1 = 0.000001; + fl1 = fl2 = 0.000001; + fl1 = fl1 * 10.0; + fl2 = fl1 / 1.232323; + fl1 = fl2 - fl2; + fl1 = fl2; + } + exit(!!pid1); + } - if ((status >> 8) != 0) { - tst_resm(TFAIL, "child exited with failure"); - continue; - } + tst_res(TINFO, "process id in parent of child from fork: %d", pid1); + pid2 = SAFE_WAIT(&status); - tst_resm(TPASS, "test 1 PASSED"); - } + if (pid1 != pid2) { + tst_res(TFAIL, "pids don't match: %d vs %d", pid1, pid2); + return; } - cleanup(); - tst_exit(); -} + if ((status >> 8) != 0) { + tst_res(TFAIL, "child exited with failure"); + return; + } -static void setup(void) -{ - tst_sig(FORK, DEF_HANDLER, cleanup); - TEST_PAUSE; + tst_res(TPASS, "test PASSED"); } -static void cleanup(void) -{ -} +static struct tst_test test = { + .test_all = verify_fork, + .forks_child = 1, +}; diff --git a/testcases/kernel/syscalls/fsconfig/.gitignore b/testcases/kernel/syscalls/fsconfig/.gitignore index 2bc54b827..cfedae5f7 100644 --- a/testcases/kernel/syscalls/fsconfig/.gitignore +++ b/testcases/kernel/syscalls/fsconfig/.gitignore @@ -1,2 +1,3 @@ /fsconfig01 /fsconfig02 +/fsconfig03 diff --git a/testcases/kernel/syscalls/fsconfig/fsconfig03.c b/testcases/kernel/syscalls/fsconfig/fsconfig03.c new file mode 100644 index 000000000..0ba5355d3 --- /dev/null +++ b/testcases/kernel/syscalls/fsconfig/fsconfig03.c @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 Alejandro Guerrero <aguerrero@qualys.com> + * Copyright (c) 2023 Wei Gao <wegao@suse.com> + */ + +/*\ + * [Description] + * + * Test for CVE-2022-0185. + * + * References links: + * + * - https://www.openwall.com/lists/oss-security/2022/01/25/14 + * - https://github.com/Crusaders-of-Rust/CVE-2022-0185 + * + */ + +#include "tst_test.h" +#include "lapi/fsmount.h" + +#define MNTPOINT "mntpoint" + +static int fd = -1; + +static void setup(void) +{ + fsopen_supported_by_kernel(); +} + +static void run(void) +{ + char *val = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + long pagesize; + + TEST(fd = fsopen(tst_device->fs_type, 0)); + if (fd == -1) + tst_brk(TBROK | TTERRNO, "fsopen() failed"); + + pagesize = sysconf(_SC_PAGESIZE); + if (pagesize == -1) + tst_brk(TBROK, "sysconf(_SC_PAGESIZE) failed"); + + for (size_t i = 0; i < 5000; i++) { + /* use same logic in kernel legacy_parse_param function */ + const size_t len = i * (strlen(val) + 2) + (strlen(val) + 1) + 2; + + TEST(fsconfig(fd, FSCONFIG_SET_STRING, "\x00", val, 0)); + + /* Legacy fsconfig() just copies arguments to buffer */ + if (!TST_RET && len <= (size_t)pagesize) + continue; + + if (!TST_RET) { + tst_res(TFAIL, "fsconfig() passed unexpectedly"); + } else if (TST_RET != -1) { + tst_brk(TBROK | TTERRNO, + "Invalid fsconfig() return value %ld", TST_RET); + } else if (TST_ERR != EINVAL) { + tst_res(TFAIL | TTERRNO, + "fsconfig() failed with unexpected error"); + } + } + + if (fd != -1) + SAFE_CLOSE(fd); + + if (tst_taint_check()) + tst_res(TFAIL, "kernel has issues on %s", + tst_device->fs_type); + else + tst_res(TPASS, "kernel seems to be fine on %s", + tst_device->fs_type); +} + +static void cleanup(void) +{ + if (fd >= 0) + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .needs_root = 1, + .format_device = 1, + .mntpoint = MNTPOINT, + .all_filesystems = 1, + .taint_check = TST_TAINT_W | TST_TAINT_D, + .skip_filesystems = (const char *const []){"fuse", NULL}, + .tags = (const struct tst_tag[]) { + {"linux-git", "722d94847de29"}, + {"CVE", "2022-0185"}, + {} + } +}; diff --git a/testcases/kernel/syscalls/futex/Makefile b/testcases/kernel/syscalls/futex/Makefile index 7228496bc..1d05cf115 100644 --- a/testcases/kernel/syscalls/futex/Makefile +++ b/testcases/kernel/syscalls/futex/Makefile @@ -9,6 +9,9 @@ futex_wait02: LDLIBS+=-lrt futex_wake03: LDLIBS+=-lrt futex_wait05: LDLIBS+=-lrt futex_wait_bitset01: LDLIBS+=-lrt +futex_waitv01: LDLIBS+=-lrt +futex_waitv02: LDLIBS+=-lrt +futex_waitv03: LDLIBS+=-lrt futex_wait03: CFLAGS+=-pthread futex_wake02: CFLAGS+=-pthread diff --git a/testcases/kernel/syscalls/futex/futex_wake04.c b/testcases/kernel/syscalls/futex/futex_wake04.c index 176dd4aeb..03d90591b 100644 --- a/testcases/kernel/syscalls/futex/futex_wake04.c +++ b/testcases/kernel/syscalls/futex/futex_wake04.c @@ -21,7 +21,6 @@ */ #include <stdio.h> -#include <sys/mman.h> #include <fcntl.h> #include <sys/time.h> #include <string.h> diff --git a/testcases/kernel/syscalls/getcpu/getcpu01.c b/testcases/kernel/syscalls/getcpu/getcpu01.c index f6fcc4fc1..9842c8999 100644 --- a/testcases/kernel/syscalls/getcpu/getcpu01.c +++ b/testcases/kernel/syscalls/getcpu/getcpu01.c @@ -69,6 +69,7 @@ static unsigned int get_nodeid(unsigned int cpu_id) DIR *directory_parent, *directory_node; struct dirent *de, *dn; char directory_path[PATH_MAX]; + char *invalid_number; unsigned int cpu; int node_id = 0; @@ -91,7 +92,9 @@ static unsigned int get_nodeid(unsigned int cpu_id) while ((dn = readdir(directory_node)) != NULL) { if (strncmp(dn->d_name, "cpu", 3)) continue; - cpu = strtoul(dn->d_name + 3, NULL, 0); + cpu = strtoul(dn->d_name + 3, &invalid_number, 0); + if (strcmp(invalid_number, "\0")) + continue; if (cpu == cpu_id) { node_id = strtoul(de->d_name + 4, NULL, 0); diff --git a/testcases/kernel/syscalls/geteuid/geteuid01.c b/testcases/kernel/syscalls/geteuid/geteuid01.c index d02fb0a8d..66fb8936c 100644 --- a/testcases/kernel/syscalls/geteuid/geteuid01.c +++ b/testcases/kernel/syscalls/geteuid/geteuid01.c @@ -1,87 +1,26 @@ +//SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) Linux Test Project, 2003-2023 * - * 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. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * 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. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ - * + * Author: William Roske + * CO-PILOT: Dave Fenner */ -/* - * AUTHOR : William Roske - * CO-PILOT : Dave Fenner +/*\ + *[Description] + * + * Check the basic functionality of the geteuid() system call. */ -#include <sys/types.h> -#include <errno.h> -#include <string.h> -#include <signal.h> - -#include "test.h" -#include "compat_16.h" - -static void setup(void); -static void cleanup(void); - -TCID_DEFINE(geteuid01); -int TST_TOTAL = 1; +#include "tst_test.h" +#include "compat_tst_16.h" -int main(int ac, char **av) +static void verify_geteuid(void) { - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - TEST(GETEUID(cleanup)); - - if (TEST_RETURN < 0) { - tst_resm(TFAIL | TTERRNO, "geteuid failed"); - continue; /* next loop for MTKERNEL */ - } - - tst_resm(TPASS, "geteuid returned %ld", TEST_RETURN); - } - - cleanup(); - tst_exit(); -} - -static void setup(void) -{ - tst_sig(NOFORK, DEF_HANDLER, cleanup); - TEST_PAUSE; + TST_EXP_POSITIVE(GETEUID(), "geteuid()"); } -static void cleanup(void) -{ -} +static struct tst_test test = { + .test_all = verify_geteuid, +}; diff --git a/testcases/kernel/syscalls/geteuid/geteuid02.c b/testcases/kernel/syscalls/geteuid/geteuid02.c index e00f81296..eb2272bff 100644 --- a/testcases/kernel/syscalls/geteuid/geteuid02.c +++ b/testcases/kernel/syscalls/geteuid/geteuid02.c @@ -1,79 +1,36 @@ +//SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) International Business Machines Corp., 2001 - * Ported by Wayne Boyer - * - * 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 + * Copyright (c) Linux Test Project, 2003-2023 + * Ported by Wayne Boyer */ -#include <pwd.h> -#include <errno.h> - -#include "test.h" -#include "compat_16.h" - -TCID_DEFINE(geteuid02); -int TST_TOTAL = 1; +/*\ + *[Description] + * + * Check that geteuid() return value matches value from /proc/self/status. + */ -static void setup(void); -static void cleanup(void); +#include "tst_test.h" +#include "compat_tst_16.h" -int main(int ac, char **av) +static void verify_geteuid(void) { - struct passwd *pwent; - int lc; - uid_t uid; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); + long uid[4]; - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; + TST_EXP_POSITIVE(GETEUID(), "geteuid()"); - TEST(GETEUID(cleanup)); + if (!TST_PASS) + return; - if (TEST_RETURN == -1) - tst_brkm(TBROK | TTERRNO, cleanup, "geteuid* failed"); + SAFE_FILE_LINES_SCANF("/proc/self/status", "Uid: %ld %ld %ld %ld", + &uid[0], &uid[1], &uid[2], &uid[3]); - uid = geteuid(); - pwent = getpwuid(uid); - - if (pwent == NULL) - tst_resm(TFAIL | TERRNO, "getpwuid failed"); - - UID16_CHECK(pwent->pw_uid, geteuid, cleanup); - if (pwent->pw_uid != TEST_RETURN) - tst_resm(TFAIL, "getpwuid value, %d, " - "does not match geteuid " - "value, %ld", pwent->pw_uid, - TEST_RETURN); - else - tst_resm(TPASS, "values from geteuid " - "and getpwuid match"); - } - - cleanup(); - tst_exit(); -} - -static void setup(void) -{ - tst_sig(NOFORK, DEF_HANDLER, cleanup); - TEST_PAUSE; + TST_EXP_EXPR(TST_RET == uid[1], + "geteuid() ret %ld == /proc/self/status EUID: %ld", + TST_RET, uid[1]); } -static void cleanup(void) -{ -} +static struct tst_test test = { + .test_all = verify_geteuid, +}; diff --git a/testcases/kernel/syscalls/getgroups/getgroups01.c b/testcases/kernel/syscalls/getgroups/getgroups01.c index dc3074b75..cfddeb408 100644 --- a/testcases/kernel/syscalls/getgroups/getgroups01.c +++ b/testcases/kernel/syscalls/getgroups/getgroups01.c @@ -95,7 +95,7 @@ int main(int ac, char **av) /* * Check that if ngrps is zero that the number of groups is - * return and the the gidset array is not modified. + * return and the gidset array is not modified. * This is a POSIX special case. */ memset(gidset, 052, NGROUPS * sizeof(GID_T)); diff --git a/testcases/kernel/syscalls/gethostname/gethostname01.c b/testcases/kernel/syscalls/gethostname/gethostname01.c index a7cb5417f..f2276a38c 100644 --- a/testcases/kernel/syscalls/gethostname/gethostname01.c +++ b/testcases/kernel/syscalls/gethostname/gethostname01.c @@ -1,161 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. - * - * 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. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * 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. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ - * + * Copyright (c) 2023 SUSE LLC Ioannis Bonatakis <ybonatakis@suse.com> */ -/* $Id: gethostname01.c,v 1.6 2009/10/26 14:55:47 subrata_modak Exp $ */ -/********************************************************** - * - * OS Test - Silicon Graphics, Inc. - * - * TEST IDENTIFIER : gethostname01 - * - * EXECUTED BY : anyone - * - * TEST TITLE : Basic test for gethostname(2) - * - * PARENT DOCUMENT : usctpl01 - * - * TEST CASE TOTAL : 1 - * - * WALL CLOCK TIME : 1 - * - * CPU TYPES : ALL - * - * AUTHOR : William Roske - * - * CO-PILOT : Dave Fenner - * - * DATE STARTED : 03/30/92 - * - * INITIAL RELEASE : UNICOS 7.0 - * - * TEST CASES - * - * 1.) gethostname(2) returns...(See Description) - * - * INPUT SPECIFICATIONS - * The standard options for system call tests are accepted. - * (See the parse_opts(3) man page). - * - * DURATION - * Terminates - with frequency and infinite modes. - * - * SIGNALS - * Uses SIGUSR1 to pause before test if option set. - * (See the parse_opts(3) man page). - * - * RESOURCES - * None - * - * ENVIRONMENTAL NEEDS - * No run-time environmental needs. - * - * SPECIAL PROCEDURAL REQUIREMENTS - * None - * - * INTERCASE DEPENDENCIES - * None - * - * DETAILED DESCRIPTION - * This is a Phase I test for the gethostname(2) system call. It is intended - * to provide a limited exposure of the system call, for now. It - * should/will be extended when full functional tests are written for - * gethostname(2). - * - * Setup: - * Setup signal handling. - * Pause for SIGUSR1 if option specified. - * - * Test: - * Loop if the proper options are given. - * Execute system call - * Check return code, if system call failed (return=-1) - * Log the errno and Issue a FAIL message. - * Otherwise, Issue a PASS message. - * - * Cleanup: - * Print errno log and/or timing stats if options given - * - * - *#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#**/ - -#include <errno.h> -#include <signal.h> -#include <string.h> - -#include "test.h" - -void setup(); -void cleanup(); - -char *TCID = "gethostname01"; -int TST_TOTAL = 1; - -int main(int ac, char **av) -{ - int lc; - char hname[100]; /* host name */ - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - TEST(gethostname(hname, sizeof(hname))); - - if (TEST_RETURN == -1) { - tst_resm(TFAIL | TTERRNO, "gethostname failed"); - continue; /* next loop for MTKERNEL */ - } - - tst_resm(TPASS, "gethostname returned %ld", - TEST_RETURN); - } +/*\ + * [Description] + * + * Test is checking that gethostname() succeeds. + */ - cleanup(); - tst_exit(); -} +#include "tst_test.h" +#include <stdlib.h> -void setup(void) +static void run(void) { + char hname[100]; - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; + TST_EXP_PASS(gethostname(hname, sizeof(hname))); } -void cleanup(void) -{ -} +static struct tst_test test = { + .test_all = run +}; diff --git a/testcases/kernel/syscalls/getpgid/getpgid01.c b/testcases/kernel/syscalls/getpgid/getpgid01.c index 060486e7e..4c614e0b9 100644 --- a/testcases/kernel/syscalls/getpgid/getpgid01.c +++ b/testcases/kernel/syscalls/getpgid/getpgid01.c @@ -1,145 +1,57 @@ +// 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 + * Copyright (c) International Business Machines Corp., 2001 + * 07/2001 Ported by Wayne Boyer + * Copyright (c) 2023 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> */ -/* - * NAME - * getpgid01.c - * - * DESCRIPTION - * Testcase to check the basic functionality of getpgid(). - * - * ALGORITHM - * block1: Does getpgid(0), and checks for error. - * block2: Does getpgid(getpid()) and checks for error. - * block3: Does getpgid(getppid()) and checks for error. - * block4: Verifies that getpgid(getpgid(0)) == getpgid(0). - * block5: Does getpgid(1) and checks for error. +/*\ + * [Description] * - * USAGE - * getpgid01 - * - * HISTORY - * 07/2001 Ported by Wayne Boyer - * - * RESTRICTIONS - * Expects that there are no EPERM limitations on getting the - * process group ID from proc 1 (init). + * Verify the basic functionality of getpgid(2) syscall. */ -#define _GNU_SOURCE 1 - -#include <errno.h> -#include <unistd.h> -#include <stdarg.h> -#include <sys/wait.h> -#include <sys/types.h> -#include "test.h" -void setup(void); -void cleanup(void); +#include "tst_test.h" -char *TCID = "getpgid01"; -int TST_TOTAL = 1; - -int main(int ac, char **av) +static int get_init_pgid(void) { - int lc; - - register int pgid_0, pgid_1; - register int my_pid, my_ppid; - int ex_stat; - - tst_parse_opts(ac, av, NULL, NULL); + int pgid; - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - - if ((pgid_0 = FORK_OR_VFORK()) == -1) - tst_brkm(TBROK, cleanup, "fork failed"); - if (pgid_0 > 0) { - while ((pgid_0 = wait(&ex_stat)) != -1) ; - - if (WEXITSTATUS(ex_stat) == 0) - tst_resm(TPASS, "%s PASSED", TCID); - else - tst_resm(TFAIL, "%s FAILED", TCID); - - exit(0); - } + SAFE_FILE_SCANF("/proc/1/stat", "%*d %*s %*c %*d %d", &pgid); + return pgid; +} - if ((pgid_0 = getpgid(0)) == -1) - tst_resm(TFAIL | TERRNO, "getpgid(0) failed"); - else - tst_resm(TPASS, "getpgid(0) PASSED"); +static void run(void) +{ + pid_t pid_1, child_pid, pgid; -//block2: - my_pid = getpid(); - if ((pgid_1 = getpgid(my_pid)) == -1) - tst_resm(TFAIL | TERRNO, "getpgid(%d) failed", my_pid); + pgid = getpgid(0); + tst_res(TINFO, "getpgid(0) in parent = %d", pgid); - if (pgid_0 != pgid_1) { - tst_resm(TFAIL, "getpgid(my_pid=%d) != getpgid(0) " - "[%d != %d]", my_pid, pgid_1, pgid_0); - } else - tst_resm(TPASS, "getpgid(getpid()) PASSED"); + pid_1 = SAFE_FORK(); + if (!pid_1) { + child_pid = getpid(); -//block3: - my_ppid = getppid(); - if ((pgid_1 = getpgid(my_ppid)) == -1) - tst_resm(TFAIL | TERRNO, "getpgid(%d) failed", my_ppid); + tst_res(TINFO, "getpid() in child = %d", child_pid); + tst_res(TINFO, "Running getpgid() in child"); - if (pgid_0 != pgid_1) { - tst_resm(TFAIL, "getpgid(%d) != getpgid(0) [%d != %d]", - my_ppid, pgid_1, pgid_0); - } else - tst_resm(TPASS, "getpgid(getppid()) PASSED"); + TST_EXP_PID(getpgid(0)); + TST_EXP_EQ_LI(TST_RET, pgid); -//block4: - if ((pgid_1 = getpgid(pgid_0)) < 0) - tst_resm(TFAIL | TERRNO, "getpgid(%d) failed", pgid_0); + TST_EXP_PID(getpgid(child_pid), "getpgid(%d)", child_pid); + TST_EXP_EQ_LI(TST_RET, pgid); - if (pgid_0 != pgid_1) { - tst_resm(TFAIL, "getpgid(%d) != getpgid(0) [%d != %d]", - pgid_0, pgid_1, pgid_0); - } else - tst_resm(TPASS, "getpgid(%d) PASSED", pgid_0); + TST_EXP_PID(getpgid(pgid), "getpgid(%d)", pgid); + TST_EXP_EQ_LI(TST_RET, pgid); -//block5: - if (getpgid(1) < 0) - tst_resm(TFAIL | TERRNO, "getpgid(1) failed"); - else - tst_resm(TPASS, "getpgid(1) PASSED"); + TST_EXP_PID(getpgid(1)); + TST_EXP_EQ_LI(TST_RET, get_init_pgid()); } - cleanup(); - tst_exit(); + tst_reap_children(); } -void setup(void) -{ - - tst_sig(FORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; -} - -void cleanup(void) -{ -} +static struct tst_test test = { + .test_all = run, + .forks_child = 1 +}; diff --git a/testcases/kernel/syscalls/getpgid/getpgid02.c b/testcases/kernel/syscalls/getpgid/getpgid02.c index 92482e3ae..30d0129bc 100644 --- a/testcases/kernel/syscalls/getpgid/getpgid02.c +++ b/testcases/kernel/syscalls/getpgid/getpgid02.c @@ -1,137 +1,34 @@ +// 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 + * Copyright (c) International Business Machines Corp., 2001 + * 07/2001 Ported by Wayne Boyer + * Copyright (c) 2023 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> */ -/* - * NAME - * getpgid02.c - * - * DESCRIPTION - * Testcase to check the basic functionality of getpgid(). - * - * ALGORITHM - * test 1: Does getpgid(-99) and expects ESRCH. - * test 2: Searches an unused pid and expects ESRCH. - * - * USAGE: <for command-line> - * getpgid02 [-c n] [-e] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -e : Turn on errno logging. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 07/2001 Ported by Wayne Boyer +/*\ + * [Description] * - * RESTRICTIONS - * none + * Verify that getpgid(2) fails with errno ESRCH when + * pid does not match any process. */ -#define _GNU_SOURCE 1 -#include <errno.h> -#include <unistd.h> -#include <stdarg.h> -#include <sys/wait.h> -#include <sys/types.h> -#include "test.h" +#include "tst_test.h" -void setup(void); -void cleanup(void); +static pid_t unused_pid; +static pid_t neg_pid = -99; -char *TCID = "getpgid02"; -int TST_TOTAL = 2; - -int pgid_0, pgid_1; -#define BADPID -99 - -struct test_case_t { - int *id; - int error; -} TC[] = { - /* The pid value is negative */ - { - &pgid_0, ESRCH}, - /* The pid value does not match any process */ - { - &pgid_1, ESRCH} -}; - -int main(int ac, char **av) +static void setup(void) { - int lc; - int i; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - /* reset tst_count in case we are looping */ - tst_count = 0; - - /* loop through the test cases */ - for (i = 0; i < TST_TOTAL; i++) { - - TEST(getpgid(*TC[i].id)); - - if (TEST_RETURN != -1) { - tst_resm(TFAIL, "call succeeded unexpectedly"); - continue; - } - - if (TEST_ERRNO == TC[i].error) { - tst_resm(TPASS, "expected failure - " - "errno = %d : %s", TEST_ERRNO, - strerror(TEST_ERRNO)); - } else { - tst_resm(TFAIL, "unexpected error - %d : %s - " - "expected %d", TEST_ERRNO, - strerror(TEST_ERRNO), TC[i].error); - } - } - } - cleanup(); - - tst_exit(); + unused_pid = tst_get_unused_pid(); } -/* - * setup() - performs all ONE TIME setup for this test. - */ -void setup(void) +static void run(void) { - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - pgid_0 = BADPID; - - pgid_1 = tst_get_unused_pid(cleanup); + TST_EXP_FAIL2(getpgid(neg_pid), ESRCH, "getpgid(%d)", neg_pid); + TST_EXP_FAIL2(getpgid(unused_pid), ESRCH, "getpgid(%d)", unused_pid); } -/* - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - */ -void cleanup(void) -{ - -} +static struct tst_test test = { + .setup = setup, + .test_all = run +}; diff --git a/testcases/kernel/syscalls/getpgrp/getpgrp01.c b/testcases/kernel/syscalls/getpgrp/getpgrp01.c index 61feba8d1..a94736661 100644 --- a/testcases/kernel/syscalls/getpgrp/getpgrp01.c +++ b/testcases/kernel/syscalls/getpgrp/getpgrp01.c @@ -1,160 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. - * - * 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. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * 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. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ - * + * AUTHOR: William Roske, CO-PILOT: Dave Fenner + * Copyright (c) 2023 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> */ -/* $Id: getpgrp01.c,v 1.6 2009/10/26 14:55:47 subrata_modak Exp $ */ -/********************************************************** - * - * OS Test - Silicon Graphics, Inc. - * - * TEST IDENTIFIER : getpgrp01 - * - * EXECUTED BY : anyone - * - * TEST TITLE : Basic test for getpgrp(2) - * - * PARENT DOCUMENT : usctpl01 - * - * TEST CASE TOTAL : 1 - * - * WALL CLOCK TIME : 1 - * - * CPU TYPES : ALL - * - * AUTHOR : William Roske - * - * CO-PILOT : Dave Fenner - * - * DATE STARTED : 03/30/92 - * - * INITIAL RELEASE : UNICOS 7.0 - * - * TEST CASES - * - * 1.) getpgrp(2) returns...(See Description) - * - * INPUT SPECIFICATIONS - * The standard options for system call tests are accepted. - * (See the parse_opts(3) man page). - * - * OUTPUT SPECIFICATIONS - *$ - * DURATION - * Terminates - with frequency and infinite modes. - * - * SIGNALS - * Uses SIGUSR1 to pause before test if option set. - * (See the parse_opts(3) man page). - * - * RESOURCES - * None - * - * ENVIRONMENTAL NEEDS - * No run-time environmental needs. - * - * SPECIAL PROCEDURAL REQUIREMENTS - * None - * - * INTERCASE DEPENDENCIES - * None - * - * DETAILED DESCRIPTION - * This is a Phase I test for the getpgrp(2) system call. It is intended - * to provide a limited exposure of the system call, for now. It - * should/will be extended when full functional tests are written for - * getpgrp(2). - * - * Setup: - * Setup signal handling. - * Pause for SIGUSR1 if option specified. - * - * Test: - * Loop if the proper options are given. - * Execute system call - * Check return code, if system call failed (return=-1) - * Log the errno and Issue a FAIL message. - * Otherwise, Issue a PASS message. - * - * Cleanup: - * Print errno log and/or timing stats if options given - * - * - *#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#**/ - -#include <sys/types.h> -#include <fcntl.h> -#include <errno.h> -#include <signal.h> -#include <string.h> -#include "test.h" - -void setup(); -void cleanup(); - -char *TCID = "getpgrp01"; -int TST_TOTAL = 1; - -int main(int ac, char **av) -{ - int lc; - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - TEST(getpgrp()); - - if (TEST_RETURN == -1) - tst_resm(TFAIL | TTERRNO, "getpgrp failed"); - else - tst_resm(TPASS, "getpgrp returned %ld", TEST_RETURN); - - } +/*\ + * [Description] + * + * Verify that getpgrp(2) syscall executes successfully. + */ - cleanup(); - tst_exit(); -} +#include "tst_test.h" -void setup(void) +static void run(void) { - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; + TST_EXP_PID(getpgrp()); + TST_EXP_EQ_LI(TST_RET, SAFE_GETPGID(0)); } -void cleanup(void) -{ -} +static struct tst_test test = { + .test_all = run +}; diff --git a/testcases/kernel/syscalls/getpid/getpid02.c b/testcases/kernel/syscalls/getpid/getpid02.c index d826724f4..86ad5a29f 100644 --- a/testcases/kernel/syscalls/getpid/getpid02.c +++ b/testcases/kernel/syscalls/getpid/getpid02.c @@ -7,6 +7,7 @@ * [Description] * * Check that: + * * - fork() in parent returns the same pid as getpid() in child * - getppid() in child returns the same pid as getpid() in parent */ diff --git a/testcases/kernel/syscalls/getrusage/getrusage04.c b/testcases/kernel/syscalls/getrusage/getrusage04.c index 06b576d79..b03bc549b 100644 --- a/testcases/kernel/syscalls/getrusage/getrusage04.c +++ b/testcases/kernel/syscalls/getrusage/getrusage04.c @@ -104,8 +104,9 @@ int main(int argc, char *argv[]) tst_count = 0; i = 0; SAFE_GETRUSAGE(cleanup, RUSAGE_THREAD, &usage); - tst_resm(TINFO, "utime:%12luus; stime:%12luus", - usage.ru_utime.tv_usec, usage.ru_stime.tv_usec); + tst_resm(TINFO, "utime:%12lldus; stime:%12lldus", + (long long)usage.ru_utime.tv_usec, + (long long)usage.ru_stime.tv_usec); ulast = usage.ru_utime.tv_usec; slast = usage.ru_stime.tv_usec; @@ -115,9 +116,9 @@ int main(int argc, char *argv[]) sdelta = usage.ru_stime.tv_usec - slast; if (udelta > 0 || sdelta > 0) { i++; - tst_resm(TINFO, "utime:%12luus; stime:%12luus", - usage.ru_utime.tv_usec, - usage.ru_stime.tv_usec); + tst_resm(TINFO, "utime:%12lldus; stime:%12lldus", + (long long)usage.ru_utime.tv_usec, + (long long)usage.ru_stime.tv_usec); if ((long)udelta > 1000 + (BIAS_MAX * factor_nr)) { sprintf(msg_string, "utime increased > %ldus:", diff --git a/testcases/kernel/syscalls/init_module/init_module01.c b/testcases/kernel/syscalls/init_module/init_module01.c index 79e567cd6..26ff0b93b 100644 --- a/testcases/kernel/syscalls/init_module/init_module01.c +++ b/testcases/kernel/syscalls/init_module/init_module01.c @@ -53,6 +53,7 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .needs_root = 1, - /* lockdown requires signed modules */ + /* lockdown and SecureBoot requires signed modules */ .skip_in_lockdown = 1, + .skip_in_secureboot = 1, }; diff --git a/testcases/kernel/syscalls/init_module/init_module02.c b/testcases/kernel/syscalls/init_module/init_module02.c index ad6569a06..e6730e21c 100644 --- a/testcases/kernel/syscalls/init_module/init_module02.c +++ b/testcases/kernel/syscalls/init_module/init_module02.c @@ -22,7 +22,7 @@ #define MODULE_NAME "init_module.ko" static unsigned long size, zero_size; -static int kernel_lockdown; +static int kernel_lockdown, secure_boot; static void *buf, *faulty_buf, *null_buf; static struct tst_cap cap_req = TST_CAP(TST_CAP_REQ, CAP_SYS_MODULE); @@ -53,7 +53,8 @@ static void setup(void) tst_module_exists(MODULE_NAME, NULL); - kernel_lockdown = tst_lockdown_enabled(); + kernel_lockdown = tst_lockdown_enabled() > 0; + secure_boot = tst_secureboot_enabled() > 0; fd = SAFE_OPEN(MODULE_NAME, O_RDONLY|O_CLOEXEC); SAFE_FSTAT(fd, &sb); size = sb.st_size; @@ -67,8 +68,8 @@ static void run(unsigned int n) { struct tcase *tc = &tcases[n]; - if (tc->skip_in_lockdown && kernel_lockdown) { - tst_res(TCONF, "Kernel is locked down, skipping %s", tc->name); + if (tc->skip_in_lockdown && (kernel_lockdown || secure_boot)) { + tst_res(TCONF, "Cannot load unsigned modules, skipping %s", tc->name); return; } diff --git a/testcases/kernel/syscalls/io_uring/io_uring01.c b/testcases/kernel/syscalls/io_uring/io_uring01.c index 70151bb85..ab1ec00d6 100644 --- a/testcases/kernel/syscalls/io_uring/io_uring01.c +++ b/testcases/kernel/syscalls/io_uring/io_uring01.c @@ -264,5 +264,10 @@ static struct tst_test test = { .bufs = (struct tst_buffers []) { {&iov, .iov_sizes = (int[]){BLOCK_SZ, -1}}, {} + }, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/kernel/io_uring_disabled", "0", + TST_SR_SKIP_MISSING | TST_SR_TCONF_RO}, + {} } }; diff --git a/testcases/kernel/syscalls/io_uring/io_uring02.c b/testcases/kernel/syscalls/io_uring/io_uring02.c index c5c770074..c9d4bbcb1 100644 --- a/testcases/kernel/syscalls/io_uring/io_uring02.c +++ b/testcases/kernel/syscalls/io_uring/io_uring02.c @@ -255,6 +255,11 @@ static struct tst_test test = { TST_CAP(TST_CAP_REQ, CAP_SYS_CHROOT), {} }, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/kernel/io_uring_disabled", "0", + TST_SR_SKIP_MISSING | TST_SR_TCONF_RO}, + {} + }, .tags = (const struct tst_tag[]) { {"linux-git", "9392a27d88b9"}, {"linux-git", "ff002b30181d"}, diff --git a/testcases/kernel/syscalls/ioctl/Makefile b/testcases/kernel/syscalls/ioctl/Makefile index c2ff6c8e7..1d40f5e0b 100644 --- a/testcases/kernel/syscalls/ioctl/Makefile +++ b/testcases/kernel/syscalls/ioctl/Makefile @@ -7,6 +7,8 @@ include $(top_srcdir)/include/mk/testcases.mk INSTALL_TARGETS += test_ioctl +ioctl01: LDLIBS+=-lutil + ifeq ($(ANDROID),1) FILTER_OUT_MAKE_TARGETS += ioctl02 endif diff --git a/testcases/kernel/syscalls/ioctl/ioctl01.c b/testcases/kernel/syscalls/ioctl/ioctl01.c index 2989c0e9b..c84a72b9a 100644 --- a/testcases/kernel/syscalls/ioctl/ioctl01.c +++ b/testcases/kernel/syscalls/ioctl/ioctl01.c @@ -2,104 +2,90 @@ /* * Copyright (c) International Business Machines Corp., 2001 * Copyright (c) 2020 Petr Vorel <petr.vorel@gmail.com> + * Copyright (c) Linux Test Project, 2002-2023 * 07/2001 Ported by Wayne Boyer * 04/2002 Fixes by wjhuie + */ + +/*\ + * [Description] * - * Testcase to check the errnos set by the ioctl(2) system call. + * Testcase to check the errnos set by the ioctl(2) system call. * - * ALGORITHM - * 1. EBADF: Pass an invalid fd to ioctl(fd, ..) and expect EBADF. - * 2. EFAULT: Pass an invalid address of arg in ioctl(fd, .., arg) - * 3. EINVAL: Pass invalid cmd in ioctl(fd, cmd, arg) - * 4. ENOTTY: Pass an non-streams fd in ioctl(fd, cmd, arg) - * 5. EFAULT: Pass a NULL address for termio + * - EBADF: Pass an invalid fd to ioctl(fd, ...) and expect EBADF + * - EFAULT: Pass an invalid address of arg in ioctl(fd, ..., arg) + * - EINVAL: Pass invalid cmd in ioctl(fd, cmd, arg) + * - ENOTTY: Pass an non-streams fd in ioctl(fd, cmd, arg) + * - EFAULT: Pass a NULL address for termio */ #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <termios.h> +#include <pty.h> #include "tst_test.h" #include "lapi/ioctl.h" #define INVAL_IOCTL 9999999 +static int amaster, aslave; static int fd, fd_file; static int bfd = -1; static struct termio termio; +static struct termios termios; static struct tcase { + const char *desc; int *fd; int request; - struct termio *s_tio; + void *s_tio; int error; } tcases[] = { - /* file descriptor is invalid */ - {&bfd, TCGETA, &termio, EBADF}, - /* termio address is invalid */ - {&fd, TCGETA, (struct termio *)-1, EFAULT}, - /* command is invalid */ + {"File descriptor is invalid (termio)", &bfd, TCGETA, &termio, EBADF}, + {"File descriptor is invalid (termios)", &bfd, TCGETS, &termios, EBADF}, + {"Termio address is invalid", &fd, TCGETA, (struct termio *)-1, EFAULT}, + {"Termios address is invalid", &fd, TCGETS, (struct termios *)-1, EFAULT}, /* This errno value was changed from EINVAL to ENOTTY * by kernel commit 07d106d0 and bbb63c51 */ - {&fd, INVAL_IOCTL, &termio, ENOTTY}, - /* file descriptor is for a regular file */ - {&fd_file, TCGETA, &termio, ENOTTY}, - /* termio is NULL */ - {&fd, TCGETA, NULL, EFAULT} + {"Command is invalid", &fd, INVAL_IOCTL, &termio, ENOTTY}, + {"File descriptor is for a regular file (termio)", &fd_file, TCGETA, &termio, ENOTTY}, + {"File descriptor is for a regular file (termios)", &fd_file, TCGETS, &termios, ENOTTY}, + {"Termio is NULL", &fd, TCGETA, NULL, EFAULT}, + {"Termios is NULL", &fd, TCGETS, NULL, EFAULT} }; -static char *device; - static void verify_ioctl(unsigned int i) { - TEST(ioctl(*(tcases[i].fd), tcases[i].request, tcases[i].s_tio)); - - if (TST_RET != -1) { - tst_res(TFAIL, "call succeeded unexpectedly"); - return; - } - - if (TST_ERR != tcases[i].error) { - tst_res(TFAIL | TTERRNO, - "failed unexpectedly; expected %s", - tst_strerrno(tcases[i].error)); - return; - } - - tst_res(TPASS | TTERRNO, "failed as expected"); + TST_EXP_FAIL(ioctl(*(tcases[i].fd), tcases[i].request, tcases[i].s_tio), + tcases[i].error, "%s", tcases[i].desc); } static void setup(void) { - unsigned int i; + if (openpty(&amaster, &aslave, NULL, NULL, NULL) < 0) + tst_brk(TBROK | TERRNO, "unable to open pty"); - if (!device) - tst_brk(TBROK, "You must specify a tty device with -D option"); - - fd = SAFE_OPEN(device, O_RDWR, 0777); + fd = amaster; fd_file = SAFE_OPEN("x", O_CREAT, 0777); } static void cleanup(void) { - if (fd > 0) - SAFE_CLOSE(fd); - + if (amaster > 0) + SAFE_CLOSE(amaster); + if (aslave > 0) + SAFE_CLOSE(aslave); if (fd_file > 0) SAFE_CLOSE(fd_file); } static struct tst_test test = { - .needs_root = 1, .needs_tmpdir = 1, .setup = setup, .cleanup = cleanup, .test = verify_ioctl, - .tcnt = ARRAY_SIZE(tcases), - .options = (struct tst_option[]) { - {"D:", &device, "Tty device. For example, /dev/tty[0-9]"}, - {} - } + .tcnt = ARRAY_SIZE(tcases) }; diff --git a/testcases/kernel/syscalls/ioctl/test_ioctl b/testcases/kernel/syscalls/ioctl/test_ioctl index 923275433..43836a229 100755 --- a/testcases/kernel/syscalls/ioctl/test_ioctl +++ b/testcases/kernel/syscalls/ioctl/test_ioctl @@ -41,29 +41,6 @@ case "$device_no" in [0-9]|[0-9][0-9]) has_tty $tttype if [ $? -eq 0 ]; then - tst_resm TINFO "Skipping ioctl01 with $tttype" - continue - fi - tst_resm TINFO "Testing ioctl01 with $tttype" - ioctl01 -D $tttype - RC=$? - if [ $RC -eq 0 ] - then - tst_resm TPASS "ioctl01 Passed with $tttype" - else - tst_resm TFAIL "ioctl01 Failed with $tttype" - fi -echo;; -esac -done - -for tttype in `ls /dev/tty*` -do -device_no=${tttype#/dev/tty} -case "$device_no" in -[0-9]|[0-9][0-9]) - has_tty $tttype - if [ $? -eq 0 ]; then tst_resm TINFO "Skipping ioctl02 with $tttype" continue fi diff --git a/testcases/kernel/syscalls/ioprio/ioprio.h b/testcases/kernel/syscalls/ioprio/ioprio.h index c74380475..dbe27c15f 100644 --- a/testcases/kernel/syscalls/ioprio/ioprio.h +++ b/testcases/kernel/syscalls/ioprio/ioprio.h @@ -1,33 +1,14 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (c) 2019 Linus Walleij <linus.walleij@linaro.org> + * Copyright (c) 2023 Linux Test Project */ #ifndef LTP_IOPRIO_H #define LTP_IOPRIO_H -enum { - IOPRIO_CLASS_NONE = 0, - IOPRIO_CLASS_RT, - IOPRIO_CLASS_BE, - IOPRIO_CLASS_IDLE, -}; - -enum { - IOPRIO_WHO_PROCESS = 1, - IOPRIO_WHO_PGRP, - IOPRIO_WHO_USER, -}; - -/* The I/O scheduler classes have 8 priorities 0..7 except for the IDLE class */ -#define IOPRIO_PRIO_NUM 8 - -#define IOPRIO_CLASS_SHIFT (13) -#define IOPRIO_PRIO_MASK ((1UL << IOPRIO_CLASS_SHIFT) - 1) - -#define IOPRIO_PRIO_CLASS(data) ((data) >> IOPRIO_CLASS_SHIFT) -#define IOPRIO_PRIO_LEVEL(data) ((data) & IOPRIO_PRIO_MASK) -#define IOPRIO_PRIO_VALUE(class, data) (((class) << IOPRIO_CLASS_SHIFT) | data) +#include "lapi/ioprio.h" +#include "lapi/syscalls.h" static const char * const to_class_str[] = { [IOPRIO_CLASS_NONE] = "NONE", @@ -46,10 +27,10 @@ static inline int sys_ioprio_set(int which, int who, int ioprio) return tst_syscall(__NR_ioprio_set, which, who, ioprio); } -/* Priority range from 0 (highest) to 7 (lowest) */ +/* Priority range from 0 (highest) to IOPRIO_PRIO_NUM (lowest) */ static inline int prio_in_range(int prio) { - if ((prio < 0) || (prio > 7)) + if ((prio < 0) || (prio >= IOPRIO_PRIO_NUM)) return 0; return 1; } @@ -91,4 +72,4 @@ static inline void ioprio_check_setting(int class, int prio, int report) newprio); } -#endif +#endif /* LTP_IOPRIO_H */ diff --git a/testcases/kernel/syscalls/ioprio/ioprio_get01.c b/testcases/kernel/syscalls/ioprio/ioprio_get01.c index 6e822434e..f1325be31 100644 --- a/testcases/kernel/syscalls/ioprio/ioprio_get01.c +++ b/testcases/kernel/syscalls/ioprio/ioprio_get01.c @@ -1,16 +1,17 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2019 Linus Walleij <linus.walleij@linaro.org> + * Copyright (c) 2023 Linux Test Project + */ + +/*\ + * [Description] * - * Description: * Basic ioprio_get() test. Gets the current process I/O priority and * checks that the values are sane. */ -#include <sys/types.h> -#include <sys/syscall.h> #include "tst_test.h" -#include "lapi/syscalls.h" #include "ioprio.h" static void run(void) diff --git a/testcases/kernel/syscalls/ioprio/ioprio_set01.c b/testcases/kernel/syscalls/ioprio/ioprio_set01.c index 19953ba36..0868cea7c 100644 --- a/testcases/kernel/syscalls/ioprio/ioprio_set01.c +++ b/testcases/kernel/syscalls/ioprio/ioprio_set01.c @@ -1,17 +1,18 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2019 Linus Walleij <linus.walleij@linaro.org> + * Copyright (c) 2019-2023 Linux Test Project + */ + +/*\ + * [Description] * - * Description: * Basic ioprio_set() test. Gets the current process I/O priority and * bumps it up one notch, then down two notches and checks that the * new priority is reported back correctly. */ -#include <sys/types.h> -#include <sys/syscall.h> #include "tst_test.h" -#include "lapi/syscalls.h" #include "ioprio.h" static int orig_class; diff --git a/testcases/kernel/syscalls/ioprio/ioprio_set02.c b/testcases/kernel/syscalls/ioprio/ioprio_set02.c index 328a130cb..37db7bf42 100644 --- a/testcases/kernel/syscalls/ioprio/ioprio_set02.c +++ b/testcases/kernel/syscalls/ioprio/ioprio_set02.c @@ -1,17 +1,18 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2019 Linus Walleij <linus.walleij@linaro.org> + * Copyright (c) 2023 Linux Test Project + */ + +/*\ + * [Description] * - * Description: * Extended ioprio_set() test. * Tests to set all 8 priority levels for best effort priority, then * switches to test all 8 priority levels for idle priority. */ -#include <sys/types.h> -#include <sys/syscall.h> #include "tst_test.h" -#include "lapi/syscalls.h" #include "ioprio.h" static void run(void) diff --git a/testcases/kernel/syscalls/ioprio/ioprio_set03.c b/testcases/kernel/syscalls/ioprio/ioprio_set03.c index b2c962a6f..6efcacc1c 100644 --- a/testcases/kernel/syscalls/ioprio/ioprio_set03.c +++ b/testcases/kernel/syscalls/ioprio/ioprio_set03.c @@ -1,16 +1,17 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2019 Linus Walleij <linus.walleij@linaro.org> + * Copyright (c) 2023 Linux Test Project + */ + +/*\ + * [Description] * - * Description: * Negative ioprio_set() test. Test some non-working priorities to make * sure they don't work. */ -#include <sys/types.h> -#include <sys/syscall.h> #include "tst_test.h" -#include "lapi/syscalls.h" #include "ioprio.h" static void run(void) @@ -27,7 +28,7 @@ static void run(void) sys_ioprio_set(IOPRIO_WHO_PROCESS, 0, IOPRIO_PRIO_VALUE(class, 4)); TEST(sys_ioprio_set(IOPRIO_WHO_PROCESS, 0, - IOPRIO_PRIO_VALUE(class, 8))); + IOPRIO_PRIO_VALUE(class, IOPRIO_PRIO_NUM))); if (TST_RET == -1) { ioprio_check_setting(class, 4, 1); if (errno == EINVAL) diff --git a/testcases/kernel/syscalls/ipc/msgctl/msgctl01.c b/testcases/kernel/syscalls/ipc/msgctl/msgctl01.c index 75adcb229..56d1505fd 100644 --- a/testcases/kernel/syscalls/ipc/msgctl/msgctl01.c +++ b/testcases/kernel/syscalls/ipc/msgctl/msgctl01.c @@ -6,7 +6,7 @@ */ /* - * Test that IPC_STAT command succeeds and the the buffer is filled with + * Test that IPC_STAT command succeeds and the buffer is filled with * correct data. */ #include <errno.h> diff --git a/testcases/kernel/syscalls/ipc/msgget/msgget02.c b/testcases/kernel/syscalls/ipc/msgget/msgget02.c index ce59a8fb5..1885599d1 100644 --- a/testcases/kernel/syscalls/ipc/msgget/msgget02.c +++ b/testcases/kernel/syscalls/ipc/msgget/msgget02.c @@ -8,11 +8,11 @@ * * Test for EEXIST, ENOENT, EACCES errors. * - * 1) msgget(2) fails if a message queue exists for key and msgflg + * - msgget(2) fails if a message queue exists for key and msgflg * specified both IPC_CREAT and IPC_EXCL. - * 2) msgget(2) fails if no message queue exists for key and msgflg + * - msgget(2) fails if no message queue exists for key and msgflg * did not specify IPC_CREAT. - * 3) msgget(2) fails if a message queue exists for key, but the + * - msgget(2) fails if a message queue exists for key, but the * calling process does not have permission to access the queue, * and does not have the CAP_IPC_OWNER capability. * diff --git a/testcases/kernel/syscalls/ipc/msgstress/msgstress03.c b/testcases/kernel/syscalls/ipc/msgstress/msgstress03.c index 3cb70ab18..aa37d9058 100644 --- a/testcases/kernel/syscalls/ipc/msgstress/msgstress03.c +++ b/testcases/kernel/syscalls/ipc/msgstress/msgstress03.c @@ -110,11 +110,12 @@ int main(int argc, char **argv) } free_pids = tst_get_free_pids(cleanup); - if (nprocs >= free_pids) { + /* Each forked child forks once, take it into account here. */ + if (nprocs * 2 >= free_pids) { tst_resm(TINFO, "Requested number of processes higher than limit (%d > %d), " - "setting to %d", nprocs, free_pids, free_pids); - nprocs = free_pids; + "setting to %d", nprocs * 2, free_pids, free_pids); + nprocs = free_pids / 2; } srand(getpid()); diff --git a/testcases/kernel/syscalls/ipc/semget/.gitignore b/testcases/kernel/syscalls/ipc/semget/.gitignore index ce26c93b0..4519b30d2 100644 --- a/testcases/kernel/syscalls/ipc/semget/.gitignore +++ b/testcases/kernel/syscalls/ipc/semget/.gitignore @@ -1,5 +1,3 @@ /semget01 /semget02 -/semget03 /semget05 -/semget06 diff --git a/testcases/kernel/syscalls/ipc/semget/Makefile b/testcases/kernel/syscalls/ipc/semget/Makefile index 26b9f264d..b1201281d 100644 --- a/testcases/kernel/syscalls/ipc/semget/Makefile +++ b/testcases/kernel/syscalls/ipc/semget/Makefile @@ -3,10 +3,10 @@ top_srcdir ?= ../../../../.. -LTPLIBS = ltpipc +LTPLIBS = ltpnewipc include $(top_srcdir)/include/mk/testcases.mk -LTPLDLIBS = -lltpipc +LTPLDLIBS = -lltpnewipc include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/syscalls/ipc/semget/semget01.c b/testcases/kernel/syscalls/ipc/semget/semget01.c index 217163b3a..872acabd3 100644 --- a/testcases/kernel/syscalls/ipc/semget/semget01.c +++ b/testcases/kernel/syscalls/ipc/semget/semget01.c @@ -1,172 +1,65 @@ +// 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 + * Copyright (c) International Business Machines Corp., 2001 */ -/* - * NAME - * semget01.c - * - * DESCRIPTION - * semget01 - test that semget() correclty creates a semaphore set +/*\ + * [Description] * - * ALGORITHM - * loop if that option was specified - * call semget() to create the semaphore set - * check the return code - * if failure, issue a FAIL message. - * otherwise, - * if doing functionality testing - * stat the semaphore set - * if the number of primitive semaphores is correct and - * the semaphore uid == the process uid - * then, - * issue a PASS message - * otherwise - * issue a FAIL message - * call cleanup - * - * USAGE: <for command-line> - * semget01 [-c n] [-f] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -f : Turn off functionality Testing. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 03/2001 - Written by Wayne Boyer - * - * RESTRICTIONS - * none + * This case checks that semget() correclty creates a semaphore set. */ -#include "ipcsem.h" +#include <unistd.h> +#include <sys/types.h> +#include <sys/ipc.h> +#include "lapi/sem.h" +#include "tst_test.h" +#include "libnewipc.h" +#include "tst_safe_sysv_ipc.h" -char *TCID = "semget01"; -int TST_TOTAL = 1; +static int sem_id = -1, sem_key = -1; -int sem_id_1 = -1; - -int main(int ac, char **av) +static void check_functionality(void) { - int lc; - void check_functionality(void); - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); /* global setup */ - - /* The following loop checks looping state if -i option given */ - - for (lc = 0; TEST_LOOPING(lc); lc++) { - /* reset tst_count in case we are looping */ - tst_count = 0; - - /* - * Use TEST macro to make the call - */ - - TEST(semget(semkey, PSEMS, IPC_CREAT | IPC_EXCL | SEM_RA)); - - if (TEST_RETURN == -1) { - tst_resm(TFAIL, "%s call failed - errno = %d : %s", - TCID, TEST_ERRNO, strerror(TEST_ERRNO)); - } else { - /* get the semaphore ID */ - sem_id_1 = TEST_RETURN; - - check_functionality(); - } - - /* - * remove the semaphore that was created and mark the ID - * as invalid. - */ - if (sem_id_1 != -1) { - rm_sema(sem_id_1); - sem_id_1 = -1; - } - } + struct semid_ds semary; + union semun un_arg; - cleanup(); + un_arg.buf = &semary; + SAFE_SEMCTL(sem_id, 0, IPC_STAT, un_arg); + TST_EXP_EQ_LI(un_arg.buf->sem_nsems, PSEMS); + TST_EXP_EQ_LI(un_arg.buf->sem_perm.cuid, geteuid()); - tst_exit(); + tst_res(TPASS, "basic semaphore values are okay"); } -/* - * check_functionality() - check the functionality of the tested system call. - */ -void check_functionality(void) +static void verify_semget(void) { - struct semid_ds semary; - union semun un_arg; /* union defined in ipcsem.h */ - - /* STAT the semaphore */ - un_arg.buf = &semary; - if (semctl(sem_id_1, 0, IPC_STAT, un_arg) == -1) { - tst_brkm(TBROK, cleanup, "Could not stat the semaphore"); + TEST(semget(sem_key, PSEMS, IPC_CREAT | IPC_EXCL | SEM_RA)); + if (TST_RET == -1) { + tst_res(TFAIL | TTERRNO, "semget() failed"); return; } - if (un_arg.buf->sem_nsems != PSEMS) { - tst_resm(TFAIL, "# of semaphores in set != # given to create"); - return; - } + sem_id = TST_RET; + check_functionality(); - if (un_arg.buf->sem_perm.cuid != geteuid()) { - tst_resm(TFAIL, "semaphore uid != process uid"); - return; - } - - tst_resm(TPASS, "basic semaphore values are okay"); + SAFE_SEMCTL(sem_id, PSEMS, IPC_RMID); } -/* - * setup() - performs all the ONE TIME setup for this test. - */ -void setup(void) +static void setup(void) { - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - /* - * Create a temporary directory and cd into it. - * This helps to ensure that a unique msgkey is created. - * See libs/libltpipc/libipc.c for more information. - */ - tst_tmpdir(); - - /* get an IPC resource key */ - semkey = getipckey(); + sem_key = GETIPCKEY(); } -/* - * cleanup() - performs all the ONE TIME cleanup for this test at completion - * or premature exit. - */ -void cleanup(void) +static void cleanup(void) { - /* if it exists, remove the semaphore resouce */ - rm_sema(sem_id_1); - - tst_rmdir(); - + if (sem_id != -1) + SAFE_SEMCTL(sem_id, PSEMS, IPC_RMID); } + +static struct tst_test test = { + .needs_tmpdir = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = verify_semget, +}; diff --git a/testcases/kernel/syscalls/ipc/semget/semget02.c b/testcases/kernel/syscalls/ipc/semget/semget02.c index 4124514c2..4273c84c7 100644 --- a/testcases/kernel/syscalls/ipc/semget/semget02.c +++ b/testcases/kernel/syscalls/ipc/semget/semget02.c @@ -1,165 +1,102 @@ +// 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 + * Copyright (c) International Business Machines Corp., 2001 */ -/* - * NAME - * semget02.c +/*\ + * [Description] * - * DESCRIPTION - * semget02 - test for EACCES and EEXIST errors + * This basic error handing of the semget syscall. * - * ALGORITHM - * create a semaphore set without read or alter permissions - * loop if that option was specified - * call semget() using two different invalid cases - * check the errno value - * issue a PASS message if we get EACCES or EEXIST - * otherwise, the tests fails - * issue a FAIL message - * call cleanup - * - * USAGE: <for command-line> - * semget02 [-c n] [-e] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -e : Turn on errno logging. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 03/2001 - Written by Wayne Boyer - * - * RESTRICTIONS - * none + * - EACCES - a semaphore set exists for key, but the calling process does not + * have permission to access the set + * - EEXIST - a semaphore set already exists for key and IPC_CREAT | IPC_EXCL + * is given + * - ENOENT - No semaphore set exists for key and semflg did not specify + * IPC_CREAT + * - EINVAL - nsems is less than 0 or greater than the limit on the number of + * semaphores per semaphore set(SEMMSL) + * - EINVAL - a semaphore set corresponding to key already exists, but nsems is + * larger than the number of semaphores in that set */ -#include <pwd.h> - -#include "ipcsem.h" -char *TCID = "semget02"; -int TST_TOTAL = 2; - -char nobody_uid[] = "nobody"; -struct passwd *ltpuser; - -int sem_id_1 = -1; - -struct test_case_t { +#include <stdlib.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/ipc.h> +#include <sys/types.h> +#include <pwd.h> +#include "tst_test.h" +#include "tst_safe_sysv_ipc.h" +#include "libnewipc.h" +#include "lapi/sem.h" + +static int sem_id = -1; +static key_t semkey, semkey1; +static struct passwd *pw; +static struct tcase { + int *key; + int nsems; int flags; - int error; -} TC[] = { - /* EACCES - the semaphore has no read or alter permissions */ - { - SEM_RA, EACCES}, - /* EEXIST - the semaphore id exists and semget() was called with */ - /* IPC_CREAT and IPC_EXCL */ - { - IPC_CREAT | IPC_EXCL, EEXIST} + int exp_err; + /*1: nobody expected, 0: root expected */ + int exp_user; +} tcases[] = { + {&semkey, PSEMS, SEM_RA, EACCES, 1}, + {&semkey, PSEMS, IPC_CREAT | IPC_EXCL, EEXIST, 0}, + {&semkey1, PSEMS, SEM_RA, ENOENT, 0}, + {&semkey1, -1, IPC_CREAT | IPC_EXCL, EINVAL, 0}, + {&semkey1, SEMMSL + 1, IPC_CREAT | IPC_EXCL, EINVAL, 0}, + {&semkey, PSEMS + 1, SEM_RA, EINVAL, 0}, }; -int main(int ac, char **av) +static void verify_semget(struct tcase *tc) { - int lc; - int i; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); /* global setup */ - - /* The following loop checks looping state if -i option given */ - - for (lc = 0; TEST_LOOPING(lc); lc++) { - /* reset tst_count in case we are looping */ - tst_count = 0; - - for (i = 0; i < TST_TOTAL; i++) { - /* use the TEST macro to make the call */ - - TEST(semget(semkey, PSEMS, TC[i].flags)); - - if (TEST_RETURN != -1) { - sem_id_1 = TEST_RETURN; - tst_resm(TFAIL, "call succeeded"); - continue; - } + TST_EXP_FAIL2(semget(*tc->key, tc->nsems, tc->flags), tc->exp_err, + "semget(%i, %i, %i)", *tc->key, tc->nsems, tc->flags); +} - if (TEST_ERRNO == TC[i].error) { - tst_resm(TPASS, "expected failure - errno " - "= %d : %s", TEST_ERRNO, - strerror(TEST_ERRNO)); - } else { - tst_resm(TFAIL, "unexpected error - %d : %s", - TEST_ERRNO, strerror(TEST_ERRNO)); - } +static void do_test(unsigned int n) +{ + pid_t pid; + struct tcase *tc = &tcases[n]; + + if (tc->exp_user == 0) { + verify_semget(tc); + } else { + pid = SAFE_FORK(); + if (pid) { + tst_reap_children(); + } else { + SAFE_SETUID(pw->pw_uid); + verify_semget(tc); + exit(0); } } - - cleanup(); - - tst_exit(); } -/* - * setup() - performs all the ONE TIME setup for this test. - */ -void setup(void) +static void setup(void) { - tst_require_root(); - - /* Switch to nobody user for correct error code collection */ - ltpuser = getpwnam(nobody_uid); - if (seteuid(ltpuser->pw_uid) == -1) { - tst_resm(TINFO, "setreuid failed to " - "to set the effective uid to %d", ltpuser->pw_uid); - perror("setreuid"); - } - - tst_sig(NOFORK, DEF_HANDLER, cleanup); + semkey = GETIPCKEY(); + semkey1 = GETIPCKEY(); - TEST_PAUSE; + sem_id = SAFE_SEMGET(semkey, PSEMS, IPC_CREAT | IPC_EXCL); - /* - * Create a temporary directory and cd into it. - * This helps to ensure that a unique msgkey is created. - * See libs/libltpipc/libipc.c for more information. - */ - tst_tmpdir(); - - /* get an IPC resource key */ - semkey = getipckey(); - - /* create a semaphore set without read or alter permissions */ - if ((sem_id_1 = semget(semkey, PSEMS, IPC_CREAT | IPC_EXCL)) == -1) { - tst_brkm(TBROK, cleanup, "couldn't create semaphore in setup"); - } + pw = SAFE_GETPWNAM("nobody"); } -/* - * cleanup() - performs all the ONE TIME cleanup for this test at completion - * or premature exit. - */ -void cleanup(void) +static void cleanup(void) { - /* if it exists, remove the semaphore resource */ - rm_sema(sem_id_1); - - tst_rmdir(); - + if (sem_id != -1) + SAFE_SEMCTL(sem_id, PSEMS, IPC_RMID); } + +static struct tst_test test = { + .needs_tmpdir = 1, + .needs_root = 1, + .forks_child = 1, + .tcnt = ARRAY_SIZE(tcases), + .setup = setup, + .cleanup = cleanup, + .test = do_test, +}; diff --git a/testcases/kernel/syscalls/ipc/semget/semget03.c b/testcases/kernel/syscalls/ipc/semget/semget03.c deleted file mode 100644 index 995b4bd3a..000000000 --- a/testcases/kernel/syscalls/ipc/semget/semget03.c +++ /dev/null @@ -1,133 +0,0 @@ -/* - * - * 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 - */ - -/* - * NAME - * semget03.c - * - * DESCRIPTION - * semget03 - test for ENOENT error - * - * ALGORITHM - * loop if that option was specified - * call semget() with a valid key but with no associated semaphore set - * and IPC_CREAT is not asserted - * check the errno value - * issue a PASS message if we get ENOENT - * otherwise, the tests fails - * issue a FAIL message - * call cleanup - * - * USAGE: <for command-line> - * semget03 [-c n] [-e] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -e : Turn on errno logging. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 03/2001 - Written by Wayne Boyer - * - * RESTRICTIONS - * none - */ - -#include "ipcsem.h" - -char *TCID = "semget03"; -int TST_TOTAL = 1; - -int sem_id_1 = -1; - -int main(int ac, char **av) -{ - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); /* global setup */ - - /* The following loop checks looping state if -i option given */ - - for (lc = 0; TEST_LOOPING(lc); lc++) { - /* reset tst_count in case we are looping */ - tst_count = 0; - - /* use the TEST macro to make the call */ - - TEST(semget(semkey, PSEMS, SEM_RA)); - - if (TEST_RETURN != -1) { - sem_id_1 = TEST_RETURN; - tst_resm(TFAIL, "call succeeded when error expected"); - continue; - } - - switch (TEST_ERRNO) { - case ENOENT: - tst_resm(TPASS, "expected failure - errno " - "= %d : %s", TEST_ERRNO, strerror(TEST_ERRNO)); - break; - default: - tst_resm(TFAIL, "unexpected error - %d : %s", - TEST_ERRNO, strerror(TEST_ERRNO)); - break; - } - } - - cleanup(); - - tst_exit(); -} - -/* - * setup() - performs all the ONE TIME setup for this test. - */ -void setup(void) -{ - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - /* - * Create a temporary directory and cd into it. - * This helps to ensure that a unique msgkey is created. - * See libs/libltpipc/libipc.c for more information. - */ - tst_tmpdir(); - - /* get an IPC resource key */ - semkey = getipckey(); -} - -/* - * cleanup() - performs all the ONE TIME cleanup for this test at completion - * or premature exit. - */ -void cleanup(void) -{ - /* if it exists, remove the semaphore resource */ - rm_sema(sem_id_1); - - tst_rmdir(); - -} diff --git a/testcases/kernel/syscalls/ipc/semget/semget05.c b/testcases/kernel/syscalls/ipc/semget/semget05.c index f801cb8ed..dd9a6285d 100644 --- a/testcases/kernel/syscalls/ipc/semget/semget05.c +++ b/testcases/kernel/syscalls/ipc/semget/semget05.c @@ -1,152 +1,83 @@ +// 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 + * Copyright (c) International Business Machines Corp., 2001 */ -/* - * NAME - * semget05.c - * - * DESCRIPTION - * semget05 - test for ENOSPC error +/*\ + * [Description] * - * ALGORITHM - * create semaphore sets in a loop until the system limit is reached - * loop if that option was specified - * attempt to create yet another semaphore set - * check the errno value - * issue a PASS message if we get ENOSPC - * otherwise, the tests fails - * issue a FAIL message - * call cleanup + * Test for ENOSPC error. * - * USAGE: <for command-line> - * HISTORY - * 03/2001 - Written by Wayne Boyer - * 07/2006 - Changes By Michael Reed - * - Changed the value of MAXIDS for the specific machine by reading - * the system limit for SEMMNI - The maximum number of sempahore sets - * 03/2008 - Matthieu Fertré (mfertre@irisa.fr) - * - Fix concurrency issue. Create private semaphores to - * avoid conflict with concurrent processes. - * - * RESTRICTIONS - * none - */ - -#include "ipcsem.h" - -char *TCID = "semget05"; -int TST_TOTAL = 1; - -/* - * The MAXIDS value is somewhat arbitrary and may need to be increased - * depending on the system being tested. + * ENOSPC - a semaphore set exceed the maximum number of semaphore sets(SEMMNI) */ -int MAXIDS = 2048; - -int *sem_id_arr = NULL; -int num_sems = 0; /* count the semaphores created */ - -int main(int ac, char **av) +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/ipc.h> +#include "lapi/sem.h" +#include "tst_test.h" +#include "libnewipc.h" +#include "tst_safe_sysv_ipc.h" + +static int *sem_id_arr; +static int maxsems, array_cnt, used_cnt; +static key_t semkey; + +static void verify_semget(void) { - int lc; - FILE *fp; - - tst_parse_opts(ac, av, NULL, NULL); - - /* Set the MAXIDS for the specific machine by reading the system limit - * for SEMMNI - The maximum number of sempahore sets - */ - fp = fopen("/proc/sys/kernel/sem", "r"); - if (fp != NULL) { - int getmaxid; - if (fscanf(fp, "%*d %*d %*d %d", &getmaxid) == 1) - MAXIDS = getmaxid + 1; - fclose(fp); - } - - sem_id_arr = malloc(sizeof(int) * MAXIDS); - if (sem_id_arr == NULL) - tst_brkm(TBROK, cleanup, "malloc failed"); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - - - TEST(semget(IPC_PRIVATE, PSEMS, IPC_CREAT | IPC_EXCL | SEM_RA)); - if (TEST_RETURN != -1) { - tst_resm(TFAIL, "call succeeded when error expected"); - continue; - } - - switch (TEST_ERRNO) { - case ENOSPC: - tst_resm(TPASS, "expected failure - errno " - "= %d : %s", TEST_ERRNO, strerror(TEST_ERRNO)); - break; - default: - tst_resm(TFAIL, "unexpected error - %d : %s", - TEST_ERRNO, strerror(TEST_ERRNO)); - break; - } - } - - cleanup(); - - tst_exit(); + TST_EXP_FAIL2(semget(semkey + maxsems, PSEMS, IPC_CREAT | IPC_EXCL | SEM_RA), + ENOSPC, "semget(%i, %i, %i)", semkey + maxsems, PSEMS, + IPC_CREAT | IPC_EXCL | SEM_RA); } -void setup(void) +static void setup(void) { - int sem_q; + int res, num; - tst_sig(NOFORK, DEF_HANDLER, cleanup); + semkey = GETIPCKEY(); + used_cnt = GET_USED_ARRAYS(); + tst_res(TINFO, "Current environment %d semaphore arrays are already in use", + used_cnt); + SAFE_FILE_SCANF("/proc/sys/kernel/sem", "%*d %*d %*d %d", &maxsems); - TEST_PAUSE; + /* Prevent timeout due to high semaphore array limit */ + tst_set_max_runtime(maxsems / 200); - tst_tmpdir(); - - while ((sem_q = semget(IPC_PRIVATE, PSEMS, IPC_CREAT | IPC_EXCL)) != -1) { - sem_id_arr[num_sems++] = sem_q; - if (num_sems == MAXIDS) { - tst_brkm(TBROK, cleanup, "The maximum number of " - "semaphore ID's has been\n\t reached. Please " - "increase the MAXIDS value in the test."); - } - } + sem_id_arr = SAFE_MALLOC((maxsems - used_cnt) * sizeof(int)); + for (num = 0; num < maxsems - used_cnt; num++) { + res = semget(semkey + num, PSEMS, IPC_CREAT | IPC_EXCL | SEM_RA); + if (res == -1) + tst_brk(TBROK | TERRNO, "semget failed unexpectedly"); - if (errno != ENOSPC) { - tst_brkm(TBROK, cleanup, "Didn't get ENOSPC in test setup" - " - errno = %d : %s", errno, strerror(errno)); + sem_id_arr[array_cnt++] = res; } + tst_res(TINFO, "The maximum number of semaphore arrays (%d) has been reached", + maxsems); } -void cleanup(void) +static void cleanup(void) { - int i; + int num; - for (i = 0; i < num_sems; i++) { - rm_sema(sem_id_arr[i]); - } + if (!sem_id_arr) + return; + + for (num = 0; num < array_cnt; num++) + SAFE_SEMCTL(sem_id_arr[num], PSEMS, IPC_RMID); free(sem_id_arr); - tst_rmdir(); } + +static struct tst_test test = { + .needs_tmpdir = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = verify_semget, + .save_restore = (const struct tst_path_val[]){ + {"/proc/sys/kernel/sem", NULL, + TST_SR_TCONF_MISSING | TST_SR_SKIP_RO}, + {} + } +}; diff --git a/testcases/kernel/syscalls/ipc/semget/semget06.c b/testcases/kernel/syscalls/ipc/semget/semget06.c deleted file mode 100644 index 52297c010..000000000 --- a/testcases/kernel/syscalls/ipc/semget/semget06.c +++ /dev/null @@ -1,143 +0,0 @@ -/* - * - * 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 - */ - -/* - * NAME - * semget06.c - * - * DESCRIPTION - * semget06 - test for EINVAL error - * - * ALGORITHM - * loop if that option was specified - * call semget() using two different invalid cases - too many and too - * few primitive semaphores - * check the errno value - * issue a PASS message if we get EINVAL - * otherwise, the tests fails - * issue a FAIL message - * call cleanup - * - * USAGE: <for command-line> - * semget06 [-c n] [-e] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -e : Turn on errno logging. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 03/2001 - Written by Wayne Boyer - * - * RESTRICTIONS - * none - */ - -#include "ipcsem.h" - -char *TCID = "semget06"; -int TST_TOTAL = 2; - -#define LARGENUM 1024 * 32 -#define SMALLNUM -1 - -int sem_id_1 = -1; - -int num_sems[] = { LARGENUM, SMALLNUM }; - -int main(int ac, char **av) -{ - int lc; - int i; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); /* global setup */ - - /* The following loop checks looping state if -i option given */ - - for (lc = 0; TEST_LOOPING(lc); lc++) { - /* reset tst_count in case we are looping */ - tst_count = 0; - - /* loop through the test cases */ - - for (i = 0; i < TST_TOTAL; i++) { - TEST(semget(semkey, num_sems[i], - IPC_CREAT | IPC_EXCL | SEM_RA)); - - if (TEST_RETURN != -1) { - sem_id_1 = TEST_RETURN; - tst_resm(TFAIL, "call succeeded"); - continue; - } - - switch (TEST_ERRNO) { - case EINVAL: - tst_resm(TPASS, "expected failure - errno " - "= %d : %s", TEST_ERRNO, - strerror(TEST_ERRNO)); - break; - default: - tst_resm(TFAIL, "unexpected error - %d : %s", - TEST_ERRNO, strerror(TEST_ERRNO)); - break; - } - } - } - - cleanup(); - - tst_exit(); -} - -/* - * setup() - performs all the ONE TIME setup for this test. - */ -void setup(void) -{ - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - /* - * Create a temporary directory and cd into it. - * This helps to ensure that a unique msgkey is created. - * See libs/libltpipc/libipc.c for more information. - */ - tst_tmpdir(); - - /* get an IPC resource key */ - semkey = getipckey(); -} - -/* - * cleanup() - performs all the ONE TIME cleanup for this test at completion - * or premature exit. - */ -void cleanup(void) -{ - /* if it exists, remove the semaphore resource */ - rm_sema(sem_id_1); - - tst_rmdir(); - -} diff --git a/testcases/kernel/syscalls/ipc/semop/.gitignore b/testcases/kernel/syscalls/ipc/semop/.gitignore index bb57f08af..cc67b1862 100644 --- a/testcases/kernel/syscalls/ipc/semop/.gitignore +++ b/testcases/kernel/syscalls/ipc/semop/.gitignore @@ -1,3 +1,5 @@ /semop01 /semop02 /semop03 +/semop04 +/semop05 diff --git a/testcases/kernel/syscalls/ipc/semop/Makefile b/testcases/kernel/syscalls/ipc/semop/Makefile index 6b2b26d05..43afffb3f 100644 --- a/testcases/kernel/syscalls/ipc/semop/Makefile +++ b/testcases/kernel/syscalls/ipc/semop/Makefile @@ -7,6 +7,9 @@ LTPLIBS = ltpnewipc include $(top_srcdir)/include/mk/testcases.mk -LTPLDLIBS = -lltpnewipc +semop01: LTPLDLIBS = -lltpnewipc +semop02: LTPLDLIBS = -lltpnewipc +semop03: LTPLDLIBS = -lltpnewipc +semop05: LDLIBS += -lpthread include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/syscalls/ipc/semop/semop04.c b/testcases/kernel/syscalls/ipc/semop/semop04.c new file mode 100644 index 000000000..1f49e7740 --- /dev/null +++ b/testcases/kernel/syscalls/ipc/semop/semop04.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) International Business Machines Corp., 2001 + * Copyright (C) 2003-2023 Linux Test Project, Inc. + * Author: 2001 Paul Larson <plars@us.ibm.com> + * Modified: 2001 Manoj Iyer <manjo@ausin.ibm.com> + */ + +/*\ + * [Description] + * + * Creates a semaphore and two processes. The processes + * each go through a loop where they semdown, delay for a + * random amount of time, and semup, so they will almost + * always be fighting for control of the semaphore. + */ + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/ipc.h> +#include "lapi/sem.h" +#include "tst_test.h" +#include "tst_safe_sysv_ipc.h" + +#define LOOPS 1000 +#define SEED 123 + +static void semup(int semid) +{ + struct sembuf semops; + + semops.sem_num = 0; + semops.sem_op = 1; + semops.sem_flg = SEM_UNDO; + + SAFE_SEMOP(semid, &semops, 1); +} + +static void semdown(int semid) +{ + struct sembuf semops; + + semops.sem_num = 0; + semops.sem_op = -1; + semops.sem_flg = SEM_UNDO; + + SAFE_SEMOP(semid, &semops, 1); +} + +static void mainloop(int semid) +{ + int i; + + for (i = 0; i < LOOPS; i++) { + semdown(semid); + usleep(1 + ((100.0 * rand()) / RAND_MAX)); + semup(semid); + } +} + +static void run(void) +{ + int semid; + union semun semunion; + pid_t pid; + + /* set up the semaphore */ + semid = SAFE_SEMGET((key_t) 9142, 1, 0666 | IPC_CREAT); + + semunion.val = 1; + + SAFE_SEMCTL(semid, 0, SETVAL, semunion); + + tst_res(TINFO, "srand seed is %d", SEED); + srand(SEED); + + pid = SAFE_FORK(); + + if (pid) { + mainloop(semid); + tst_reap_children(); + TST_EXP_POSITIVE(semctl(semid, 0, IPC_RMID, semunion)); + } else { + mainloop(semid); + } +} + +static struct tst_test test = { + .test_all = run, + .forks_child = 1, +}; diff --git a/testcases/kernel/syscalls/ipc/semop/semop05.c b/testcases/kernel/syscalls/ipc/semop/semop05.c new file mode 100644 index 000000000..34b714bf0 --- /dev/null +++ b/testcases/kernel/syscalls/ipc/semop/semop05.c @@ -0,0 +1,157 @@ +/* + * + * Copyright (c) International Business Machines Corp., 2002 + * + * 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 + */ + +/* + * FILE : sem02.c + * + * DESCRIPTION : The application creates several threads using pthread_create(). + * One thread performs a semop() with the SEM_UNDO flag set. The change in + * sempaphore value performed by that semop should be "undone" only when the + * last pthread exits. + * + * EXPECTED OUTPUT: + * Waiter, pid = <pid#> + * Poster, pid = <pid#>, posting + * Poster posted + * Poster exiting + * Waiter waiting, pid = <pid#> + * Waiter done waiting + * + * HISTORY: + * written by Dave Olien (oliend@us.ibm.com) + * 03/06/2002 Robbie Williamson (robbiew@us.ibm.com) + * -ported + * 07/04/2003 Paul Larson (plars@linuxtestproject.org) + * -ported to LTP + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <pthread.h> +#include <sys/types.h> +#include <sys/ipc.h> +#include "lapi/sem.h" +#include "test.h" + +#define KEY IPC_PRIVATE + +#define NUMTHREADS 2 + +void *retval[NUMTHREADS]; +void *waiter(void *); +void *poster(void *); +void cleanup(void); + +char *TCID = "sem02"; +int TST_TOTAL = 1; + +struct sembuf Psembuf = { 0, -1, SEM_UNDO }; +struct sembuf Vsembuf = { 0, 1, SEM_UNDO }; + +int sem_id; +int err_ret; /* This is used to determine PASS/FAIL status */ +int main(int argc, char **argv) +{ + int i, rc; + union semun semunion; + + pthread_t pt[NUMTHREADS]; + pthread_attr_t attr; + + tst_parse_opts(argc, argv, NULL, NULL); + /* Create the semaphore set */ + sem_id = semget(KEY, 1, 0666 | IPC_CREAT); + if (sem_id < 0) { + printf("semget failed, errno = %d\n", errno); + exit(1); + } + /* initialize data structure associated to the semaphore */ + semunion.val = 1; + semctl(sem_id, 0, SETVAL, semunion); + + /* setup the attributes of the thread */ + /* set the scope to be system to make sure the threads compete on a */ + /* global scale for cpu */ + pthread_attr_init(&attr); + pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); + + err_ret = 1; /* Set initial error value to 1 */ + /* Create the threads */ + for (i = 0; i < NUMTHREADS; i++) { + if (i == 0) + rc = pthread_create(&pt[i], &attr, waiter, retval[i]); + else + rc = pthread_create(&pt[i], &attr, poster, retval[i]); + } + + /* Sleep long enough to see that the other threads do what they are supposed to do */ + sleep(20); + semunion.val = 1; + semctl(sem_id, 0, IPC_RMID, semunion); + if (err_ret == 1) + tst_resm(TFAIL, "failed"); + else + tst_resm(TPASS, "passed"); + cleanup(); + + tst_exit(); +} + +/* This thread sleeps 10 seconds then waits on the semaphore. As long + as someone has posted on the semaphore, and no undo has taken + place, the semop should complete and we'll print "Waiter done + waiting." */ +void *waiter(void *foo) +{ + int pid; + pid = getpid(); + + tst_resm(TINFO, "Waiter, pid = %d", pid); + sleep(10); + + tst_resm(TINFO, "Waiter waiting, pid = %d", pid); + semop(sem_id, &Psembuf, 1); + tst_resm(TINFO, "Waiter done waiting"); + err_ret = 0; /* If the message above is displayed, the test is a PASS */ + pthread_exit(0); +} + +/* This thread immediately posts on the semaphore and then immediately + exits. If the *thread* exits, the undo should not happen, and the + waiter thread which will start waiting on it in 10 seconds, should + still get it. */ +void *poster(void *foo) +{ + int pid; + + pid = getpid(); + tst_resm(TINFO, "Poster, pid = %d, posting", pid); + semop(sem_id, &Vsembuf, 1); + tst_resm(TINFO, "Poster posted"); + tst_resm(TINFO, "Poster exiting"); + + pthread_exit(0); +} + +void cleanup(void) +{ +} diff --git a/testcases/kernel/syscalls/ipc/shmget/shmget02.c b/testcases/kernel/syscalls/ipc/shmget/shmget02.c index 3788e711f..8168803a5 100644 --- a/testcases/kernel/syscalls/ipc/shmget/shmget02.c +++ b/testcases/kernel/syscalls/ipc/shmget/shmget02.c @@ -11,17 +11,17 @@ * * Test for ENOENT, EEXIST, EINVAL, EACCES, EPERM errors. * - * ENOENT - No segment exists for the given key and IPC_CREAT was not specified. - * EEXIST - the segment exists and IPC_CREAT | IPC_EXCL is given. - * EINVAL - A new segment was to be created and size is less than SHMMIN or - * greater than SHMMAX. Or a segment for the given key exists, but size is - * gran eater than the size of that segment. - * EACCES - The user does not have permission to access the shared memory segment. - * EPERM - The SHM_HUGETLB flag was specified, but the caller was not privileged - * (did not have the CAP_IPC_LOCK capability) and is not a member of the - * sysctl_hugetlb_shm_group group. - * ENOMEM - The SHM_HUGETLB flag was specified, the caller was privileged but not - * have enough hugepage memory space. + * - ENOENT - No segment exists for the given key and IPC_CREAT was not specified. + * - EEXIST - the segment exists and IPC_CREAT | IPC_EXCL is given. + * - EINVAL - A new segment was to be created and size is less than SHMMIN or + * greater than SHMMAX. Or a segment for the given key exists, but size is + * gran eater than the size of that segment. + * - EACCES - The user does not have permission to access the shared memory segment. + * - EPERM - The SHM_HUGETLB flag was specified, but the caller was not + * privileged (did not have the CAP_IPC_LOCK capability) and is not a member + * of the sysctl_hugetlb_shm_group group. + * - ENOMEM - The SHM_HUGETLB flag was specified, the caller was privileged but + * not have enough hugepage memory space. */ #include <errno.h> @@ -56,7 +56,7 @@ static struct tcase { {&shmkey1, SHM_SIZE, IPC_EXCL, 0, 0, ENOENT}, {&shmkey, SHM_SIZE, IPC_CREAT | IPC_EXCL, 0, 0, EEXIST}, {&shmkey1, SHMMIN - 1, IPC_CREAT | IPC_EXCL, 0, 0, EINVAL}, - {&shmkey1, SHMMAX + 1, IPC_CREAT | IPC_EXCL, 0, 0, EINVAL}, + {&shmkey1, 8192 + 1, IPC_CREAT | IPC_EXCL, 0, 0, EINVAL}, {&shmkey, SHM_SIZE * 2, IPC_EXCL, 0, 0, EINVAL}, {&shmkey, SHM_SIZE, SHM_RD, 1, 0, EACCES}, {&shmkey1, SHM_SIZE, IPC_CREAT | SHM_HUGETLB, 0, 1, EPERM}, @@ -149,4 +149,8 @@ static struct tst_test test = { .test = do_test, .tcnt = ARRAY_SIZE(tcases), .hugepages = {TST_NO_HUGEPAGES}, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/kernel/shmmax", "8192", TST_SR_TCONF_MISSING | TST_SR_TBROK_RO}, + {} + }, }; diff --git a/testcases/kernel/syscalls/keyctl/keyctl02.c b/testcases/kernel/syscalls/keyctl/keyctl02.c index 572f34b16..35cc2838d 100644 --- a/testcases/kernel/syscalls/keyctl/keyctl02.c +++ b/testcases/kernel/syscalls/keyctl/keyctl02.c @@ -144,6 +144,7 @@ static struct tst_test test = { .test_all = do_test, .tags = (const struct tst_tag[]) { {"linux-git", "b4a1b4f5047e"}, + {"CVE", "2015-7550"}, {} } }; diff --git a/testcases/kernel/syscalls/keyctl/keyctl07.c b/testcases/kernel/syscalls/keyctl/keyctl07.c index 875ef0bb8..d9e20db5f 100644 --- a/testcases/kernel/syscalls/keyctl/keyctl07.c +++ b/testcases/kernel/syscalls/keyctl/keyctl07.c @@ -104,7 +104,7 @@ static struct tst_test test = { .test_all = do_test, .forks_child = 1, .tags = (const struct tst_tag[]) { - {"CVE", "2017-12912"}, + {"CVE", "2017-12192"}, {"linux-git", "37863c43b2c6"}, {} } diff --git a/testcases/kernel/syscalls/madvise/.gitignore b/testcases/kernel/syscalls/madvise/.gitignore index f4bfdfefe..722ac3c34 100644 --- a/testcases/kernel/syscalls/madvise/.gitignore +++ b/testcases/kernel/syscalls/madvise/.gitignore @@ -7,3 +7,4 @@ /madvise08 /madvise09 /madvise10 +/madvise11 diff --git a/testcases/kernel/syscalls/madvise/Makefile b/testcases/kernel/syscalls/madvise/Makefile index 044619fb8..78613df11 100644 --- a/testcases/kernel/syscalls/madvise/Makefile +++ b/testcases/kernel/syscalls/madvise/Makefile @@ -6,3 +6,5 @@ top_srcdir ?= ../../../.. include $(top_srcdir)/include/mk/testcases.mk include $(top_srcdir)/include/mk/generic_leaf_target.mk + +madvise11: CFLAGS += -pthread diff --git a/testcases/kernel/syscalls/madvise/madvise01.c b/testcases/kernel/syscalls/madvise/madvise01.c index 2262bf12d..884c59b0b 100644 --- a/testcases/kernel/syscalls/madvise/madvise01.c +++ b/testcases/kernel/syscalls/madvise/madvise01.c @@ -11,7 +11,6 @@ */ #include <sys/types.h> -#include <sys/mman.h> #include <sys/stat.h> #include <sys/mount.h> #include <errno.h> diff --git a/testcases/kernel/syscalls/madvise/madvise02.c b/testcases/kernel/syscalls/madvise/madvise02.c index 858d67ae2..90c0431c5 100644 --- a/testcases/kernel/syscalls/madvise/madvise02.c +++ b/testcases/kernel/syscalls/madvise/madvise02.c @@ -30,7 +30,6 @@ */ #include <sys/types.h> -#include <sys/mman.h> #include <sys/resource.h> #include <sys/stat.h> #include <sys/time.h> diff --git a/testcases/kernel/syscalls/madvise/madvise06.c b/testcases/kernel/syscalls/madvise/madvise06.c index c7967ae6f..be22318ea 100644 --- a/testcases/kernel/syscalls/madvise/madvise06.c +++ b/testcases/kernel/syscalls/madvise/madvise06.c @@ -198,7 +198,7 @@ static void test_advice_willneed(void) meminfo_diag("After madvise"); res = swapcached > swapcached_start + PASS_THRESHOLD_KB; - tst_res(res ? TPASS : TFAIL, + tst_res(res ? TPASS : TINFO, "%s than %ld Kb were moved to the swap cache", res ? "more" : "less", PASS_THRESHOLD_KB); @@ -226,10 +226,15 @@ static void test_advice_willneed(void) meminfo_diag("After page access"); res = page_fault_num_2 - page_fault_num_1; - tst_res(res == 0 ? TPASS : TFAIL, + tst_res(res == 0 ? TPASS : TINFO, "%d pages were faulted out of 3 max", res); SAFE_MUNMAP(target, CHUNK_SZ); + + if (tst_taint_check()) + tst_res(TFAIL, "Kernel tainted"); + else + tst_res(TPASS, "No kernel taints"); } static struct tst_test test = { @@ -237,6 +242,7 @@ static struct tst_test test = { .setup = setup, .needs_tmpdir = 1, .needs_root = 1, + .taint_check = TST_TAINT_W | TST_TAINT_D, .save_restore = (const struct tst_path_val[]) { {"/proc/sys/vm/swappiness", NULL, TST_SR_SKIP_MISSING | TST_SR_TCONF_RO}, diff --git a/testcases/kernel/syscalls/madvise/madvise11.c b/testcases/kernel/syscalls/madvise/madvise11.c new file mode 100644 index 000000000..7a12abf20 --- /dev/null +++ b/testcases/kernel/syscalls/madvise/madvise11.c @@ -0,0 +1,442 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 Oracle and/or its affiliates. + */ + +/*\ + * [Description] + * + * Stress a possible race condition between memory pages allocation + * and soft-offline of unrelated pages as explained in the commit: + * d4ae9916ea29 (mm: soft-offline: close the race against page allocation) + * + * Control that soft-offlined pages get correctly replaced: with the + * same content and without SIGBUS generation when accessed. + */ + +#include <errno.h> +#include <mntent.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/klog.h> + +#include "tst_test.h" +#include "tst_safe_pthread.h" +#include "tst_safe_stdio.h" +#include "lapi/mmap.h" + +#define NUM_LOOPS 5 +#define NUM_PAGES 32 +#define NUM_PAGES_OFFSET 5 + +/* Needed module to online back memory pages */ +#define HW_MODULE "hwpoison_inject" + +static pthread_t *thread_ids; +static int number_threads; +static int run_iterations; +static int maximum_pfns; + +static volatile int sigbus_received; +static pthread_cond_t sigbus_received_cv; +static pthread_mutex_t sigbus_received_mtx = PTHREAD_MUTEX_INITIALIZER; + +static long pagesize; +static char beginning_tag[BUFSIZ]; +static int hwpoison_probe; + +static void my_yield(void) +{ + static const struct timespec t0 = { 0, 0 }; + + nanosleep(&t0, NULL); +} + +/* a SIGBUS received is a confirmation of test failure */ +static void sigbus_handler(int signum LTP_ATTRIBUTE_UNUSED) +{ + pthread_mutex_lock(&sigbus_received_mtx); + sigbus_received++; + pthread_cond_signal(&sigbus_received_cv); + pthread_mutex_unlock(&sigbus_received_mtx); + pause(); +} + +static void *sigbus_monitor(void *arg LTP_ATTRIBUTE_UNUSED) +{ + pthread_mutex_lock(&sigbus_received_mtx); + while (!sigbus_received) + pthread_cond_wait(&sigbus_received_cv, &sigbus_received_mtx); + pthread_mutex_unlock(&sigbus_received_mtx); + tst_res(TFAIL, "SIGBUS Received"); + exit(1); +} + +/* + * Allocate a page and write a sentinel value into it. + */ +static void *allocate_write(int sentinel) +{ + void *p; + int *s; + + p = SAFE_MMAP(NULL, pagesize, PROT_READ|PROT_WRITE, + MAP_SHARED|MAP_ANONYMOUS, -1, 0); + s = (int *)p; + *s = sentinel; + return p; +} + +/* + * Verify and unmap the given page. + */ +static int verif_unmap(void *page, int sentinel) +{ + int *s = (int *)page; + + if (*s != sentinel) { + tst_res(TFAIL, "pid[%d]: fail: bad sentinel value seen: %d expected: %d\n", getpid(), *s, sentinel); + return 1; + } + + return SAFE_MUNMAP(page, pagesize); +} + +/* + * allocate_offline() - Allocate and offline test called per-thread + * + * This function does the allocation and offline by mmapping an + * anonymous page and offlining it. + */ +static int allocate_offline(int tnum) +{ + int loop; + + for (loop = 0; loop < NUM_LOOPS; loop++) { + long *ptrs[NUM_PAGES]; + int num_alloc; + int i; + + for (num_alloc = 0; num_alloc < NUM_PAGES; num_alloc++) { + + ptrs[num_alloc] = allocate_write((tnum << NUM_PAGES_OFFSET) | num_alloc); + if (ptrs[num_alloc] == NULL) + return -1; + + if (madvise(ptrs[num_alloc], pagesize, MADV_SOFT_OFFLINE) == -1) { + if (errno != EINVAL) + tst_res(TFAIL | TERRNO, "madvise failed"); + if (errno == EINVAL) + tst_res(TCONF, "madvise() didn't support MADV_SOFT_OFFLINE"); + return errno; + } + } + + for (i = 0; i < num_alloc; i++) { + if (verif_unmap(ptrs[i], (tnum << NUM_PAGES_OFFSET) | i) != 0) + return 1; + } + + my_yield(); + if (!tst_remaining_runtime()) { + tst_res(TINFO, "Thread [%d]: Test runtime is over, exiting", tnum); + break; + } + } + + return 0; +} + +static void *alloc_mem(void *threadnum) +{ + int err; + int tnum = (int)(uintptr_t)threadnum; + + /* waiting for other threads starting */ + TST_CHECKPOINT_WAIT(0); + + err = allocate_offline(tnum); + tst_res(TINFO, + "Thread [%d] returned %d, %s.", tnum, err, (err ? "failed" : "succeeded")); + return (void *)(uintptr_t) (err ? -1 : 0); +} + +static void stress_alloc_offl(void) +{ + int thread_index; + int thread_failure = 0; + pthread_t sigbus_monitor_t; + + run_iterations++; + + SAFE_PTHREAD_CREATE(&sigbus_monitor_t, NULL, sigbus_monitor, NULL); + pthread_detach(sigbus_monitor_t); + + for (thread_index = 0; thread_index < number_threads; thread_index++) { + SAFE_PTHREAD_CREATE(&thread_ids[thread_index], NULL, alloc_mem, + (void *)(uintptr_t)thread_index); + } + + TST_CHECKPOINT_WAKE2(0, number_threads); + + for (thread_index = 0; thread_index < number_threads; thread_index++) { + void *status; + + SAFE_PTHREAD_JOIN(thread_ids[thread_index], &status); + if ((intptr_t)status != 0) { + tst_res(TFAIL, "thread [%d] - exited with errors", + thread_index); + thread_failure++; + } + } + + if (thread_failure == 0) + tst_res(TPASS, "soft-offline / mmap race still clean"); +} + +/* + * ------------ + * Cleanup code: + * The idea is to retrieve all the pfn numbers that have been soft-offined + * (generating a "Soft offlining pfn 0x..." message in the kernel ring buffer) + * by the current test (since a "beginning_tag" message we write when starting). + * And to put these pages back online by writing the pfn number to the + * <debugfs>/hwpoison/unpoison-pfn special file. + * ------------ + */ +#define OFFLINE_PATTERN "Soft offlining pfn 0x" +#define OFFLINE_PATTERN_LEN sizeof(OFFLINE_PATTERN) + +/* return the pfn if the kmsg msg is a soft-offline indication*/ +static unsigned long parse_kmsg_soft_offlined_pfn(char *line, ssize_t len) +{ + char *pos; + unsigned long addr = 0UL; + + pos = strstr(line, OFFLINE_PATTERN); + if (pos == NULL) + return 0UL; + + pos += OFFLINE_PATTERN_LEN-1; + if (pos > (line + len)) + return 0UL; + + addr = strtoul(pos, NULL, 16); + if ((addr == ULONG_MAX) && (errno == ERANGE)) + return 0UL; + + return addr; +} + +/* return the pfns seen in kernel message log */ +static int populate_from_klog(char *begin_tag, unsigned long *pfns, int max) +{ + int found = 0, fd, beginning_tag_found = 0; + ssize_t sz; + unsigned long pfn; + char buf[BUFSIZ]; + + fd = SAFE_OPEN("/dev/kmsg", O_RDONLY|O_NONBLOCK); + + while (found < max) { + sz = read(fd, buf, sizeof(buf)); + /* kmsg returns EPIPE if record was modified while reading */ + if (sz < 0 && errno == EPIPE) + continue; + if (sz <= 0) + break; + if (!beginning_tag_found) { + if (strstr(buf, begin_tag)) + beginning_tag_found = 1; + continue; + } + pfn = parse_kmsg_soft_offlined_pfn(buf, sz); + if (pfn) + pfns[found++] = pfn; + } + SAFE_CLOSE(fd); + return found; +} + +/* + * Read the given file to search for the key. + * Return 1 if the key is found. + */ +static int find_in_file(char *path, char *key) +{ + char line[4096]; + int found = 0; + FILE *file = SAFE_FOPEN(path, "r"); + + while (fgets(line, sizeof(line), file)) { + if (strstr(line, key)) { + found = 1; + break; + } + } + SAFE_FCLOSE(file); + return found; +} + +static void unpoison_this_pfn(unsigned long pfn, int fd) +{ + char pfn_str[19]; + + snprintf(pfn_str, sizeof(pfn_str), "0x%lx", pfn); + SAFE_WRITE(0, fd, pfn_str, strlen(pfn_str)); +} + +/* Find and open the <debugfs>/hwpoison/unpoison-pfn special file */ +static int open_unpoison_pfn(void) +{ + char *added_file_path = "/hwpoison/unpoison-pfn"; + const char *const cmd_modprobe[] = {"modprobe", HW_MODULE, NULL}; + char debugfs_fp[4096]; + struct mntent *mnt; + FILE *mntf; + + if (!find_in_file("/proc/modules", HW_MODULE) && tst_check_builtin_driver(HW_MODULE)) + hwpoison_probe = 1; + + /* probe hwpoison only if it isn't already there */ + if (hwpoison_probe) + SAFE_CMD(cmd_modprobe, NULL, NULL); + + /* debugfs mount point */ + mntf = setmntent("/proc/mounts", "r"); + if (!mntf) { + tst_brk(TBROK | TERRNO, "Can't open /proc/mounts"); + return -1; + } + while ((mnt = getmntent(mntf)) != NULL) { + if (strcmp(mnt->mnt_type, "debugfs") == 0) { + strcpy(debugfs_fp, mnt->mnt_dir); + strcat(debugfs_fp, added_file_path); + break; + } + } + endmntent(mntf); + if (!mnt) + return -1; + + TEST(open(debugfs_fp, O_WRONLY)); + + if (TST_RET == -1 && TST_ERR == EPERM && tst_lockdown_enabled() > 0) { + tst_res(TINFO, + "Cannot restore soft-offlined memory due to lockdown"); + return TST_RET; + } + + if (TST_RET == -1) { + tst_brk(TBROK | TTERRNO, "open(%s) failed", debugfs_fp); + } else if (TST_RET < 0) { + tst_brk(TBROK | TTERRNO, "Invalid open() return value %ld", + TST_RET); + } + + return TST_RET; +} + +/* + * Get all the Offlined PFNs indicated in the dmesg output + * starting after the given beginning tag, and request a debugfs + * hwpoison/unpoison-pfn for each of them. + */ +static void unpoison_pfn(char *begin_tag) +{ + unsigned long *pfns; + const char *const cmd_rmmod[] = {"rmmod", HW_MODULE, NULL}; + int found_pfns, fd; + + pfns = SAFE_MALLOC(sizeof(pfns) * maximum_pfns * run_iterations); + + fd = open_unpoison_pfn(); + if (fd >= 0) { + found_pfns = populate_from_klog(begin_tag, pfns, maximum_pfns * run_iterations); + + tst_res(TINFO, "Restore %d Soft-offlined pages", found_pfns); + /* unpoison in reverse order */ + while (found_pfns-- > 0) + unpoison_this_pfn(pfns[found_pfns], fd); + + SAFE_CLOSE(fd); + } + /* remove hwpoison only if we probed it */ + if (hwpoison_probe) + SAFE_CMD(cmd_rmmod, NULL, NULL); +} + +/* + * Create and write a beginning tag to the kernel buffer to be used on cleanup + * when trying to restore the soft-offlined pages of our test run. + */ +static void write_beginning_tag_to_kmsg(void) +{ + int fd; + + fd = SAFE_OPEN("/dev/kmsg", O_WRONLY); + snprintf(beginning_tag, sizeof(beginning_tag), + "Soft-offlining pages test starting (pid: %ld)", + (long)getpid()); + SAFE_WRITE(1, fd, beginning_tag, strlen(beginning_tag)); + SAFE_CLOSE(fd); +} + +static void setup(void) +{ + struct sigaction my_sigaction; + + number_threads = (int)sysconf(_SC_NPROCESSORS_ONLN) * 2; + if (number_threads <= 1) + number_threads = 2; + else if (number_threads > 5) + number_threads = 5; + + maximum_pfns = number_threads * NUM_LOOPS * NUM_PAGES; + thread_ids = SAFE_MALLOC(sizeof(pthread_t) * number_threads); + pagesize = sysconf(_SC_PAGESIZE); + + /* SIGBUS is the main failure criteria */ + my_sigaction.sa_handler = sigbus_handler; + if (sigaction(SIGBUS, &my_sigaction, NULL) == -1) + tst_res(TFAIL | TERRNO, "Signal handler attach failed"); + + write_beginning_tag_to_kmsg(); + tst_res(TINFO, "Spawning %d threads, with a total of %d memory pages", + number_threads, maximum_pfns); +} + +static void cleanup(void) +{ + unpoison_pfn(beginning_tag); +} + +static struct tst_test test = { + .needs_root = 1, + .needs_drivers = (const char *const []) { + HW_MODULE, + NULL + }, + .needs_cmds = (const char *[]) { + "modprobe", + "rmmod", + NULL + }, + .needs_kconfigs = (const char *[]) { + "CONFIG_MEMORY_FAILURE=y", + NULL + }, + .max_runtime = 30, + .needs_checkpoints = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = stress_alloc_offl, + .tags = (const struct tst_tag[]) { + {"linux-git", "d4ae9916ea29"}, + {} + } +}; diff --git a/testcases/kernel/syscalls/memfd_create/memfd_create02.c b/testcases/kernel/syscalls/memfd_create/memfd_create02.c index f547e1424..b9ddc0825 100644 --- a/testcases/kernel/syscalls/memfd_create/memfd_create02.c +++ b/testcases/kernel/syscalls/memfd_create/memfd_create02.c @@ -13,10 +13,8 @@ #define _GNU_SOURCE #include <errno.h> - -#include <tst_test.h> - #include "memfd_create_common.h" +#include "tst_test.h" static char buf[2048]; static char term_buf[2048]; diff --git a/testcases/kernel/syscalls/memfd_create/memfd_create04.c b/testcases/kernel/syscalls/memfd_create/memfd_create04.c index 7b699b218..585f17e16 100644 --- a/testcases/kernel/syscalls/memfd_create/memfd_create04.c +++ b/testcases/kernel/syscalls/memfd_create/memfd_create04.c @@ -1,20 +1,23 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) Zilogic Systems Pvt. Ltd., 2018 - * Email: code@zilogic.com + * Copyright (c) Zilogic Systems Pvt. Ltd. <code@zilogic.com>, 2018 + * Copyright (c) Linux Test Project, 2019-2023 */ -/* - * Test: Validating memfd_create() with MFD_HUGETLB and MFD_HUGE_x flags. +/*\ + * [Description] + * + * Validating memfd_create() with MFD_HUGETLB and MFD_HUGE_x flags. * - * Test cases: Attempt to create files in the hugetlbfs filesystem using - * different huge page sizes. + * Attempt to create files in the hugetlbfs filesystem using different huge page + * sizes. * - * Test logic: memfd_create() should return non-negative value (fd) - * if the system supports that particular huge page size. - * On success, fd is returned. - * On failure, -1 is returned with ENODEV error. + * [Algorithm] + * + * memfd_create() should return non-negative value (fd) if the system supports + * that particular huge page size. + * On success, fd is returned. On failure, -1 is returned with ENODEV error. */ #define _GNU_SOURCE @@ -25,8 +28,6 @@ #include <errno.h> #include <stdio.h> -#define PATH_HUGEPAGES "/sys/kernel/mm/hugepages" - static struct test_flag { int flag; char *h_size; @@ -48,7 +49,7 @@ static void check_hugepage_support(struct test_flag *test_flags) char pattern[64]; sprintf(pattern, PATH_HUGEPAGES); - strcat(pattern, "/hugepages-"); + strcat(pattern, "hugepages-"); strcat(pattern, test_flags->h_size); if (access(pattern, F_OK)) diff --git a/testcases/kernel/syscalls/mknod/mknod01.c b/testcases/kernel/syscalls/mknod/mknod01.c index f79e5fa42..7a4d5b43f 100644 --- a/testcases/kernel/syscalls/mknod/mknod01.c +++ b/testcases/kernel/syscalls/mknod/mknod01.c @@ -1,123 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. - * AUTHOR : William Roske - * CO-PILOT : Dave Fenner - * - * 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. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * 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. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ + * AUTHOR: William Roske, CO-PILOT: Dave Fenner + * Copyright (c) 2023 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> + */ + +/*\ + * [Description] * + * Verify that mknod(2) successfully creates a filesystem node with + * various modes. */ -#include <unistd.h> -#include <errno.h> -#include <string.h> -#include <signal.h> -#include <sys/types.h> -#include <sys/stat.h> #include <sys/sysmacros.h> - -#include "test.h" -#include "safe_macros.h" - -static void setup(void); -static void cleanup(void); - -char *TCID = "mknod01"; +#include "tst_test.h" #define PATH "test_node" -int tcases[] = { /* modes to give nodes created (1 per text case) */ - S_IFREG | 0777, /* ordinary file with mode 0777 */ - S_IFIFO | 0777, /* fifo special with mode 0777 */ - S_IFCHR | 0777, /* character special with mode 0777 */ - S_IFBLK | 0777, /* block special with mode 0777 */ +static int tcases[] = { + S_IFREG | 0777, + S_IFIFO | 0777, + S_IFCHR | 0777, + S_IFBLK | 0777, - S_IFREG | 04700, /* ordinary file with mode 04700 (suid) */ - S_IFREG | 02700, /* ordinary file with mode 02700 (sgid) */ - S_IFREG | 06700, /* ordinary file with mode 06700 (sgid & suid) */ + S_IFREG | 04700, + S_IFREG | 02700, + S_IFREG | 06700, }; -int TST_TOTAL = ARRAY_SIZE(tcases); -int main(int ac, char **av) +static void run(unsigned int i) { - int lc, i; - dev_t dev; - - tst_parse_opts(ac, av, NULL, NULL); + dev_t dev = 0; - setup(); + if (S_ISCHR(tcases[i]) || S_ISBLK(tcases[i])) + dev = makedev(1, 3); - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - - for (i = 0; i < TST_TOTAL; i++) { - /* - * overlayfs doesn't support mknod char device with - * major 0 and minor 0, which is known as whiteout_dev - */ - if (S_ISCHR(tcases[i])) - dev = makedev(1, 3); - else - dev = 0; - TEST(mknod(PATH, tcases[i], dev)); - - if (TEST_RETURN == -1) { - tst_resm(TFAIL, - "mknod(%s, %#o, %lu) failed, errno=%d : %s", - PATH, tcases[i], dev, TEST_ERRNO, - strerror(TEST_ERRNO)); - } else { - tst_resm(TPASS, - "mknod(%s, %#o, %lu) returned %ld", - PATH, tcases[i], dev, TEST_RETURN); - } - - SAFE_UNLINK(cleanup, PATH); - } - - } - - cleanup(); - tst_exit(); + TST_EXP_PASS(mknod(PATH, tcases[i], dev), + "mknod(PATH, %o, %ld)", + tcases[i], dev); + SAFE_UNLINK(PATH); } -void setup(void) -{ - tst_require_root(); - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - tst_tmpdir(); -} - -void cleanup(void) -{ - tst_rmdir(); -} +static struct tst_test test = { + .test = run, + .tcnt = ARRAY_SIZE(tcases), + .needs_root = 1, + .needs_tmpdir = 1 +}; diff --git a/testcases/kernel/syscalls/mknod/mknod02.c b/testcases/kernel/syscalls/mknod/mknod02.c index 594473e24..b1885fed1 100644 --- a/testcases/kernel/syscalls/mknod/mknod02.c +++ b/testcases/kernel/syscalls/mknod/mknod02.c @@ -1,301 +1,57 @@ +// 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 + * 07/2001 Ported by Wayne Boyer + * Copyright (c) 2023 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> */ -/* - * Test Name: mknod02 - * - * Test Description: - * Verify that mknod(2) succeeds when used to create a filesystem - * node with set group-ID bit set on a directory without set group-ID bit set. - * The node created should have set group-ID bit set and its gid should be - * equal to that of its parent directory. - * - * Expected Result: - * mknod() should return value 0 on success and node created should have - * set group-ID bit set, its gid should be equal to that of its parent - * directory. - * - * Algorithm: - * Setup: - * Setup signal handling. - * Create temporary directory. - * Pause for SIGUSR1 if option specified. - * - * Test: - * Loop if the proper options are given. - * Execute system call - * Check return code, if system call failed (return=-1) - * Log the errno and Issue a FAIL message. - * Otherwise, - * Verify the Functionality of system call - * if successful, - * Issue Functionality-Pass message. - * Otherwise, - * Issue Functionality-Fail message. - * Cleanup: - * Print errno log and/or timing stats if options given - * Delete the temporary directory created. - * - * Usage: <for command-line> - * mknod02 [-c n] [-f] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -f : Turn off functionality Testing. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 07/2001 Ported by Wayne Boyer - * - * RESTRICTIONS: - * This test should be run by 'super-user' (root) only. +/*\ + * [Description] * + * Verify that if mknod(2) creates a filesystem node in a directory which + * does not have the set-group-ID bit set, new node will not inherit the + * group ownership from its parent directory and its group ID will be the + * effective group ID of the process. */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <errno.h> -#include <string.h> -#include <signal.h> #include <pwd.h> -#include <sys/types.h> -#include <sys/stat.h> - -#include "test.h" -#include "safe_macros.h" +#include "tst_test.h" -#define LTPUSER "nobody" -#define MODE_RWX S_IFIFO | S_IRWXU | S_IRWXG | S_IRWXO -#define MODE_SGID S_IFIFO | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO -#define DIR_TEMP "testdir_2" -#define TNODE "tnode_%d" +#define MODE_DIR 0777 +#define MODE1 0010777 +#define MODE_SGID 02000 -struct stat buf; /* struct. to hold stat(2) o/p contents */ -struct passwd *user1; /* struct. to hold getpwnam(3) o/p contents */ +#define TEMP_DIR "testdir" +#define TEMP_NODE "testnode" -char *TCID = "mknod02"; -int TST_TOTAL = 1; -char node_name[PATH_MAX]; /* buffer to hold node name created */ +static struct stat buf; +static struct passwd *user_nobody; +static gid_t gid_nobody; -gid_t group1_gid, group2_gid, mygid; /* user and process group id's */ -uid_t save_myuid, user1_uid; /* user and process user id's */ -pid_t mypid; /* process id */ - -void setup(); /* setup function for the test */ -void cleanup(); /* cleanup function for the test */ - -int main(int ac, char **av) +static void setup(void) { - int lc; - int fflag; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* - * Attempt to create a filesystem node with group-id bit set - * on a directory without group id bit set such that, - * the node created by mknod(2) should have group-id (sgid) - * bit set and node's gid should be equal to that of its - * parent directory. - */ - TEST(mknod(node_name, MODE_SGID, 0)); - - /* Check return code from mknod(2) */ - if (TEST_RETURN == -1) { - tst_resm(TFAIL, - "mknod(%s, %#o, 0) failed, errno=%d : %s", - node_name, MODE_SGID, TEST_ERRNO, - strerror(TEST_ERRNO)); - continue; - } - /* Set the functionality flag */ - fflag = 1; - - /* Check for node's creation */ - if (stat(node_name, &buf) < 0) { - tst_resm(TFAIL, "stat() of %s failed, errno:%d", - node_name, TEST_ERRNO); - - /* unset functionality flag */ - fflag = 0; - } - - /* Verify mode permissions of node */ - if (!(buf.st_mode & S_ISGID)) { - tst_resm(TFAIL, "%s: Incorrect modes, setgid " - "bit not set", node_name); - /* unset flag as functionality fails */ - fflag = 0; - } - - /* Verify group ID of node */ - if (buf.st_gid != mygid) { - tst_resm(TFAIL, "%s: Incorrect group", - node_name); - /* unset flag as functionality fails */ - fflag = 0; - } - if (fflag) { - tst_resm(TPASS, "Functionality of mknod(%s, " - "%#o, 0) successful", - node_name, MODE_SGID); - } - - /* Remove the node for the next go `round */ - if (unlink(node_name) == -1) { - tst_resm(TWARN, "unlink(%s) failed, errno:%d %s", - node_name, errno, strerror(errno)); - } - } + user_nobody = SAFE_GETPWNAM("nobody"); + gid_nobody = user_nobody->pw_gid; - /* Change the directory back to temporary directory */ - SAFE_CHDIR(cleanup, ".."); - - /* - * Invoke cleanup() to delete the test directories created - * in the setup() and exit main(). - */ - cleanup(); - - tst_exit(); + SAFE_MKDIR(TEMP_DIR, MODE_DIR); + SAFE_CHOWN(TEMP_DIR, -1, gid_nobody); } -/* - * setup(void) - performs all ONE TIME setup for this test. - * Exit the test program on receipt of unexpected signals. - * Create a temporary directory used to hold test directories created - * and change the directory to it. - * Verify that pid of process executing the test is root. - * Create a test directory on temporary directory and set the ownership - * of test directory to ltp user and process. - * Set the effective uid/gid of the process to that of ltp user. - */ -void setup(void) +static void run(void) { - tst_require_root(); - - /* Capture unexpected signals */ - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - /* Make a temp dir and cd to it */ - tst_tmpdir(); - - /* fix permissions on the tmpdir */ - if (chmod(".", 0711) != 0) { - tst_brkm(TBROK, cleanup, "chmod() failed"); - } - - /* Save the real user id of the current test process */ - save_myuid = getuid(); - - /* Save the process id of the current test process */ - mypid = getpid(); - - /* Get the node name to be created in the test */ - sprintf(node_name, TNODE, mypid); - - /* Get the uid/gid of ltpuser */ - if ((user1 = getpwnam(LTPUSER)) == NULL) { - tst_brkm(TBROK | TERRNO, cleanup, - "Couldn't determine if %s was in /etc/passwd", - LTPUSER); - } - user1_uid = user1->pw_uid; - group1_gid = user1->pw_gid; - - /* Get the effective group id of the test process */ - group2_gid = getegid(); + SAFE_CHDIR(TEMP_DIR); + TST_EXP_PASS(mknod(TEMP_NODE, MODE1, 0), "mknod(%s, %o, 0)", TEMP_NODE, MODE1); - /* - * Create a test directory under temporary directory with the - * specified mode permissions, with uid/gid set to that of guest - * user and the test process. - */ - SAFE_MKDIR(cleanup, DIR_TEMP, MODE_RWX); - SAFE_CHOWN(cleanup, DIR_TEMP, user1_uid, group2_gid); + SAFE_STAT(TEMP_NODE, &buf); + TST_EXP_EQ_LI(buf.st_gid, 0); - /* - * Verify that test directory created with expected permission modes - * and ownerships. - */ - SAFE_STAT(cleanup, DIR_TEMP, &buf); - - /* Verify modes of test directory */ - if (buf.st_mode & S_ISGID) { - tst_brkm(TBROK, cleanup, - "%s: Incorrect modes, setgid bit set", DIR_TEMP); - } - - /* Verify group ID of test directory */ - if (buf.st_gid != group2_gid) { - tst_brkm(TBROK, cleanup, "%s: Incorrect group", DIR_TEMP); - } - - /* - * Set the effective group id and user id of the test process - * to that of guest user. - */ - SAFE_SETGID(cleanup, group1_gid); - if (setreuid(-1, user1_uid) < 0) { - tst_brkm(TBROK, cleanup, - "Unable to set process uid to that of ltp user"); - } - - /* Save the real group ID of the current process */ - mygid = getgid(); - - /* Change directory to DIR_TEMP */ - SAFE_CHDIR(cleanup, DIR_TEMP); + SAFE_UNLINK(TEMP_NODE); + SAFE_CHDIR(".."); } -/* - * cleanup() - Performs all ONE TIME cleanup for this test at - * completion or premature exit. - * Print test timing stats and errno log if test executed with options. - * Restore the real/effective user id of the process changed during - * setup(). - * Remove temporary directory and sub-directories/files under it - * created during setup(). - * Exit the test program with normal exit code. - */ -void cleanup(void) -{ - - /* - * Restore the effective uid of the process changed in the - * setup(). - */ - if (setreuid(-1, save_myuid) < 0) { - tst_brkm(TBROK, NULL, - "resetting process real/effective uid failed"); - } - - tst_rmdir(); - -} +static struct tst_test test = { + .setup = setup, + .test_all = run, + .needs_root = 1, + .needs_tmpdir = 1 +}; diff --git a/testcases/kernel/syscalls/mlock/mlock01.c b/testcases/kernel/syscalls/mlock/mlock01.c index 2338d4d56..0b079f8be 100644 --- a/testcases/kernel/syscalls/mlock/mlock01.c +++ b/testcases/kernel/syscalls/mlock/mlock01.c @@ -1,145 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2002 - * - * 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 - */ - -/* - * NAME - * mlock01.c - * - * DESCRIPTION - * Test to see that mlock works - *$ - * ALGORITHM - * test 1: - * Call mlock with various valid addresses and lengths. No - * error should be returned - * - * USAGE: <for command-line> - * -c n Run n copies concurrently - * -e Turn on errno logging - * -f Turn off functional testing - * -h Show this help screen - * -i n Execute test n times - * -I x Execute test for x seconds - * -p Pause for SIGUSR1 before starting - * -P x Pause for x seconds between iterations - * -t Turn on syscall timing + * Copyright (c) International Business Machines Corp., 2002 * * HISTORY * 06/2002 Written by Paul Larson - * - * RESTRICTIONS - * None */ -#include <errno.h> -#include <unistd.h> -#include <sys/mman.h> -#include "test.h" -void setup(); -void setup1(int); -void cleanup(); +/*\ + * [Description] + * + * Test mlock with various valid addresses and lengths. + */ -char *TCID = "mlock01"; -int TST_TOTAL = 4; +#include <stdlib.h> +#include "tst_test.h" -void *addr1; +static void *addr; -struct test_case_t { - void **addr; +static struct tcase { + char *msg; int len; - void (*setupfunc) (); -} TC[] = { - /* mlock should return ENOMEM when some or all of the address - * range pointed to by addr and len are not valid mapped pages - * in the address space of the process - */ - { - &addr1, 1, setup1}, { - &addr1, 1024, setup1}, { - &addr1, 1024 * 1024, setup1}, { - &addr1, 1024 * 1024 * 10, setup1} +} tcases[] = { + {"mlock 1 byte", 1}, + {"mlock 1024 bytes", 1024}, + {"mlock 1024 * 1024 bytes", 1024 * 1024}, + {"mlock 1024 * 1024 * 10 bytes", 1024 * 1024 * 10} }; -#if !defined(UCLINUX) - -int main(int ac, char **av) -{ - int lc, i; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - /* - * FIXME (garrcoop): this should really test out whether or not the - * process's mappable address space is indeed accessible by the - * current user, instead of needing to be run by root all the time. - */ - tst_require_root(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - for (i = 0; i < TST_TOTAL; i++) { - - if (TC[i].setupfunc != NULL) - TC[i].setupfunc(TC[i].len); - - TEST(mlock(*(TC[i].addr), TC[i].len)); - - /* I'm confused -- given the description above this - * should fail as designed, but this application - * */ - if (TEST_RETURN == -1) - tst_resm(TFAIL | TTERRNO, "mlock failed"); - else - tst_resm(TPASS, "mlock passed"); - } - } - - cleanup(); - - tst_exit(); -} - -#else - -int main(void) +static void do_mlock(unsigned int i) { - tst_brkm(TCONF, NULL, "test is not available on uClinux"); -} - -#endif /* if !defined(UCLINUX) */ + struct tcase *tc = &tcases[i]; -void setup(void) -{ - TEST_PAUSE; + tst_res(TINFO, "%s", tc->msg); + addr = SAFE_MALLOC(tc->len); + TST_EXP_PASS(mlock(addr, tc->len), "mlock(%p, %d)", addr, tc->len); + free(addr); + addr = NULL; } -void setup1(int len) +static void cleanup(void) { - addr1 = malloc(len); - if (addr1 == NULL) - tst_brkm(TFAIL, cleanup, "malloc failed"); + if (addr) + free(addr); } -void cleanup(void) -{ -} +static struct tst_test test = { + .needs_root = 1, + .test = do_mlock, + .tcnt = ARRAY_SIZE(tcases), + .cleanup = cleanup, +}; diff --git a/testcases/kernel/syscalls/mlock/mlock02.c b/testcases/kernel/syscalls/mlock/mlock02.c index 50ee31d1c..921ddeeae 100644 --- a/testcases/kernel/syscalls/mlock/mlock02.c +++ b/testcases/kernel/syscalls/mlock/mlock02.c @@ -1,109 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) International Business Machines Corp., 2002 - * 06/2002 Written by Paul Larson + * Copyright (c) International Business Machines Corp., 2002 * - * 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 + * 06/2002 Written by Paul Larson */ -/* - * Test Description: - * Verify that, - * 1. mlock() fails with -1 return value and sets errno to ENOMEM, - * if some of the specified address range does not correspond to - * mapped pages in the address space of the process. - * 2. mlock() fails with -1 return value and sets errno to ENOMEM, - * if (Linux 2.6.9 and later) the caller had a non-zero RLIMIT_MEMLOCK - * soft resource limit, but tried to lock more memory than the limit - * permitted. This limit is not enforced if the process is privileged - * (CAP_IPC_LOCK). - * 3. mlock() fails with -1 return value and sets errno to EPERM, - * if (Linux 2.6.9 and later) the caller was not privileged (CAP_IPC_LOCK) - * and its RLIMIT_MEMLOCK soft resource limit was 0. +/*\ + * [Description] + * + * Test for ENOMEM, EPERM errors. + * + * 1) mlock(2) fails with ENOMEM if some of the specified address range + * does not correspond to mapped pages in the address space of + * the process. + * + * 2) mlock(2) fails with ENOMEM if the caller had a non-zero RLIMIT_MEMLOCK + * soft resource limit, but tried to lock more memory than the limit + * permitted. This limit is not enforced if the process is + * privileged (CAP_IPC_LOCK). + * + * 3) mlock(2) fails with EPERM if the caller was not privileged (CAP_IPC_LOCK) + * and its RLIMIT_MEMLOCK soft resource limit was 0. */ -#include <errno.h> #include <unistd.h> #include <sys/mman.h> +#include <sys/types.h> #include <pwd.h> - -#include "test.h" -#include "safe_macros.h" - -char *TCID = "mlock02"; - -#if !defined(UCLINUX) - -static void setup(void); -static void cleanup(void); -static void test_enomem1(void); -static void test_enomem2(void); -static void test_eperm(void); -static void mlock_verify(const void *, const size_t, const int); +#include "tst_test.h" static size_t len; static struct rlimit original; static struct passwd *ltpuser; -static void (*test_func[])(void) = { test_enomem1, test_enomem2, test_eperm }; - -int TST_TOTAL = ARRAY_SIZE(test_func); - -int main(int ac, char **av) -{ - int lc, i; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - for (i = 0; i < TST_TOTAL; i++) - (*test_func[i])(); - } - - cleanup(); - tst_exit(); -} - -static void setup(void) -{ - tst_require_root(); - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - ltpuser = SAFE_GETPWNAM(cleanup, "nobody"); - - len = getpagesize(); - - SAFE_GETRLIMIT(cleanup, RLIMIT_MEMLOCK, &original); -} - static void test_enomem1(void) { void *addr; - struct rlimit rl; - addr = SAFE_MMAP(cleanup, NULL, len, PROT_READ, + addr = SAFE_MMAP(NULL, len, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); - - SAFE_MUNMAP(cleanup, addr, len); - - mlock_verify(addr, len, ENOMEM); + SAFE_MUNMAP(addr, len); + TST_EXP_FAIL(mlock(addr, len), ENOMEM, "mlock(%p, %lu)", addr, len); } static void test_enomem2(void) @@ -113,20 +50,14 @@ static void test_enomem2(void) rl.rlim_max = len - 1; rl.rlim_cur = len - 1; - SAFE_SETRLIMIT(cleanup, RLIMIT_MEMLOCK, &rl); - - addr = SAFE_MMAP(cleanup, NULL, len, PROT_READ, + SAFE_SETRLIMIT(RLIMIT_MEMLOCK, &rl); + addr = SAFE_MMAP(NULL, len, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); - - SAFE_SETEUID(cleanup, ltpuser->pw_uid); - - mlock_verify(addr, len, ENOMEM); - - SAFE_SETEUID(cleanup, 0); - - SAFE_MUNMAP(cleanup, addr, len); - - SAFE_SETRLIMIT(cleanup, RLIMIT_MEMLOCK, &original); + SAFE_SETEUID(ltpuser->pw_uid); + TST_EXP_FAIL(mlock(addr, len), ENOMEM, "mlock(%p, %lu)", addr, len); + SAFE_SETEUID(0); + SAFE_MUNMAP(addr, len); + SAFE_SETRLIMIT(RLIMIT_MEMLOCK, &original); } static void test_eperm(void) @@ -136,51 +67,32 @@ static void test_eperm(void) rl.rlim_max = 0; rl.rlim_cur = 0; - SAFE_SETRLIMIT(cleanup, RLIMIT_MEMLOCK, &rl); - - addr = SAFE_MMAP(cleanup, NULL, len, PROT_READ, + SAFE_SETRLIMIT(RLIMIT_MEMLOCK, &rl); + addr = SAFE_MMAP(NULL, len, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); - - SAFE_SETEUID(cleanup, ltpuser->pw_uid); - - mlock_verify(addr, len, EPERM); - - SAFE_SETEUID(cleanup, 0); - - SAFE_MUNMAP(cleanup, addr, len); - - SAFE_SETRLIMIT(cleanup, RLIMIT_MEMLOCK, &original); + SAFE_SETEUID(ltpuser->pw_uid); + TST_EXP_FAIL(mlock(addr, len), EPERM, "mlock(%p, %lu)", addr, len); + SAFE_SETEUID(0); + SAFE_MUNMAP(addr, len); + SAFE_SETRLIMIT(RLIMIT_MEMLOCK, &original); } -static void mlock_verify(const void *addr, const size_t len, const int error) +static void run(void) { - TEST(mlock(addr, len)); - - if (TEST_RETURN != -1) { - tst_resm(TFAIL, "mlock succeeded unexpectedly"); - return; - } - - if (TEST_ERRNO != error) { - tst_resm(TFAIL | TTERRNO, - "mlock didn't fail as expected; expected - %d : %s", - error, strerror(error)); - } else { - tst_resm(TPASS | TTERRNO, "mlock failed as expected"); - } + test_enomem1(); + test_enomem2(); + test_eperm(); } -static void cleanup(void) -{ -} - -#else - -int TST_TOTAL = 1; - -int main(void) +static void setup(void) { - tst_brkm(TCONF, NULL, "test is not available on uClinux"); + ltpuser = SAFE_GETPWNAM("nobody"); + len = getpagesize(); + SAFE_GETRLIMIT(RLIMIT_MEMLOCK, &original); } -#endif /* if !defined(UCLINUX) */ +static struct tst_test test = { + .needs_root = 1, + .setup = setup, + .test_all = run, +}; diff --git a/testcases/kernel/syscalls/mlock/mlock03.c b/testcases/kernel/syscalls/mlock/mlock03.c index 8bc65701c..3700b64b0 100644 --- a/testcases/kernel/syscalls/mlock/mlock03.c +++ b/testcases/kernel/syscalls/mlock/mlock03.c @@ -1,5 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0 /* + * Copyright (C) 2010 Red Hat, Inc. + */ + +/*\ + * [Description] + * + * This case is a regression test on old RHEL5. + * * Stack size mapping is decreased through mlock/munlock call. + * See the following url: + * https://bugzilla.redhat.com/show_bug.cgi?id=643426 * * This is to test kernel if it has a problem with shortening [stack] * mapping through several loops of mlock/munlock of /proc/self/maps. @@ -11,109 +22,61 @@ * munlock 44KiB bfefa000-bff05000 rw-p 00000000 00:00 0 [stack] * * with more iterations - could drop to 0KiB. - * - * Copyright (C) 2010 Red Hat, Inc. - * 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. - * - * Further, this software is distributed without any warranty that it - * is free of the rightful claim of any third person regarding - * infringement or the like. Any license provided herein, whether - * implied or otherwise, applies only to this software file. Patent - * licenses, if any, provided herein do not apply to combinations of - * this program with other software, or any other product whatsoever. - * - * 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. */ + #include <sys/mman.h> #include <stdio.h> #include <string.h> -#include "test.h" +#include <pwd.h> +#include "tst_test.h" +#include "tst_safe_stdio.h" #define KB 1024 -char *TCID = "mlock03"; -int TST_TOTAL = 1; - -static void setup(void); -static void cleanup(void); - -int main(int argc, char *argv[]) +static void verify_mlock(void) { - int lc; long from, to; long first = -1, last = -1; char b[KB]; FILE *fp; - tst_parse_opts(argc, argv, NULL, NULL); - - setup(); + fp = SAFE_FOPEN("/proc/self/maps", "r"); + while (!feof(fp)) { + if (!fgets(b, KB - 1, fp)) + break; + b[strlen(b) - 1] = '\0'; + if (sscanf(b, "%lx-%lx", &from, &to) != 2) { + tst_brk(TBROK, "parse %s start and end address failed", + b); + continue; + } - for (lc = 0; TEST_LOOPING(lc); lc++) { - fp = fopen("/proc/self/maps", "r"); - if (fp == NULL) - tst_brkm(TBROK | TERRNO, cleanup, "fopen"); - while (!feof(fp)) { - if (!fgets(b, KB - 1, fp)) - break; - b[strlen(b) - 1] = '\0'; - sscanf(b, "%lx-%lx", &from, &to); + /* Record the initial stack size. */ + if (strstr(b, "[stack]") != NULL) + first = (to - from) / KB; - /* Record the initial stack size. */ - if (lc == 0 && strstr(b, "[stack]") != NULL) - first = (to - from) / KB; + tst_res(TINFO, "mlock [%lx,%lx]", from, to); + if (mlock((const void *)from, to - from) == -1) + tst_res(TINFO | TERRNO, "mlock failed"); - switch (lc & 1) { - case 0: - if (mlock((const void *)from, to - from) == -1) - tst_resm(TINFO | TERRNO, - "mlock failed"); - break; - case 1: - if (munlock((void *)from, to - from) == -1) - tst_resm(TINFO | TERRNO, - "munlock failed"); - break; - default: - break; - } - tst_resm(TINFO, "%s from %lx to %0lx", - (lc & 1) ? "munlock" : "mlock", from, to); + tst_res(TINFO, "munlock [%lx,%lx]", from, to); + if (munlock((void *)from, to - from) == -1) + tst_res(TINFO | TERRNO, "munlock failed"); - /* Record the final stack size. */ - if (strstr(b, "[stack]") != NULL) - last = (to - from) / KB; - } - fclose(fp); + /* Record the final stack size. */ + if (strstr(b, "[stack]") != NULL) + last = (to - from) / KB; } - tst_resm(TINFO, "starting stack size is %ld", first); - tst_resm(TINFO, "final stack size is %ld", last); + SAFE_FCLOSE(fp); + + tst_res(TINFO, "starting stack size is %ld", first); + tst_res(TINFO, "final stack size is %ld", last); if (last < first) - tst_resm(TFAIL, "stack size is decreased."); + tst_res(TFAIL, "stack size is decreased."); else - tst_resm(TPASS, "stack size is not decreased."); - - cleanup(); - tst_exit(); + tst_res(TPASS, "stack size is not decreased."); } -void setup(void) -{ - tst_require_root(); - - tst_sig(FORK, DEF_HANDLER, cleanup); - TEST_PAUSE; -} - -void cleanup(void) -{ -} +static struct tst_test test = { + .test_all = verify_mlock, +}; diff --git a/testcases/kernel/syscalls/mlock/mlock04.c b/testcases/kernel/syscalls/mlock/mlock04.c index 8ac884583..f25460ba1 100644 --- a/testcases/kernel/syscalls/mlock/mlock04.c +++ b/testcases/kernel/syscalls/mlock/mlock04.c @@ -1,102 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * This is a reproducer copied from one of LKML patch submission, + * Copyright (C) 2010 Red Hat, Inc. + */ + +/*\ + * [Description] + * + * This is a reproducer copied from one of LKML patch submission * which subject is * * [PATCH] mlock: revert the optimization for dirtying pages and triggering writeback. + * url see https://www.spinics.net/lists/kernel/msg1141090.html * * "In 5ecfda0, we do some optimization in mlock, but it causes * a very basic test case(attached below) of mlock to fail. So * this patch revert it with some tiny modification so that it * apply successfully with the lastest 38-rc2 kernel." * - * Copyright (C) 2010 Red Hat, Inc. - * 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. - * - * Further, this software is distributed without any warranty that it - * is free of the rightful claim of any third person regarding - * infringement or the like. Any license provided herein, whether - * implied or otherwise, applies only to this software file. Patent - * licenses, if any, provided herein do not apply to combinations of - * this program with other software, or any other product whatsoever. + * This bug was fixed by kernel + * commit fdf4c587a7 ("mlock: operate on any regions with protection != PROT_NONE") * - * 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. + * As this case does, mmaps a file with PROT_WRITE permissions but without + * PROT_READ, so attempt to not unnecessarity break COW during mlock ended up + * causing mlock to fail with a permission problem on unfixed kernel. */ -#include "test.h" -#include "safe_macros.h" -#include "config.h" - -char *TCID = "mlock04"; -int TST_TOTAL = 1; #include <sys/mman.h> #include <stdio.h> #include <sys/types.h> -#include <sys/stat.h> -#include <errno.h> -#include <fcntl.h> -#include <unistd.h> -#include <sys/types.h> - -int fd, file_len = 40960; -char *testfile = "test_mlock"; +#include "tst_test.h" +#include "tst_safe_macros.h" -static void setup(void); -static void cleanup(void); +static int fd = -1, file_len = 40960; +static char *testfile = "test_mlock"; -int main(void) +static void verify_mlock(void) { char *buf; - int lc; - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - buf = mmap(NULL, file_len, PROT_WRITE, MAP_SHARED, fd, 0); - - if (buf == MAP_FAILED) - tst_brkm(TBROK | TERRNO, cleanup, "mmap"); - if (mlock(buf, file_len) == -1) - tst_brkm(TBROK | TERRNO, cleanup, "mlock"); - - tst_resm(TINFO, "locked %d bytes from %p", file_len, buf); - - if (munlock(buf, file_len) == -1) - tst_brkm(TBROK | TERRNO, cleanup, "munlock"); - - SAFE_MUNMAP(cleanup, buf, file_len); - } - - tst_resm(TPASS, "test succeeded."); - - cleanup(); - - tst_exit(); + buf = SAFE_MMAP(NULL, file_len, PROT_WRITE, MAP_SHARED, fd, 0); + TST_EXP_PASS(mlock(buf, file_len), "mlock(%p, %d)", buf, file_len); + SAFE_MUNLOCK(buf, file_len); + SAFE_MUNMAP(buf, file_len); } static void setup(void) { - tst_tmpdir(); - - fd = SAFE_OPEN(cleanup, testfile, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); - - SAFE_FTRUNCATE(cleanup, fd, file_len); - - TEST_PAUSE; + fd = SAFE_OPEN(testfile, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + SAFE_FTRUNCATE(fd, file_len); } static void cleanup(void) { - close(fd); - - tst_rmdir(); + if (fd > -1) + SAFE_CLOSE(fd); } + +static struct tst_test test = { + .needs_tmpdir = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = verify_mlock, + .tags = (const struct tst_tag[]) { + {"linux-git", "fdf4c587a793"}, + {} + } +}; diff --git a/testcases/kernel/syscalls/mmap/.gitignore b/testcases/kernel/syscalls/mmap/.gitignore index 8811226be..4591fdbb9 100644 --- a/testcases/kernel/syscalls/mmap/.gitignore +++ b/testcases/kernel/syscalls/mmap/.gitignore @@ -5,7 +5,6 @@ /mmap04 /mmap05 /mmap06 -/mmap07 /mmap08 /mmap09 /mmap10 @@ -18,3 +17,4 @@ /mmap17 /mmap18 /mmap19 +/mmap20 diff --git a/testcases/kernel/syscalls/mmap/mmap02.c b/testcases/kernel/syscalls/mmap/mmap02.c index 566cc323a..7ffe61fa3 100644 --- a/testcases/kernel/syscalls/mmap/mmap02.c +++ b/testcases/kernel/syscalls/mmap/mmap02.c @@ -1,186 +1,64 @@ +// 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 + * 07/2001 Ported by Wayne Boyer + * Copyright (c) 2023 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> */ -/* - * Test Description: - * Call mmap() with prot parameter set to PROT_READ and with the file - * descriptor being open for read, to map a file creating mapped memory - * with read access. The minimum file permissions should be 0444. - * - * The call should succeed to create the mapped region with required - * attributes. +/*\ + * [Description] * - * Expected Result: - * mmap() should succeed returning the address of the mapped region, - * the mapped region should contain the contents of the mapped file. - * - * HISTORY - * 07/2001 Ported by Wayne Boyer + * Verify that, mmap() call with PROT_READ and a file descriptor which is + * open for read only, succeeds to map a file creating mapped memory with + * read access. */ -#include <stdio.h> -#include <stdlib.h> -#include <sys/types.h> -#include <errno.h> -#include <unistd.h> -#include <fcntl.h> -#include <string.h> -#include <signal.h> -#include <sys/stat.h> -#include <sys/mman.h> - -#include "test.h" -#define TEMPFILE "mmapfile" - -char *TCID = "mmap02"; -int TST_TOTAL = 1; +#include <stdlib.h> +#include "tst_test.h" +#define TEMPFILE "mmapfile" +static ssize_t page_sz; +static int fd; static char *addr; -static char *dummy; -static size_t page_sz; -static int fildes; - -static void setup(void); -static void cleanup(void); - -int main(int ac, char **av) -{ - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* - * Call mmap to map the temporary file 'TEMPFILE' - * with read access. - */ - errno = 0; - addr = mmap(0, page_sz, PROT_READ, - MAP_FILE | MAP_SHARED, fildes, 0); - - /* Check for the return value of mmap() */ - if (addr == MAP_FAILED) { - tst_resm(TFAIL | TERRNO, "mmap of %s failed", TEMPFILE); - continue; - } - - /* - * Read the file contents into the dummy - * string. - */ - if (read(fildes, dummy, page_sz) < 0) { - tst_brkm(TFAIL | TERRNO, cleanup, - "reading %s failed", TEMPFILE); - } - - /* - * Check whether mapped memory region has - * the file contents. - */ - if (memcmp(dummy, addr, page_sz)) { - tst_resm(TFAIL, "mapped memory area contains " - "invalid data"); - } else { - tst_resm(TPASS, - "Functionality of mmap() successful"); - } - - /* Clean up things in case we are looping */ - /* Unmap the mapped memory */ - if (munmap(addr, page_sz) != 0) { - tst_brkm(TFAIL | TERRNO, cleanup, "munmapping failed"); - } - } - - cleanup(); - tst_exit(); -} +static char *buf; static void setup(void) { - char *tst_buff; - - tst_sig(FORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - page_sz = getpagesize(); + buf = SAFE_MALLOC(page_sz); + memset(buf, 'A', page_sz); - /* Allocate space for the test buffer */ - if ((tst_buff = calloc(page_sz, sizeof(char))) == NULL) { - tst_brkm(TFAIL, NULL, "calloc failed (tst_buff)"); - } - - /* Fill the test buffer with the known data */ - memset(tst_buff, 'A', page_sz); + fd = SAFE_OPEN(TEMPFILE, O_RDWR | O_CREAT, 0666); + SAFE_WRITE(SAFE_WRITE_ALL, fd, buf, page_sz); - tst_tmpdir(); - - /* Creat a temporary file used for mapping */ - if ((fildes = open(TEMPFILE, O_RDWR | O_CREAT, 0666)) < 0) { - free(tst_buff); - tst_brkm(TFAIL | TERRNO, cleanup, "opening %s failed", - TEMPFILE); - } - - /* Write test buffer contents into temporary file */ - if (write(fildes, tst_buff, page_sz) < (int)page_sz) { - free(tst_buff); - tst_brkm(TFAIL | TERRNO, cleanup, - "writing to %s failed", TEMPFILE); - } - - /* Free the memory allocated for test buffer */ - free(tst_buff); - - /* Change Mode permissions on Temporary file */ - if (fchmod(fildes, 0444) < 0) { - tst_brkm(TFAIL | TERRNO, cleanup, "fchmod(%s, 0444) failed", - TEMPFILE); - } - - /* Close the temporary file */ - if (close(fildes) < 0) { - tst_brkm(TFAIL | TERRNO, cleanup, "closing %s failed", - TEMPFILE); - } + SAFE_FCHMOD(fd, 0444); + SAFE_CLOSE(fd); + fd = SAFE_OPEN(TEMPFILE, O_RDONLY); +} - /* Open the temporary file again, - Readonly mode */ - if ((fildes = open(TEMPFILE, O_RDONLY)) < 0) { - tst_brkm(TFAIL, cleanup, "reopening %s readonly failed", - TEMPFILE); - } +static void run(void) +{ + addr = SAFE_MMAP(NULL, page_sz, PROT_READ, MAP_FILE | MAP_SHARED, fd, 0); - /* Allocate and initialize dummy string of system page size bytes */ - if ((dummy = calloc(page_sz, sizeof(char))) == NULL) { - tst_brkm(TFAIL, cleanup, "calloc failed (dummy)"); - } + if (memcmp(buf, addr, page_sz) == 0) + tst_res(TPASS, "mmap() functionality successful"); + else + tst_res(TFAIL, "mapped memory area contains invalid data"); + SAFE_MUNMAP(addr, page_sz); } static void cleanup(void) { - close(fildes); - free(dummy); - tst_rmdir(); + if (fd > 0) + SAFE_CLOSE(fd); + + free(buf); } + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test_all = run, + .needs_tmpdir = 1 +}; diff --git a/testcases/kernel/syscalls/mmap/mmap05.c b/testcases/kernel/syscalls/mmap/mmap05.c index 82f122543..7abddaa9e 100644 --- a/testcases/kernel/syscalls/mmap/mmap05.c +++ b/testcases/kernel/syscalls/mmap/mmap05.c @@ -1,205 +1,83 @@ +// 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 + * 07/2001 Ported by Wayne Boyer + * Copyright (c) 2023 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> */ -/* - * Test Description: - * Call mmap() to map a file creating mapped memory with no access under - * the following conditions - - * - The prot parameter is set to PROT_NONE - * - The file descriptor is open for read(any mode other than write) - * - The minimum file permissions should be 0444. - * - * The call should succeed to map the file creating mapped memory with the - * required attributes. - * - * Expected Result: - * mmap() should succeed returning the address of the mapped region, - * and an attempt to access the contents of the mapped region should give - * rise to the signal SIGSEGV. +/*\ + * [Description] * - * HISTORY - * 07/2001 Ported by Wayne Boyer + * Verify that, mmap() call with 'PROT_NONE' and a file descriptor which is + * open for read and write, succeeds to map the file creating mapped memory, + * but any attempt to access the contents of the mapped region causes the + * SIGSEGV signal. */ -#include <stdio.h> + #include <stdlib.h> -#include <sys/types.h> -#include <errno.h> -#include <unistd.h> -#include <fcntl.h> -#include <string.h> -#include <signal.h> -#include <sys/stat.h> -#include <sys/mman.h> #include <setjmp.h> +#include "tst_test.h" -#include "test.h" - -#define TEMPFILE "mmapfile" - -char *TCID = "mmap05"; -int TST_TOTAL = 1; - +#define TEMPFILE "mmapfile" static size_t page_sz; static volatile char *addr; -static int fildes; -static volatile int pass = 0; +static int fd; +static volatile int sig_flag; static sigjmp_buf env; -static void setup(void); -static void cleanup(void); -static void sig_handler(int sig); - -int main(int ac, char **av) +static void sig_handler(int sig) { - int lc; - char file_content; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* - * Call mmap to map the temporary file 'TEMPFILE' - * with no access. - */ - errno = 0; - addr = mmap(0, page_sz, PROT_NONE, - MAP_FILE | MAP_SHARED, fildes, 0); - TEST_ERRNO = errno; - - /* Check for the return value of mmap() */ - if (addr == MAP_FAILED) { - tst_resm(TFAIL | TERRNO, "mmap() failed on %s", - TEMPFILE); - continue; - } - - /* - * Try to access the mapped region. This should - * generate a SIGSEGV which will be caught below. - * - * This is wrapped by the sigsetjmp() call that will - * take care of restoring the program's context in an - * elegant way in conjunction with the call to - * siglongjmp() in the signal handler. - */ - if (sigsetjmp(env, 1) == 0) { - file_content = addr[0]; - } - - if (pass) { - tst_resm(TPASS, "Got SIGSEGV as expected"); - } else { - tst_resm(TFAIL, "Mapped memory region with NO " - "access is accessible"); - } - - /* Unmap mapped memory and reset pass in case we are looping */ - if (munmap((void *)addr, page_sz) != 0) { - tst_brkm(TFAIL | TERRNO, cleanup, "munmap failed"); - } - pass = 0; - + if (sig == SIGSEGV) { + sig_flag = 1; + siglongjmp(env, 1); } - - cleanup(); - tst_exit(); } static void setup(void) { - char *tst_buff; - - tst_sig(NOFORK, sig_handler, cleanup); + char *buf; - TEST_PAUSE; + SAFE_SIGNAL(SIGSEGV, sig_handler); page_sz = getpagesize(); + buf = SAFE_MALLOC(page_sz); + memset(buf, 'A', page_sz); - /* Allocate space for the test buffer */ - if ((tst_buff = calloc(page_sz, sizeof(char))) == NULL) { - tst_brkm(TFAIL, NULL, "calloc failed (tst_buff)"); - } - - /* Fill the test buffer with the known data */ - memset(tst_buff, 'A', page_sz); - - tst_tmpdir(); - - /* Creat a temporary file used for mapping */ - if ((fildes = open(TEMPFILE, O_WRONLY | O_CREAT, 0666)) < 0) { - free(tst_buff); - tst_brkm(TFAIL | TERRNO, cleanup, "opening %s failed", - TEMPFILE); - } + fd = SAFE_OPEN(TEMPFILE, O_RDWR | O_CREAT, 0666); + SAFE_WRITE(SAFE_WRITE_ALL, fd, buf, page_sz); + free(buf); +} - /* Write test buffer contents into temporary file */ - if (write(fildes, tst_buff, page_sz) != (int)page_sz) { - free(tst_buff); - tst_brkm(TFAIL, cleanup, "writing to %s failed", TEMPFILE); +static void run(void) +{ + addr = mmap(NULL, page_sz, PROT_NONE, MAP_FILE | MAP_SHARED, fd, 0); + if (addr == MAP_FAILED) { + tst_res(TFAIL | TERRNO, "mmap() of %s failed", TEMPFILE); + return; } - /* Free the memory allocated for test buffer */ - free(tst_buff); + if (sigsetjmp(env, 1) == 0) + tst_res(TINFO, "Trying to access mapped region: %c", addr[0]); - /* Make sure proper permissions set on file */ - if (fchmod(fildes, 0444) < 0) { - tst_brkm(TFAIL | TERRNO, cleanup, "fchmod of %s failed", - TEMPFILE); - } + if (sig_flag) + tst_res(TPASS, "Received SIGSEGV signal as expected"); + else + tst_res(TFAIL, "SIGSEGV signal not received"); - /* Close the temporary file opened for write */ - if (close(fildes) < 0) { - tst_brkm(TFAIL | TERRNO, cleanup, "closing %s failed", - TEMPFILE); - } + SAFE_MUNMAP((char *)addr, page_sz); - /* Open the temporary file again for reading */ - if ((fildes = open(TEMPFILE, O_RDONLY)) < 0) { - tst_brkm(TFAIL | TERRNO, cleanup, "opening %s readonly failed", - TEMPFILE); - } -} - -/* - * sig_handler() - Signal Catching function. - * This function gets executed when the test process receives - * the signal SIGSEGV while trying to access the contents of memory which - * is not accessible. - */ -static void sig_handler(int sig) -{ - if (sig == SIGSEGV) { - /* set the global variable and jump back */ - pass = 1; - siglongjmp(env, 1); - } else { - tst_brkm(TBROK, cleanup, "received an unexpected signal: %d", - sig); - } + sig_flag = 0; } static void cleanup(void) { - close(fildes); - tst_rmdir(); + if (fd > 0) + SAFE_CLOSE(fd); } + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test_all = run, + .needs_tmpdir = 1 +}; diff --git a/testcases/kernel/syscalls/mmap/mmap06.c b/testcases/kernel/syscalls/mmap/mmap06.c index fb7c49257..615743fa7 100644 --- a/testcases/kernel/syscalls/mmap/mmap06.c +++ b/testcases/kernel/syscalls/mmap/mmap06.c @@ -1,143 +1,83 @@ +// 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 + * 07/2001 Ported by Wayne Boyer + * Copyright (c) 2023 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> */ -/* - * Test Description: - * Call mmap() to map a file creating a mapped region with read access - * under the following conditions - - * - The prot parameter is set to PROT_READ - * - The file descriptor is open for writing. +/*\ + * [Description] * - * The call should fail to map the file. + * Verify that, mmap() call fails with errno: * - * Expected Result: - * mmap() should fail returning -1 and errno should get set to EACCES. - * - * HISTORY - * 07/2001 Ported by Wayne Boyer + * - EACCES, when a file mapping is requested but the file descriptor is not open for reading. + * - EINVAL, when length argument is 0. + * - EINVAL, when flags contains none of MAP_PRIVATE, MAP_SHARED, or MAP_SHARED_VALIDATE. */ -#include <stdio.h> -#include <stdlib.h> -#include <sys/types.h> -#include <errno.h> -#include <unistd.h> -#include <fcntl.h> -#include <string.h> -#include <signal.h> -#include <sys/stat.h> -#include <sys/mman.h> - -#include "test.h" - -#define TEMPFILE "mmapfile" -char *TCID = "mmap06"; -int TST_TOTAL = 1; +#include <stdlib.h> +#include "tst_test.h" +#define MMAPSIZE 1024 +#define TEMPFILE "mmapfile" static size_t page_sz; -static char *addr; -static int fildes; - -static void setup(void); -static void cleanup(void); - -int main(int ac, char **av) -{ - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* - * Call mmap to map the temporary file 'TEMPFILE' - * with read access. - */ - errno = 0; - addr = mmap(0, page_sz, PROT_READ, - MAP_FILE | MAP_SHARED, fildes, 0); - TEST_ERRNO = errno; - - /* Check for the return value of mmap() */ - if (addr != MAP_FAILED) { - tst_resm(TFAIL | TERRNO, - "mmap() returned invalid value, expected: %p", - MAP_FAILED); - /* Unmap the mapped memory */ - if (munmap(addr, page_sz) != 0) { - tst_resm(TBROK, "munmap() failed"); - cleanup(); - } - continue; - } - if (TEST_ERRNO == EACCES) { - tst_resm(TPASS, "mmap failed with EACCES"); - } else { - tst_resm(TFAIL | TERRNO, - "mmap failed with unexpected errno"); - } - } - cleanup(); - tst_exit(); - -} +static int fd; + +static struct tcase { + size_t length; + int prot; + int flags; + int exp_errno; +} tcases[] = { + {MMAPSIZE, PROT_WRITE, MAP_FILE | MAP_PRIVATE, EACCES}, + {MMAPSIZE, PROT_WRITE, MAP_FILE | MAP_SHARED, EACCES}, + {MMAPSIZE, PROT_READ, MAP_FILE | MAP_PRIVATE, EACCES}, + {MMAPSIZE, PROT_READ, MAP_FILE | MAP_SHARED, EACCES}, + {MMAPSIZE, PROT_READ | PROT_WRITE, MAP_FILE | MAP_PRIVATE, EACCES}, + {MMAPSIZE, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, EACCES}, + {0, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, EINVAL}, + {MMAPSIZE, PROT_READ | PROT_WRITE, MAP_FILE, EINVAL} +}; static void setup(void) { - char *tst_buff; - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; + char *buf; page_sz = getpagesize(); + buf = SAFE_MALLOC(page_sz); + memset(buf, 'A', page_sz); - /* Allocate space for the test buffer */ - if ((tst_buff = calloc(page_sz, sizeof(char))) == NULL) { - tst_brkm(TFAIL, NULL, "calloc() failed (tst_buff)"); - } + fd = SAFE_OPEN(TEMPFILE, O_WRONLY | O_CREAT, 0666); + SAFE_WRITE(SAFE_WRITE_ALL, fd, buf, page_sz); + free(buf); +} - /* Fill the test buffer with the known data */ - memset(tst_buff, 'A', page_sz); +static void run(unsigned int i) +{ + struct tcase *tc = &tcases[i]; - tst_tmpdir(); + TESTPTR(mmap(NULL, tc->length, tc->prot, tc->flags, fd, 0)); - /* Creat a temporary file used for mapping */ - if ((fildes = open(TEMPFILE, O_WRONLY | O_CREAT, 0666)) < 0) { - free(tst_buff); - tst_brkm(TFAIL, cleanup, "opening %s failed", TEMPFILE); + if (TST_RET_PTR != MAP_FAILED) { + tst_res(TFAIL, "mmap() was successful unexpectedly"); + SAFE_MUNMAP(TST_RET_PTR, MMAPSIZE); + } else if (TST_ERR == tc->exp_errno) { + tst_res(TPASS | TERRNO, "mmap() failed with"); + } else { + tst_res(TFAIL | TERRNO, "mmap() failed unexpectedly"); } - - /* Write test buffer contents into temporary file */ - if (write(fildes, tst_buff, page_sz) < (ssize_t)page_sz) { - free(tst_buff); - tst_brkm(TFAIL, cleanup, "writing to %s failed", TEMPFILE); - } - - free(tst_buff); } static void cleanup(void) { - close(fildes); - tst_rmdir(); + if (fd > 0) + SAFE_CLOSE(fd); } + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test = run, + .tcnt = ARRAY_SIZE(tcases), + .needs_tmpdir = 1 +}; diff --git a/testcases/kernel/syscalls/mmap/mmap07.c b/testcases/kernel/syscalls/mmap/mmap07.c deleted file mode 100644 index 682e527aa..000000000 --- a/testcases/kernel/syscalls/mmap/mmap07.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * 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: - * Call mmap() to map a file creating a mapped region with read access - * under the following conditions - - * - The prot parameter is set to PROT_WRITE - * - The file descriptor is open for writing. - * - The flags parameter has MAP_PRIVATE set. - * - * The call should fail to map the file. - * - * Expected Result: - * mmap() should fail returning -1 and errno should get set to EACCES. - * - * HISTORY - * 07/2001 Ported by Wayne Boyer - */ -#include <stdio.h> -#include <stdlib.h> -#include <sys/types.h> -#include <errno.h> -#include <unistd.h> -#include <fcntl.h> -#include <string.h> -#include <signal.h> -#include <sys/stat.h> -#include <sys/mman.h> - -#include "test.h" - -#define TEMPFILE "mmapfile" - -char *TCID = "mmap07"; -int TST_TOTAL = 1; - -static size_t page_sz; -static char *addr; -static int fildes; - -static void setup(void); -static void cleanup(void); - -int main(int ac, char **av) -{ - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* - * Call mmap to map the temporary file 'TEMPFILE' - * with write access. - */ - errno = 0; - addr = mmap(0, page_sz, PROT_WRITE, - MAP_FILE | MAP_PRIVATE, fildes, 0); - TEST_ERRNO = errno; - - /* Check for the return value of mmap() */ - if (addr != MAP_FAILED) { - tst_resm(TFAIL | TERRNO, - "mmap() returned invalid value, expected: %p", - MAP_FAILED); - /* Unmap the mapped memory */ - if (munmap(addr, page_sz) != 0) { - tst_resm(TBROK, "munmap() failed"); - cleanup(); - } - continue; - } - if (TEST_ERRNO == EACCES) { - tst_resm(TPASS, "mmap failed with EACCES"); - } else { - tst_resm(TFAIL | TERRNO, - "mmap failed with unexpected errno"); - } - - } - cleanup(); - tst_exit(); - -} - -static void setup(void) -{ - char *tst_buff; - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - page_sz = getpagesize(); - - /* Allocate space for the test buffer */ - if ((tst_buff = calloc(page_sz, sizeof(char))) == NULL) { - tst_brkm(TFAIL, NULL, - "calloc() failed to allocate space for tst_buff"); - } - - /* Fill the test buffer with the known data */ - memset(tst_buff, 'A', page_sz); - - tst_tmpdir(); - - /* Creat a temporary file used for mapping */ - if ((fildes = open(TEMPFILE, O_WRONLY | O_CREAT, 0666)) < 0) { - free(tst_buff); - tst_brkm(TFAIL, cleanup, "open() on %s failed", TEMPFILE); - } - - /* Write test buffer contents into temporary file */ - if (write(fildes, tst_buff, page_sz) < (int)page_sz) { - free(tst_buff); - tst_brkm(TFAIL, cleanup, "writing to %s failed", TEMPFILE); - } - - free(tst_buff); -} - -static void cleanup(void) -{ - close(fildes); - tst_rmdir(); -} diff --git a/testcases/kernel/syscalls/mmap/mmap08.c b/testcases/kernel/syscalls/mmap/mmap08.c index f2daf45a3..5c9fd782c 100644 --- a/testcases/kernel/syscalls/mmap/mmap08.c +++ b/testcases/kernel/syscalls/mmap/mmap08.c @@ -1,142 +1,53 @@ +// 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 + * 07/2001 Ported by Wayne Boyer + * Copyright (c) 2023 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> */ -/* - * Test Description: - * Verify that mmap() fails to map a file creating a mapped region - * when the file specified by file descriptor is not valid. - * - * Expected Result: - * mmap() should fail returning -1 and errno should get set to EBADF. +/*\ + * [Description] * - * HISTORY - * 07/2001 Ported by Wayne Boyer + * verify that, mmap() calls fails with errno EBADF when a file mapping + * is requested but the fd is not a valid file descriptor. */ -#include <stdio.h> -#include <stdlib.h> -#include <sys/types.h> -#include <errno.h> -#include <unistd.h> -#include <fcntl.h> -#include <string.h> -#include <signal.h> -#include <sys/stat.h> -#include <sys/mman.h> - -#include "test.h" -#define TEMPFILE "mmapfile" - -char *TCID = "mmap08"; -int TST_TOTAL = 1; +#include <stdlib.h> +#include "tst_test.h" +#define TEMPFILE "mmapfile" static size_t page_sz; -static char *addr; -static int fildes; +static int fd; -static void setup(void); -static void cleanup(void); - -int main(int ac, char **av) +static void setup(void) { - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* - * Call mmap to map the temporary file 'TEMPFILE' - * which is already closed. so, fildes is not valid. - */ - errno = 0; - addr = mmap(0, page_sz, PROT_WRITE, - MAP_FILE | MAP_SHARED, fildes, 0); - TEST_ERRNO = errno; - - /* Check for the return value of mmap() */ - if (addr != MAP_FAILED) { - tst_resm(TFAIL, "mmap() didn't fail (%p != %p)", - addr, MAP_FAILED); - /* Unmap the mapped memory */ - if (munmap(addr, page_sz) != 0) { - tst_brkm(TBROK, cleanup, "munmap() failed"); - } - continue; - } - if (TEST_ERRNO == EBADF) { - tst_resm(TPASS, "mmap failed with EBADF"); - } else { - tst_resm(TFAIL | TERRNO, - "mmap failed with an invalid errno"); - } - } - - cleanup(); - tst_exit(); + fd = SAFE_OPEN(TEMPFILE, O_RDWR | O_CREAT, 0666); + SAFE_CLOSE(fd); } -static void setup(void) +static void run(void) { - char *tst_buff; - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - page_sz = getpagesize(); - - if ((tst_buff = calloc(page_sz, sizeof(char))) == NULL) { - tst_brkm(TFAIL, NULL, - "calloc() failed to allocate space for tst_buff"); - } - - /* Fill the test buffer with the known data */ - memset(tst_buff, 'A', page_sz); - - tst_tmpdir(); - - /* Creat a temporary file used for mapping */ - if ((fildes = open(TEMPFILE, O_WRONLY | O_CREAT, 0666)) < 0) { - free(tst_buff); - tst_brkm(TFAIL, cleanup, "opening %s failed", TEMPFILE); - } - - /* Write test buffer contents into temporary file */ - if (write(fildes, tst_buff, page_sz) != (int)page_sz) { - free(tst_buff); - tst_brkm(TFAIL, cleanup, "writing to %s failed", TEMPFILE); - } - - /* Free the memory allocated for test buffer */ - free(tst_buff); - - /* Close the temporary file opened for writing */ - if (close(fildes) < 0) { - tst_brkm(TFAIL, cleanup, "closing %s failed", TEMPFILE); + TESTPTR(mmap(NULL, page_sz, PROT_WRITE, MAP_FILE | MAP_SHARED, fd, 0)); + + if (TST_RET_PTR != MAP_FAILED) { + tst_res(TFAIL, "mmap() passed unexpectedly"); + SAFE_MUNMAP(TST_RET_PTR, page_sz); + } else if (TST_ERR == EBADF) { + tst_res(TPASS, "mmap() failed with EBADF"); + } else { + tst_res(TFAIL | TERRNO, "mmap() failed with an invalid errno"); } } static void cleanup(void) { - tst_rmdir(); + if (fd > 0) + SAFE_CLOSE(fd); } + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test_all = run, + .needs_tmpdir = 1 +}; diff --git a/testcases/kernel/syscalls/mmap/mmap17.c b/testcases/kernel/syscalls/mmap/mmap17.c index a8136a0b2..39703fbd3 100644 --- a/testcases/kernel/syscalls/mmap/mmap17.c +++ b/testcases/kernel/syscalls/mmap/mmap17.c @@ -17,7 +17,6 @@ #include <stdio.h> #include <fcntl.h> #include <sys/types.h> -#include <sys/mman.h> #include <sys/stat.h> #include <unistd.h> #include <errno.h> diff --git a/testcases/kernel/syscalls/mmap/mmap20.c b/testcases/kernel/syscalls/mmap/mmap20.c new file mode 100644 index 000000000..02d150e45 --- /dev/null +++ b/testcases/kernel/syscalls/mmap/mmap20.c @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 Paulson Raja L <paulson@zilogic.com> + */ + +/*\ + * [Description] + * + * Test mmap(2) with MAP_SHARED_VALIDATE flag. + * + * Test expected EOPNOTSUPP errno when testing mmap(2) with MAP_SHARED_VALIDATE + * flag and invalid flag. + */ + +#include <errno.h> +#include <stdio.h> +#include <sys/types.h> +#include "tst_test.h" +#include "lapi/mmap.h" + +#define TEST_FILE "file_to_mmap" +#define TEST_FILE_SIZE 1024 +#define INVALID_FLAG (1 << 10) + +static int fd = -1; +static void *addr; + +static void setup(void) +{ + fd = SAFE_OPEN(TEST_FILE, O_CREAT | O_RDWR, 0600); + + if (tst_fill_file(TEST_FILE, 'a', TEST_FILE_SIZE, 1)) + tst_brk(TBROK, "Could not fill the testfile"); +} + +static void cleanup(void) +{ + if (fd > -1) + SAFE_CLOSE(fd); + + if (addr && addr != MAP_FAILED) + SAFE_MUNMAP(addr, TEST_FILE_SIZE); +} + +static void test_mmap(void) +{ + addr = mmap(NULL, TEST_FILE_SIZE, PROT_READ | PROT_WRITE, + INVALID_FLAG | MAP_SHARED_VALIDATE, fd, 0); + + if (addr != MAP_FAILED) + tst_res(TFAIL | TERRNO, "mmap() is successful, but it should have failed"); + else if (errno == EOPNOTSUPP) + tst_res(TPASS, "mmap() failed with errno set to EOPNOTSUPP"); + else + tst_res(TFAIL | TERRNO, "mmap() failed with unexpected error"); +} + +static struct tst_test test = { + .min_kver = "4.15", + .setup = setup, + .cleanup = cleanup, + .test_all = test_mmap, + .needs_tmpdir = 1, +}; diff --git a/testcases/kernel/syscalls/mount/.gitignore b/testcases/kernel/syscalls/mount/.gitignore index f92600d36..80885dbf0 100644 --- a/testcases/kernel/syscalls/mount/.gitignore +++ b/testcases/kernel/syscalls/mount/.gitignore @@ -5,3 +5,4 @@ /mount04 /mount05 /mount06 +/mount07 diff --git a/testcases/kernel/syscalls/mount/mount03.c b/testcases/kernel/syscalls/mount/mount03.c index 60f9963da..98d5933b7 100644 --- a/testcases/kernel/syscalls/mount/mount03.c +++ b/testcases/kernel/syscalls/mount/mount03.c @@ -122,7 +122,7 @@ static void test_file_dir_noatime(int update_fatime, int update_datime) SAFE_CLOSEDIR(test_dir); dir_atime = dir_st.st_atime; - sleep(1); + usleep(1001000); SAFE_READ(0, otfd, readbuf, sizeof(readbuf)); SAFE_FSTAT(otfd, &st); diff --git a/testcases/kernel/syscalls/mount/mount07.c b/testcases/kernel/syscalls/mount/mount07.c new file mode 100644 index 000000000..eb3fb55a0 --- /dev/null +++ b/testcases/kernel/syscalls/mount/mount07.c @@ -0,0 +1,177 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 FUJITSU LIMITED. All rights reserved. + * Author: Yang Xu <xuyang2018.jy@cn.fujitsu.com> + */ + +/*\ + * [Description] + * + * It is a basic test for MS_NOSYMFOLLOW mount option and is copied + * from kernel selftests nosymfollow-test.c. + * + * It tests to make sure that symlink traversal fails with ELOOP when + * 'nosymfollow' is set, but symbolic links can still be created, and + * readlink(2) and realpath(3) still work properly. It also verifies + * that statfs(2) correctly returns ST_NOSYMFOLLOW. + */ + +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/mount.h> +#include <stdbool.h> +#include "tst_test.h" +#include "lapi/mount.h" + +#ifndef ST_NOSYMFOLLOW +# define ST_NOSYMFOLLOW 0x2000 +#endif + +#define MNTPOINT "mntpoint" + +static char test_file[PATH_MAX]; +static char link_file[PATH_MAX]; +static char temp_link_file[PATH_MAX]; +static int flag; + +static void setup_symlink(void) +{ + int fd; + + fd = SAFE_CREAT(test_file, O_RDWR); + SAFE_SYMLINK(test_file, link_file); + SAFE_CLOSE(fd); + flag = 1; +} + +static void test_link_traversal(bool nosymfollow) +{ + if (nosymfollow) { + TST_EXP_FAIL2(open(link_file, 0, O_RDWR), ELOOP, + "open(%s, 0, O_RDWR)", link_file); + } else { + TST_EXP_FD(open(link_file, 0, O_RDWR)); + } + + if (TST_RET > 0) + SAFE_CLOSE(TST_RET); +} + +static void test_readlink(void) +{ + char buf[4096]; + + memset(buf, 0, 4096); + TST_EXP_POSITIVE(readlink(link_file, buf, sizeof(buf)), + "readlink(%s, buf, %ld)", link_file, sizeof(buf)); + if (strcmp(buf, test_file) != 0) { + tst_res(TFAIL, "readlink strcmp failed, %s, %s", + buf, test_file); + } else { + tst_res(TPASS, "readlink strcmp succeeded"); + } +} + +static void test_realpath(void) +{ + TESTPTR(realpath(link_file, NULL)); + + if (!TST_RET_PTR) { + tst_res(TFAIL | TERRNO, "realpath failed"); + return; + } + + if (strcmp(TST_RET_PTR, test_file) != 0) { + tst_res(TFAIL, "realpath strcmp failed, %s, %s", + (char *)TST_RET_PTR, test_file); + } else { + tst_res(TPASS, "realpath strcmp succeeded"); + } +} + +static void test_cycle_link(void) +{ + TST_EXP_PASS(symlink(test_file, temp_link_file), "symlink(%s, %s)", + test_file, temp_link_file); + TST_EXP_PASS(unlink(temp_link_file)); +} + +static void test_statfs(bool nosymfollow) +{ + struct statfs buf; + + SAFE_STATFS(MNTPOINT, &buf); + if (buf.f_flags & ST_NOSYMFOLLOW) { + tst_res(nosymfollow ? TPASS : TFAIL, "ST_NOSYMFOLLOW set on %s", + MNTPOINT); + } else { + tst_res(nosymfollow ? TFAIL : TPASS, "ST_NOSYMFOLLOW not set on %s", + MNTPOINT); + } +} + +static void setup(void) +{ + char *tmpdir = tst_get_tmpdir(); + + snprintf(test_file, PATH_MAX, "%s/%s/test_file", tst_get_tmpdir(), + MNTPOINT); + snprintf(link_file, PATH_MAX, "%s/%s/link_file", tst_get_tmpdir(), + MNTPOINT); + snprintf(temp_link_file, PATH_MAX, "%s/%s/temp_link_file", + tst_get_tmpdir(), MNTPOINT); + free(tmpdir); +} + +static void cleanup(void) +{ + if (tst_is_mounted(MNTPOINT)) + SAFE_UMOUNT(MNTPOINT); +} + +static void run_tests(bool nosymfollow) +{ + test_link_traversal(nosymfollow); + test_readlink(); + test_realpath(); + test_cycle_link(); + test_statfs(nosymfollow); +} + +static void run(void) +{ + tst_res(TINFO, "Testing behaviour when not setting MS_NOSYMFOLLOW"); + + TST_EXP_PASS_SILENT(mount(tst_device->dev, MNTPOINT, tst_device->fs_type, + 0, NULL)); + if (!flag || !strcmp(tst_device->fs_type, "tmpfs")) + setup_symlink(); + run_tests(false); + + tst_res(TINFO, "Testing behaviour when setting MS_NOSYMFOLLOW"); + TST_EXP_PASS_SILENT(mount(tst_device->dev, MNTPOINT, tst_device->fs_type, + MS_REMOUNT | MS_NOSYMFOLLOW, NULL)); + run_tests(true); + + SAFE_UMOUNT(MNTPOINT); +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .forks_child = 1, + .needs_root = 1, + .min_kver = "5.10", + .format_device = 1, + .mntpoint = MNTPOINT, + .all_filesystems = 1, + .skip_filesystems = (const char *const []){ + "exfat", + "vfat", + "ntfs", + NULL + }, +}; diff --git a/testcases/kernel/syscalls/mount_setattr/mount_setattr01.c b/testcases/kernel/syscalls/mount_setattr/mount_setattr01.c index 83746b878..e500df28e 100644 --- a/testcases/kernel/syscalls/mount_setattr/mount_setattr01.c +++ b/testcases/kernel/syscalls/mount_setattr/mount_setattr01.c @@ -32,7 +32,6 @@ #include <sys/statvfs.h> #include "tst_test.h" #include "lapi/fsmount.h" -#include "lapi/stat.h" #define MNTPOINT "mntpoint" #define OT_MNTPOINT "ot_mntpoint" diff --git a/testcases/kernel/syscalls/mprotect/.gitignore b/testcases/kernel/syscalls/mprotect/.gitignore index 9571ffd43..929c3b3a2 100644 --- a/testcases/kernel/syscalls/mprotect/.gitignore +++ b/testcases/kernel/syscalls/mprotect/.gitignore @@ -2,3 +2,4 @@ /mprotect02 /mprotect03 /mprotect04 +/mprotect05 diff --git a/testcases/kernel/syscalls/mprotect/mprotect05.c b/testcases/kernel/syscalls/mprotect/mprotect05.c new file mode 100644 index 000000000..2b15f5beb --- /dev/null +++ b/testcases/kernel/syscalls/mprotect/mprotect05.c @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 Oracle and/or its affiliates. All Rights Reserved. + * Author: Liam R. Howlett <liam.howlett@oracle.com> + */ + +/*\ + * [Description] + * + * Testcase to check the mprotect(2) system call split and merge. + * + * https://bugzilla.kernel.org/show_bug.cgi?id=217061 + * + */ + +#include "tst_test.h" + +#define TEST_FILE "mprotect05-testfile" + +static int fd; +static char *addr = MAP_FAILED; +static unsigned long pagesize; +static unsigned long fullsize; + +static void setup(void) +{ + pagesize = getpagesize(); + fullsize = 5 * pagesize; +} + +static void run(void) +{ + fd = SAFE_OPEN(TEST_FILE, O_RDWR | O_CREAT, 0777); + addr = SAFE_MMAP(0, fullsize, PROT_READ, MAP_SHARED, fd, 0); + + if (mprotect(addr + pagesize, pagesize, PROT_EXEC)) + tst_res(TFAIL | TERRNO, "mprotect failed to exec"); + + if (mprotect(addr + 3 * pagesize, pagesize, PROT_WRITE)) + tst_res(TFAIL | TERRNO, "mprotect failed to write"); + + if (mprotect(addr + pagesize, pagesize * 4, PROT_READ)) + tst_res(TFAIL | TERRNO, "mprotect failed to read"); + + SAFE_MUNMAP(addr, fullsize); + SAFE_CLOSE(fd); + addr = MAP_FAILED; + SAFE_UNLINK(TEST_FILE); + tst_res(TPASS, "test passed"); +} + +static void cleanup(void) +{ + if (addr != MAP_FAILED) { + SAFE_MUNMAP(addr, fullsize); + SAFE_CLOSE(fd); + } +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .needs_tmpdir = 1, + .tags = (const struct tst_tag[]) { + {"linux-git", "2fcd07b7ccd5"}, + {} + }, +}; diff --git a/testcases/kernel/syscalls/mq_notify/.gitignore b/testcases/kernel/syscalls/mq_notify/.gitignore index cca05a7fa..3f9403c05 100644 --- a/testcases/kernel/syscalls/mq_notify/.gitignore +++ b/testcases/kernel/syscalls/mq_notify/.gitignore @@ -1,2 +1,3 @@ /mq_notify01 /mq_notify02 +/mq_notify03 diff --git a/testcases/kernel/syscalls/mq_notify/mq_notify02.c b/testcases/kernel/syscalls/mq_notify/mq_notify02.c index 3109fe345..d979a4e9d 100644 --- a/testcases/kernel/syscalls/mq_notify/mq_notify02.c +++ b/testcases/kernel/syscalls/mq_notify/mq_notify02.c @@ -1,91 +1,36 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * 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. + * Author: Zeng Linggang <zenglg.jy@cn.fujitsu.com> + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> */ -/* - * ALGORITHM - * test 1: - * sevp->sigev_notify = -1, EINVAL should be returned. - * test 2: - * sevp->sigev_notify = SIGEV_SIGNAL and sevp->sigev_signo > _NSG, - * EINVAL should be returned. + +/*\ + * [Description] + * + * This test verifies that mq_notify() fails with EINVAL when invalid input + * arguments are given. */ -#include <errno.h> #include <mqueue.h> -#include "test.h" - -char *TCID = "mq_notify02"; -static void setup(void); -static void cleanup(void); +#include "tst_test.h" static struct test_case_t { struct sigevent sevp; int exp_errno; -} test_cases[] = { +} tcase[] = { {{.sigev_notify = -1}, EINVAL}, - {{.sigev_notify = SIGEV_SIGNAL, .sigev_signo = _NSIG+1}, EINVAL}, + {{.sigev_notify = SIGEV_SIGNAL, .sigev_signo = _NSIG + 1}, EINVAL}, }; -int TST_TOTAL = ARRAY_SIZE(test_cases); -static void mq_notify_verify(struct test_case_t *); - -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++) - mq_notify_verify(&test_cases[i]); - } - cleanup(); - tst_exit(); -} - -static void setup(void) +static void run(unsigned int i) { - tst_sig(NOFORK, DEF_HANDLER, cleanup); + struct test_case_t *test = &tcase[i]; - TEST_PAUSE; + TST_EXP_FAIL(mq_notify(0, &(test->sevp)), test->exp_errno); } -static void mq_notify_verify(struct test_case_t *test) -{ - TEST(mq_notify(0, &(test->sevp))); - - if (TEST_RETURN != -1) { - tst_resm(TFAIL, "mq_notify() succeeded unexpectedly"); - return; - } - - if (TEST_ERRNO == test->exp_errno) { - tst_resm(TPASS | TTERRNO, "mq_notify failed as expected"); - } else if (TEST_ERRNO == ENOSYS) { - tst_resm(TCONF | TTERRNO, "mq_notify not available"); - } else { - tst_resm(TFAIL | TTERRNO, - "mq_notify failed unexpectedly; expected: %d - %s", - test->exp_errno, strerror(test->exp_errno)); - } -} - -static void cleanup(void) -{ -} +static struct tst_test test = { + .tcnt = ARRAY_SIZE(tcase), + .test = run, +}; diff --git a/testcases/kernel/syscalls/mq_notify/mq_notify03.c b/testcases/kernel/syscalls/mq_notify/mq_notify03.c new file mode 100644 index 000000000..bf6898cd8 --- /dev/null +++ b/testcases/kernel/syscalls/mq_notify/mq_notify03.c @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) The GNU Toolchain Authors. + * Copyright (c) 2023 Wei Gao <wegao@suse.com> + * + */ + +/*\ + * [Description] + * + * Test for NULL pointer dereference in mq_notify(CVE-2021-38604) + * + * References links: + * - https://sourceware.org/bugzilla/show_bug.cgi?id=28213 + */ + +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <mqueue.h> +#include <signal.h> +#include <stdlib.h> +#include <string.h> +#include "tst_test.h" +#include "tst_safe_posix_ipc.h" + +static mqd_t m = -1; +static const char msg[] = "hello"; + +static void try_null_dereference_cb(union sigval sv) +{ + char buf[sizeof(msg)]; + + (void)sv; + + TST_EXP_VAL((size_t) mq_receive(m, buf, sizeof(buf), NULL), + sizeof(buf)); + TST_EXP_PASS(memcmp(buf, msg, sizeof(buf))); + + exit(0); +} + +static void try_null_dereference(void) +{ + struct sigevent sev; + + memset(&sev, '\0', sizeof(sev)); + sev.sigev_notify = SIGEV_THREAD; + sev.sigev_notify_function = try_null_dereference_cb; + + /* Step 1: Register & unregister notifier. + * Helper thread should receive NOTIFY_REMOVED notification. + * In a vulnerable version of glibc, NULL pointer dereference follows. + */ + TST_EXP_PASS(mq_notify(m, &sev)); + TST_EXP_PASS(mq_notify(m, NULL)); + + /* Step 2: Once again, register notification. + * Try to send one message. + * Test is considered successful, if the callback does exit (0). + */ + TST_EXP_PASS(mq_notify(m, &sev)); + TST_EXP_PASS(mq_send(m, msg, sizeof(msg), 1)); + + /* Wait... */ + pause(); +} + +static void do_test(void) +{ + static const char m_name[] = "/ltp_mq_notify03"; + struct mq_attr m_attr; + + memset(&m_attr, '\0', sizeof(m_attr)); + m_attr.mq_maxmsg = 1; + m_attr.mq_msgsize = sizeof(msg); + + m = SAFE_MQ_OPEN(m_name, + O_RDWR | O_CREAT | O_EXCL, + 0600, + &m_attr); + + TST_EXP_PASS(mq_unlink(m_name)); + + try_null_dereference(); +} + + +static struct tst_test test = { + .test_all = do_test, + .tags = (const struct tst_tag[]) { + {"glibc-git", "b805aebd42"}, + {"CVE", "2021-38604"}, + {} + }, + .needs_root = 1, +}; diff --git a/testcases/kernel/syscalls/mremap/.gitignore b/testcases/kernel/syscalls/mremap/.gitignore index 833e1b883..ec15a19cd 100644 --- a/testcases/kernel/syscalls/mremap/.gitignore +++ b/testcases/kernel/syscalls/mremap/.gitignore @@ -3,3 +3,4 @@ /mremap03 /mremap04 /mremap05 +/mremap06 diff --git a/testcases/kernel/syscalls/mremap/mremap06.c b/testcases/kernel/syscalls/mremap/mremap06.c new file mode 100644 index 000000000..a19262750 --- /dev/null +++ b/testcases/kernel/syscalls/mremap/mremap06.c @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 SUSE LLC + * Author: Vlastimil Babka <vbabka@suse.cz> + * https://bugzilla.suse.com/attachment.cgi?id=867254 + * LTP port: Petr Vorel <pvorel@suse.cz> + */ + +/*\ + * [Description] + * + * Bug reproducer for 7e7757876f25 ("mm/mremap: fix vm_pgoff in vma_merge() case 3") + */ + +#define _GNU_SOURCE +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <fcntl.h> +#include <sys/mman.h> + +#include "tst_test.h" +#include "tst_safe_macros.h" + +#define NUM_PAGES 3 + +static int fd; +static char *buf, *buf2; +static int page_size, mmap_size, mremap_size; + +static struct tcase { + size_t incompatible; + const char *desc; +} tcases[] = { + { + .desc = "all pages with compatible mapping", + }, + { + .incompatible = 3, + .desc = "third page's mapping incompatible", + }, + { + .incompatible = 1, + .desc = "first page's mapping incompatible", + }, +}; + +static int check_pages(void) +{ + int fail = 0, i; + char val; + + for (i = 0; i < (int)ARRAY_SIZE(tcases); i++) { + val = buf[i * page_size]; + if (val != 0x30 + i) { + tst_res(TFAIL, "page %d wrong value %d (0x%x)", i, val - 0x30, val); + fail = 1; + } + } + + return fail; +} + +static void do_test(unsigned int n) +{ + struct tcase *tc = &tcases[n]; + int ret; + + tst_res(TINFO, "%s", tc->desc); + + buf = SAFE_MMAP(0, mmap_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + + buf2 = mremap(buf + page_size, page_size, page_size, + MREMAP_MAYMOVE|MREMAP_FIXED, buf + mremap_size); + if (buf2 == MAP_FAILED) + tst_brk(TBROK, "mremap() failed"); + + if (tc->incompatible) { + ret = mprotect(buf + (tc->incompatible-1)*page_size, page_size, PROT_READ); + if (ret == -1) + tst_brk(TBROK, "mprotect() failed"); + } + + buf2 = mremap(buf + mremap_size, page_size, page_size, + MREMAP_MAYMOVE|MREMAP_FIXED, buf + page_size); + if (buf2 == MAP_FAILED) + tst_brk(TBROK, "mremap() failed"); + + if (!check_pages()) + tst_res(TPASS, "mmap/mremap work properly"); + + SAFE_MUNMAP(buf, mremap_size); +} + +static void setup(void) +{ + int ret, i; + + page_size = getpagesize(); + mmap_size = (NUM_PAGES+1) * page_size; + mremap_size = NUM_PAGES * page_size; + + fd = SAFE_OPEN("testfile", O_CREAT | O_RDWR | O_TRUNC, 0600); + + ret = fallocate(fd, 0, 0, mmap_size); + if (ret == -1) + tst_brk(TBROK, "fallocate() failed"); + + buf = SAFE_MMAP(0, mmap_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + + for (i = 0; i < (int)ARRAY_SIZE(tcases)+1; i++) + buf[i*page_size] = 0x30 + i; + + /* clear the page tables */ + SAFE_MUNMAP(buf, mmap_size); +} + +static void cleanup(void) +{ + if (fd > 0) + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test = do_test, + .needs_tmpdir = 1, + .tcnt = ARRAY_SIZE(tcases), + .tags = (struct tst_tag[]) { + {"linux-git", "7e7757876f25"}, + {} + }, +}; diff --git a/testcases/kernel/syscalls/msync/msync01.c b/testcases/kernel/syscalls/msync/msync01.c index 3a5a48ee5..3c57ebb99 100644 --- a/testcases/kernel/syscalls/msync/msync01.c +++ b/testcases/kernel/syscalls/msync/msync01.c @@ -25,7 +25,7 @@ * of, or all of a mapped region. * * Expected Result: - * msync() should succeed with a return value of 0, and succesfully + * msync() should succeed with a return value of 0, and successfully * synchronize the memory region. Data read from mapped region should be * the same as the initialized data. * diff --git a/testcases/kernel/syscalls/munlock/munlock01.c b/testcases/kernel/syscalls/munlock/munlock01.c index 8a52f032d..31d749e66 100644 --- a/testcases/kernel/syscalls/munlock/munlock01.c +++ b/testcases/kernel/syscalls/munlock/munlock01.c @@ -1,162 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved. - * - * 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. - * + * AUTHOR: Nirmala Devi Dhanasekar <nirmala.devi@wipro.com> */ -/************************************************************************** - * - * TEST IDENTIFIER : munlock01 - * - * EXECUTED BY : root / superuser - * - * TEST TITLE : Basic test for munlock(2) - * - * TEST CASE TOTAL : 4 - * - * AUTHOR : Nirmala Devi Dhanasekar <nirmala.devi@wipro.com> - * - * SIGNALS - * Uses SIGUSR1 to pause before test if option set. - * (See the parse_opts(3) man page). - * - * DESCRIPTION - * This is a Phase I test for the munlock(2) system call. - * It is intended to provide a limited exposure of the system call. - * - * Setup: - * Setup signal handling. - * Pause for SIGUSR1 if option specified. - * - * Test: - * Loop if the proper options are given. - * Execute system call - * Check return code, if system call failed (return=-1) - * Log the errno and Issue a FAIL message. - * Otherwise, Issue a PASS message. - * - * Cleanup: - * Print errno log and/or timing stats if options given - * - * USAGE: <for command-line> - * munlock01 [-c n] [-e] [-i n] [-I x] [-p x] [-t] - * where, -c n : Run n copies concurrently - * -e : Turn on errno logging. - * -h : Show this help screen - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -p : Pause for SIGUSR1 before starting - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * RESTRICTIONS - * Must be root/superuser to run it. - *****************************************************************************/ - -#include <errno.h> -#include <unistd.h> -#include <sys/mman.h> -#include "test.h" -void setup(); -void setup1(int); -void cleanup(); +/*\ + * [Description] + * + * Test munlock with various valid addresses and lengths. + */ -char *TCID = "munlock01"; -int TST_TOTAL = 4; +#include <stdlib.h> +#include "tst_test.h" -void *addr1; +static void *addr; -struct test_case_t { - void **addr; +static struct tcase { + char *msg; int len; - void (*setupfunc) (); -} TC[] = { - { - &addr1, 1, setup1}, { - &addr1, 1024, setup1}, { - &addr1, 1024 * 1024, setup1}, { - &addr1, 1024 * 1024 * 10, setup1} +} tcases[] = { + {"munlock 1 byte", 1}, + {"munlock 1024 bytes", 1024}, + {"munlock 1024 * 1024 bytes", 1024 * 1024}, + {"munlock 1024 * 1024 * 10 bytes", 1024 * 1024 * 10} }; -int main(int ac, char **av) -{ - int lc, i; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - /* check looping state */ - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - for (i = 0; i < TST_TOTAL; i++) { - - if (TC[i].setupfunc != NULL) - TC[i].setupfunc(i); - - TEST(munlock(*(TC[i].addr), TC[i].len)); - - /* check return code */ - if (TEST_RETURN == -1) { - tst_resm(TFAIL | TTERRNO, - "mlock(%p, %d) Failed with " - "return=%ld", TC[i].addr, TC[i].len, - TEST_RETURN); - } else { - tst_resm(TPASS, "test %d passed length = %d", - i, TC[i].len); - } - } - } - - /* cleanup and exit */ - cleanup(); - - tst_exit(); -} - -void setup1(int i) +static void verify_munlock(unsigned int i) { - addr1 = malloc(TC[i].len); - if (addr1 == NULL) - tst_brkm(TFAIL, cleanup, "malloc failed"); - TEST(mlock(*(TC[i].addr), TC[i].len)); - - /* check return code */ - if (TEST_RETURN == -1) { - tst_brkm(TFAIL | TTERRNO, cleanup, - "mlock(%p, %d) Failed with return=%ld", TC[i].addr, - TC[i].len, TEST_RETURN); - } + struct tcase *tc = &tcases[i]; + + tst_res(TINFO, "%s", tc->msg); + addr = SAFE_MALLOC(tc->len); + SAFE_MLOCK(addr, tc->len); + TST_EXP_PASS(munlock(addr, tc->len), "munlock(%p, %d)", addr, tc->len); + free(addr); + addr = NULL; } -/* setup() - performs all ONE TIME setup for this test. */ -void setup(void) +static void cleanup(void) { - tst_require_root(); - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; + if (addr) + free(addr); } -/* - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - */ -void cleanup(void) -{ -} +static struct tst_test test = { + .needs_root = 1, + .test = verify_munlock, + .tcnt = ARRAY_SIZE(tcases), + .cleanup = cleanup, +}; diff --git a/testcases/kernel/syscalls/munlock/munlock02.c b/testcases/kernel/syscalls/munlock/munlock02.c index 75906a1df..f51c3d21f 100644 --- a/testcases/kernel/syscalls/munlock/munlock02.c +++ b/testcases/kernel/syscalls/munlock/munlock02.c @@ -1,198 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved. - * - * 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. - * + * AUTHOR: Nirmala Devi Dhanasekar <nirmala.devi@wipro.com> */ -/************************************************************************** - * - * TEST IDENTIFIER : munlock02 - * - * EXECUTED BY : root / superuser - * - * TEST TITLE : Test for checking basic error conditions for - * munlock(2) - * - * TEST CASE TOTAL : 2 - * - * AUTHOR : Nirmala Devi Dhanasekar <nirmala.devi@wipro.com> - * - * SIGNALS - * Uses SIGUSR1 to pause before test if option set. - * (See the parse_opts(3) man page). - * - * DESCRIPTION - * Check for basic errors returned by munlock(2) system call. - * - * Verify that munlock(2) returns -1 and sets errno to - * - * 1) ENOMEM - Some of the specified address range does not correspond to - * mapped pages in the address space of the process. - * - * Setup: - * Setup signal handling. - * Pause for SIGUSR1 if option specified. - * - * Test: - * Loop if the proper options are given. - * Do necessary setup for each test. - * Execute system call - * Check return code, if system call failed (return=-1) - * Log the errno and Issue a FAIL message. - * Otherwise, Issue a PASS message. - * - * Cleanup: - * Print errno log and/or timing stats if options given + +/*\ + * [Description] * - * USAGE: <for command-line> - * munlock02 [-c n] [-e] [-i n] [-I x] [-p x] [-t] - * where, -c n : Run n copies concurrently - * -e : Turn on errno logging. - * -h : Show this help screen - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -p : Pause for SIGUSR1 before starting - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. + * Test for ENOMEM error. * - * RESTRICTIONS - * Test must run as root. - *****************************************************************************/ -#include <errno.h> -#include <unistd.h> -#include <sys/mman.h> -#include <pwd.h> -#include "test.h" - -void setup(); -void cleanup(); - -char *TCID = "munlock02"; -int TST_TOTAL = 1; - -#define LEN 1024 - -void *addr1; + * munlock(2) fails with ENOMEM if some of the specified address range + * does not correspond to mapped pages in the address space of the + * process. + */ -struct test_case_t { - void *addr; - int len; - int error; - char *edesc; -} TC[] = { - { -NULL, 0, ENOMEM, "address range out of address space"},}; +#include <sys/mman.h> +#include "tst_test.h" -#if !defined(UCLINUX) +static size_t len, pg_size; +static void *addr; -int main(int ac, char **av) +static void run(void) { - int lc, i; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - /* check looping state */ - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - for (i = 0; i < TST_TOTAL; i++) { -#ifdef __ia64__ - TC[0].len = 8 * getpagesize(); -#endif - TEST(munlock(TC[i].addr, TC[i].len)); - - /* check return code */ - if (TEST_RETURN == -1) { - if (TEST_ERRNO != TC[i].error) - tst_brkm(TFAIL, cleanup, - "munlock() Failed with wrong " - "errno, expected errno=%s, " - "got errno=%d : %s", - TC[i].edesc, TEST_ERRNO, - strerror(TEST_ERRNO)); - else - tst_resm(TPASS, - "expected failure - errno " - "= %d : %s", - TEST_ERRNO, - strerror(TEST_ERRNO)); - } else { - tst_brkm(TFAIL, cleanup, - "munlock() Failed, expected " - "return value=-1, got %ld", - TEST_RETURN); - } - } - } - - /* cleanup and exit */ - cleanup(); - - tst_exit(); + TST_EXP_FAIL(munlock(addr, len), ENOMEM, "munlock(%p, %lu)", + addr, len); } -/* setup() - performs all ONE TIME setup for this test. */ - -void setup(void) +static void setup(void) { - - char *address; - - tst_sig(FORK, DEF_HANDLER, cleanup); - - TC[0].len = 8 * getpagesize(); - address = mmap(0, TC[0].len, PROT_READ | PROT_WRITE, - MAP_PRIVATE_EXCEPT_UCLINUX | MAP_ANONYMOUS, 0, 0); - if (address == MAP_FAILED) - tst_brkm(TFAIL, cleanup, "mmap_failed"); - memset(address, 0x20, TC[0].len); - TEST(mlock(address, TC[0].len)); - - /* check return code */ - if (TEST_RETURN == -1) { - tst_brkm(TFAIL | TTERRNO, cleanup, - "mlock(%p, %d) Failed with return=%ld", address, - TC[0].len, TEST_RETURN); - } - TC[0].addr = address; + pg_size = getpagesize(); + len = 8 * pg_size; + addr = SAFE_MMAP(NULL, len, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); + memset(addr, 0x20, len); + SAFE_MLOCK(addr, len); /* * unmap part of the area, to create the condition for ENOMEM */ - address += 2 * getpagesize(); - munmap(address, 4 * getpagesize()); - - TEST_PAUSE; - - return; -} - -#else - -int main(void) -{ - tst_resm(TINFO, "test is not available on uClinux"); - tst_exit(); + addr += 2 * pg_size; + SAFE_MUNMAP(addr, 4 * pg_size); } -#endif /* if !defined(UCLINUX) */ - -/* - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - */ -void cleanup(void) -{ - return; -} +static struct tst_test test = { + .needs_root = 1, + .setup = setup, + .test_all = run, +}; diff --git a/testcases/kernel/syscalls/munmap/munmap01.c b/testcases/kernel/syscalls/munmap/munmap01.c index 2a5cfc90d..7d10c0eac 100644 --- a/testcases/kernel/syscalls/munmap/munmap01.c +++ b/testcases/kernel/syscalls/munmap/munmap01.c @@ -193,7 +193,7 @@ void setup(void) /* * map the open file 'TEMPFILE' from its beginning up to the maplength * into the calling process's address space at the system choosen - * with read/write permissions to the the mapped region. + * with read/write permissions to the mapped region. */ #ifdef UCLINUX /* MAP_SHARED is not implemented on uClinux */ diff --git a/testcases/kernel/syscalls/munmap/munmap02.c b/testcases/kernel/syscalls/munmap/munmap02.c index b43250512..cd85d9436 100644 --- a/testcases/kernel/syscalls/munmap/munmap02.c +++ b/testcases/kernel/syscalls/munmap/munmap02.c @@ -197,7 +197,7 @@ void setup(void) /* * map the open file 'TEMPFILE' from its beginning up to the maplength * into the calling process's address space at the system choosen - * with read/write permissions to the the mapped region. + * with read/write permissions to the mapped region. */ #ifdef UCLINUX /* mmap() doesn't support MAP_SHARED on uClinux */ diff --git a/testcases/kernel/syscalls/name_to_handle_at/name_to_handle_at01.c b/testcases/kernel/syscalls/name_to_handle_at/name_to_handle_at01.c index 9677b0671..6535fdf5c 100644 --- a/testcases/kernel/syscalls/name_to_handle_at/name_to_handle_at01.c +++ b/testcases/kernel/syscalls/name_to_handle_at/name_to_handle_at01.c @@ -72,7 +72,7 @@ static void setup(void) dir_fd = SAFE_OPEN(TEST_DIR, O_DIRECTORY); SAFE_CHDIR(TEST_DIR); SAFE_TOUCH(TEST_FILE, 0600, NULL); - file_fd = SAFE_OPEN("foo_file", O_RDWR | O_CREAT); + file_fd = SAFE_OPEN("foo_file", O_RDWR | O_CREAT, 0600); fhp = allocate_file_handle(AT_FDCWD, TEST_FILE); } diff --git a/testcases/kernel/syscalls/open_by_handle_at/open_by_handle_at01.c b/testcases/kernel/syscalls/open_by_handle_at/open_by_handle_at01.c index 76be720ca..6171229f0 100644 --- a/testcases/kernel/syscalls/open_by_handle_at/open_by_handle_at01.c +++ b/testcases/kernel/syscalls/open_by_handle_at/open_by_handle_at01.c @@ -55,7 +55,7 @@ static void setup(void) dir_fd = SAFE_OPEN(TEST_DIR, O_DIRECTORY); SAFE_CHDIR(TEST_DIR); SAFE_TOUCH(TEST_FILE, 0600, NULL); - file_fd = SAFE_OPEN("foo_file", O_RDWR | O_CREAT); + file_fd = SAFE_OPEN("foo_file", O_RDWR | O_CREAT, 0600); f_fhp = allocate_file_handle(AT_FDCWD, TEST_FILE); d_fhp = allocate_file_handle(AT_FDCWD, TEST_FILE); diff --git a/testcases/kernel/syscalls/personality/personality01.c b/testcases/kernel/syscalls/personality/personality01.c index b646e2a9b..47fb66256 100644 --- a/testcases/kernel/syscalls/personality/personality01.c +++ b/testcases/kernel/syscalls/personality/personality01.c @@ -1,24 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* + * Copyright (c) 2016 Linux Test Project * Copyright (c) International Business Machines Corp., 2001 * 03/2001 - Written by Wayne Boyer * Copyright (c) 2016 Cyril Hrubis <chrubis@suse.cz> - * - * 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 + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> */ -/* +/*\ + * [Description] + * * Tries to set different personalities. * * We set the personality in a child process since it's not guaranteed that we @@ -26,19 +17,17 @@ * bit archs. */ -#include "test.h" -#include <sys/personality.h> - -char *TCID = "personality01"; +#include "tst_test.h" +#include "lapi/personality.h" #define PAIR(id) {id, #id} struct personalities { - unsigned long int pers; + unsigned long pers; const char *name; }; -struct personalities pers[] = { +static struct personalities pers[] = { PAIR(PER_LINUX), PAIR(PER_LINUX_32BIT), PAIR(PER_SVR4), @@ -62,60 +51,24 @@ struct personalities pers[] = { PAIR(PER_HPUX), }; -int TST_TOTAL = ARRAY_SIZE(pers); - -static void do_child(unsigned int i) +static void run(unsigned int i) { - int ret; + pid_t pid; - ret = personality(pers[i].pers); - if (ret < 0) { - tst_resm(TFAIL | TERRNO, "personality(%s) failed", pers[i].name); - return; - } + pid = SAFE_FORK(); + if (!pid) { + SAFE_PERSONALITY(pers[i].pers); - ret = personality(0xffffffff); + TST_EXP_EXPR((unsigned long)SAFE_PERSONALITY(0xffffffff) == pers[i].pers, + "%s personality is set", + pers[i].name); - if ((unsigned long)ret != pers[i].pers) { - tst_resm(TFAIL, - "%s: wrong personality read back %d expected %lu", - pers[i].name, ret, pers[i].pers); return; } - - tst_resm(TPASS, "personality(%s)", pers[i].name); -} - -static void verify_personality(unsigned int i) -{ - pid_t pid; - - pid = tst_fork(); - switch (pid) { - case 0: - do_child(i); - tst_exit(); - break; - case -1: - tst_brkm(TBROK | TERRNO, NULL, "fork() failed"); - break; - default: - tst_record_childstatus(NULL, pid); - break; - } } -int main(int ac, char **av) -{ - int i, lc; - - tst_parse_opts(ac, av, NULL, NULL); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - for (i = 0; i < TST_TOTAL; i++) { - verify_personality(i); - } - } - - tst_exit(); -} +static struct tst_test test = { + .test = run, + .tcnt = ARRAY_SIZE(pers), + .forks_child = 1, +}; diff --git a/testcases/kernel/syscalls/personality/personality02.c b/testcases/kernel/syscalls/personality/personality02.c index eb18c9951..e080284f4 100644 --- a/testcases/kernel/syscalls/personality/personality02.c +++ b/testcases/kernel/syscalls/personality/personality02.c @@ -1,62 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* + * Copyright (c) 2016 Linux Test Project * Copyright (c) 2016 Cyril Hrubis <chrubis@suse.cz> - * - * 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, see <http://www.gnu.org/licenses/>. + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> */ -/* - * If personality with STICKY_TIMEOUTS is used select() timeout is not updated. +/*\ + * [Description] + * + * This test checks if select() timeout is not updated when personality with + * STICKY_TIMEOUTS is used. */ -#include "test.h" -#include <sys/personality.h> +#include "tst_test.h" +#include "lapi/personality.h" #include <sys/select.h> -char *TCID = "personality02"; -int TST_TOTAL = 1; - #define USEC 10 -static void verify_personality(void) +static void run(void) { - struct timeval tv = {.tv_sec = 0, .tv_usec = USEC}; - int ret; + struct timeval tv = { .tv_sec = 0, .tv_usec = USEC }; fd_set rfds; FD_ZERO(&rfds); FD_SET(1, &rfds); - personality(PER_LINUX | STICKY_TIMEOUTS); - ret = select(2, &rfds, NULL, NULL, &tv); - personality(PER_LINUX); - if (ret < 0) - tst_resm(TBROK | TERRNO, "select()"); + SAFE_PERSONALITY(PER_LINUX | STICKY_TIMEOUTS); - if (tv.tv_usec != USEC) - tst_resm(TFAIL, "Timeout was modified"); - else - tst_resm(TPASS, "Timeout wasn't modified"); -} - -int main(int ac, char **av) -{ - int lc; + TEST(select(2, &rfds, NULL, NULL, &tv)); + if (TST_RET == -1) + tst_brk(TBROK | TERRNO, "select() error"); - tst_parse_opts(ac, av, NULL, NULL); + SAFE_PERSONALITY(PER_LINUX); - for (lc = 0; TEST_LOOPING(lc); lc++) - verify_personality(); - - tst_exit(); + TST_EXP_EQ_LI(tv.tv_usec, USEC); } + +static struct tst_test test = { + .test_all = run, +}; diff --git a/testcases/kernel/syscalls/pipe/.gitignore b/testcases/kernel/syscalls/pipe/.gitignore index 23e7186a6..774d73205 100644 --- a/testcases/kernel/syscalls/pipe/.gitignore +++ b/testcases/kernel/syscalls/pipe/.gitignore @@ -11,3 +11,4 @@ /pipe11 /pipe12 /pipe13 +/pipe14 diff --git a/testcases/kernel/syscalls/pipe/pipe03.c b/testcases/kernel/syscalls/pipe/pipe03.c index 89c0911c1..d20867b2b 100644 --- a/testcases/kernel/syscalls/pipe/pipe03.c +++ b/testcases/kernel/syscalls/pipe/pipe03.c @@ -1,51 +1,42 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) International Business Machines Corp., 2002 + * Copyright (c) 2003-2023 Linux Test Project */ -/* - * Make sure that writing to the read end of a pipe and reading from - * the write end of a pipe both fail. +/*\ + * [Description] + * + * Verify that, an attempt to write to the read end of a pipe fails with EBADF + * and an attempt to read from the write end of a pipe also fails with EBADF. */ -#include <unistd.h> -#include <errno.h> #include "tst_test.h" static int fd[2]; static void verify_pipe(void) { - char buf[2]; - - TEST(pipe(fd)); - if (TST_RET == -1) { - tst_res(TFAIL | TTERRNO, "pipe() failed unexpectedly"); - return; - } - - TEST(write(fd[0], "A", 1)); - if (TST_RET == -1 && errno == EBADF) { - tst_res(TPASS | TTERRNO, "expected failure writing " - "to read end of pipe"); - } else { - tst_res(TFAIL | TTERRNO, "unexpected failure writing " - "to read end of pipe"); - } - - TEST(read(fd[1], buf, 1)); - if (TST_RET == -1 && errno == EBADF) { - tst_res(TPASS | TTERRNO, "expected failure reading " - "from write end of pipe"); - } else { - tst_res(TFAIL | TTERRNO, "unexpected failure reading " - "from write end of pipe"); - } + char buf[] = "abcdef"; + + SAFE_PIPE(fd); + + TST_EXP_FAIL2(write(fd[0], "A", 1), EBADF); + TST_EXP_FAIL2(read(fd[1], buf, 1), EBADF); SAFE_CLOSE(fd[0]); SAFE_CLOSE(fd[1]); } +static void cleanup(void) +{ + if (fd[0] > 0) + SAFE_CLOSE(fd[0]); + if (fd[1] > 0) + SAFE_CLOSE(fd[1]); +} + static struct tst_test test = { .test_all = verify_pipe, + .cleanup = cleanup }; diff --git a/testcases/kernel/syscalls/pipe/pipe06.c b/testcases/kernel/syscalls/pipe/pipe06.c index d83765632..0c6bc03bd 100644 --- a/testcases/kernel/syscalls/pipe/pipe06.c +++ b/testcases/kernel/syscalls/pipe/pipe06.c @@ -1,119 +1,57 @@ +// 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 + * Copyright (c) International Business Machines Corp., 2001 + * 07/2001 Ported by Wayne Boyer + * Copyright (c) Linux Test Project, 2002-2015 + * Copyright (c) 2023 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> */ -/* - * NAME - * pipe06.c - * - * DESCRIPTION - * Check what happens when the system runs out of pipes. - * - * ALGORITHM - * Issue enough pipe calls to run the system out of pipes. - * Check that we get EMFILE. +/*\ + * [Description] * - * USAGE: <for command-line> - * pipe06 [-c n] [-e] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -e : Turn on errno logging. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 07/2001 Ported by Wayne Boyer - * - * RESTRICTIONS - * None + * Verify that, pipe(2) syscall fails with errno EMFILE when + * limit on the number of open file descriptors has been reached. */ -#include <fcntl.h> -#include <errno.h> -#include "test.h" -char *TCID = "pipe06"; -int TST_TOTAL = 1; +#include "tst_test.h" +#include <stdlib.h> -int pipe_ret, pipes[2]; -void setup(void); -void cleanup(void); +static int fds[2]; +static int *opened_fds, num_opened_fds; -int main(int ac, char **av) +static void setup(void) { - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - /* reset tst_count in case we are looping */ - tst_count = 0; + int max_fds; - TEST(pipe(pipes)); + max_fds = getdtablesize(); + tst_res(TINFO, "getdtablesize() = %d", max_fds); + opened_fds = SAFE_MALLOC(max_fds * sizeof(int)); - if (TEST_RETURN != -1) { - tst_resm(TFAIL, "call succeeded unexpectedly"); - } - - if (TEST_ERRNO != EMFILE) { - tst_resm(TFAIL | TTERRNO, "pipe failed unexpectedly"); - } else { - tst_resm(TPASS, "failed with EMFILE"); - } - - } - cleanup(); - tst_exit(); + do { + SAFE_PIPE(fds); + opened_fds[num_opened_fds++] = fds[0]; + opened_fds[num_opened_fds++] = fds[1]; + } while (fds[1] < max_fds - 2); + tst_res(TINFO, "Number of fds opened by pipe calls: %d", num_opened_fds); } -/* - * setup() - performs all ONE TIME setup for this test. - */ -void setup(void) +static void run(void) { - int i, numb_fds; - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - numb_fds = getdtablesize(); - - for (i = 0; i < numb_fds; i++) { - pipe_ret = pipe(pipes); - if (pipe_ret < 0) { - if (errno != EMFILE) { - tst_brkm(TBROK | TTERRNO, cleanup, - "didn't get EMFILE"); - } - break; - } - } + TST_EXP_FAIL(pipe(fds), EMFILE); } -/* - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - */ -void cleanup(void) +static void cleanup(void) { + for (int i = 0; i < num_opened_fds; i++) + SAFE_CLOSE(opened_fds[i]); + + if (opened_fds) + free(opened_fds); } + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test_all = run +}; diff --git a/testcases/kernel/syscalls/pipe/pipe07.c b/testcases/kernel/syscalls/pipe/pipe07.c index 55bb9f419..8098007c2 100644 --- a/testcases/kernel/syscalls/pipe/pipe07.c +++ b/testcases/kernel/syscalls/pipe/pipe07.c @@ -1,176 +1,103 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) International Business Machines Corp., 2002 - * Ported by Paul Larson + * Ported by Paul Larson * Copyright (c) 2013 Cyril Hrubis <chrubis@suse.cz> - * - * 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 + * Copyright (c) 2023 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> */ -/* - * Test the ability of pipe to open the maximum even number of file - * descriptors permitted (or (maxfds - 3)/2 pipes) +/*\ + * [Description] * - * ALGORITHM - * 1. record file descriptors open prior to test run - * 2. open pipes until EMFILE is returned - * 3. check to see that the number of pipes opened is (maxfds - 3) / 2 - * 4. close all fds in range 0, maximal fd that were not open prior to - * the test execution + * Verify that, pipe(2) syscall can open the maximum number of + * file descriptors permitted. */ -#include <unistd.h> -#include <fcntl.h> -#include <errno.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <dirent.h> -#include "test.h" -#include "safe_macros.h" - -char *TCID = "pipe07"; -int TST_TOTAL = 1; - -/* used to record file descriptors open at the test start */ -static int rec_fds[128]; -static int rec_fds_max; -static void record_open_fds(void); -static void close_test_fds(int max_fd); +#include "tst_test.h" +#include <stdlib.h> -static void setup(void); -static void cleanup(void); +static int *opened_fds, *pipe_fds; +static int num_pipe_fds, exp_num_pipes; -int main(int ac, char **av) +static int record_open_fds(void) { - int lc; - int min, ret; - int npipes; - int pipes[2], max_fd = 0; - - tst_parse_opts(ac, av, NULL, NULL); + DIR *dir; + struct dirent *ent; + int fd; + int num_opened_fds = 0; + int arr_size = 0; - setup(); + dir = SAFE_OPENDIR("/proc/self/fd"); - min = getdtablesize() - rec_fds_max; - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; + while ((ent = SAFE_READDIR(dir))) { + if (!strcmp(ent->d_name, ".") || + !strcmp(ent->d_name, "..")) + continue; + fd = atoi(ent->d_name); - for (npipes = 0;; npipes++) { - ret = pipe(pipes); - if (ret < 0) { - if (errno != EMFILE) { - tst_brkm(TFAIL, cleanup, - "got unexpected error - %d", - errno); - } - break; - } + if (fd == dirfd(dir)) + continue; - max_fd = MAX(pipes[0], max_fd); - max_fd = MAX(pipes[1], max_fd); + if (num_opened_fds >= arr_size) { + arr_size = MAX(1, arr_size * 2); + opened_fds = SAFE_REALLOC(opened_fds, arr_size * sizeof(int)); } - - if (npipes == (min / 2)) - tst_resm(TPASS, "Opened %d pipes", npipes); - else - tst_resm(TFAIL, "Unable to open maxfds/2 pipes"); - - close_test_fds(max_fd); - max_fd = 0; + opened_fds[num_opened_fds++] = fd; } - cleanup(); - tst_exit(); + SAFE_CLOSEDIR(dir); + + return num_opened_fds; } static void setup(void) { - tst_sig(FORK, DEF_HANDLER, cleanup); - TEST_PAUSE; + int max_fds; + + max_fds = getdtablesize(); + tst_res(TINFO, "getdtablesize() = %d", max_fds); + pipe_fds = SAFE_MALLOC(max_fds * sizeof(int)); - record_open_fds(); + exp_num_pipes = (max_fds - record_open_fds()) / 2 * 2; + tst_res(TINFO, "expected max fds to be opened by pipe(): %d", exp_num_pipes); } -static void record_open_fds(void) +static void run(void) { - DIR *dir = opendir("/proc/self/fd"); - int dir_fd, fd; - struct dirent *file; - - if (dir == NULL) - tst_brkm(TBROK | TERRNO, cleanup, "opendir()"); - - dir_fd = dirfd(dir); + int fds[2]; - if (dir_fd == -1) - tst_brkm(TBROK | TERRNO, cleanup, "dirfd()"); - - errno = 0; - - while ((file = readdir(dir))) { - if (!strcmp(file->d_name, ".") || !strcmp(file->d_name, "..")) - continue; - - fd = atoi(file->d_name); - - if (fd == dir_fd) - continue; - - if (rec_fds_max >= (int)ARRAY_SIZE(rec_fds)) { - tst_brkm(TBROK, cleanup, - "Too much file descriptors open"); + do { + TEST(pipe(fds)); + if (!TST_RET) { + pipe_fds[num_pipe_fds++] = fds[0]; + pipe_fds[num_pipe_fds++] = fds[1]; } + } while (!TST_RET); - rec_fds[rec_fds_max++] = fd; - } - - if (errno) - tst_brkm(TBROK | TERRNO, cleanup, "readdir()"); + TST_EXP_EQ_LI(errno, EMFILE); + TST_EXP_EQ_LI(exp_num_pipes, num_pipe_fds); - closedir(dir); + for (int i = 0; i < num_pipe_fds; i++) + SAFE_CLOSE(pipe_fds[i]); - tst_resm(TINFO, "Found %u files open", rec_fds_max); + num_pipe_fds = 0; } -static int not_recorded(int fd) +static void cleanup(void) { - int i; + for (int i = 0; i < num_pipe_fds; i++) + if (pipe_fds[i] > 0) + SAFE_CLOSE(pipe_fds[i]); - for (i = 0; i < rec_fds_max; i++) - if (fd == rec_fds[i]) - return 0; + if (pipe_fds) + free(pipe_fds); - return 1; + if (opened_fds) + free(opened_fds); } -static void close_test_fds(int max_fd) -{ - int i; - - for (i = 0; i <= max_fd; i++) { - if (not_recorded(i)) { - if (close(i)) { - if (errno == EBADF) - continue; - tst_resm(TWARN | TERRNO, "close(%i)", i); - } - } - } -} - -static void cleanup(void) -{ -} +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test_all = run +}; diff --git a/testcases/kernel/syscalls/pipe/pipe08.c b/testcases/kernel/syscalls/pipe/pipe08.c index 173ec788a..28088cf61 100644 --- a/testcases/kernel/syscalls/pipe/pipe08.c +++ b/testcases/kernel/syscalls/pipe/pipe08.c @@ -1,137 +1,59 @@ +// 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 + * Copyright (c) International Business Machines Corp., 2001 + * 07/2001 Ported by Wayne Boyer + * Copyright (c) 2023 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> */ -/* - * NAME - * pipe08.c - * - * DESCRIPTION - * Check that a SIGPIPE signal is generated when a write is - * attempted on an empty pipe. - * - * ALGORITHM - * 1. Write to a pipe after closing the read side. - * 2. Check for the signal SIGPIPE to be received. +/*\ + * [Description] * - * USAGE: <for command-line> - * pipe08 [-c n] [-f] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -f : Turn off functionality Testing. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * USAGE - * pipe08 - * - * HISTORY - * 07/2001 Ported by Wayne Boyer - * - * RESTRICTIONS - * None + * Verify that, on any attempt to write to a pipe which is closed for + * reading will generate a SIGPIPE signal and write will fail with + * EPIPE errno. */ -#include <errno.h> -#include <unistd.h> -#include <signal.h> -#include <string.h> -#include "test.h" -char *TCID = "pipe08"; -int TST_TOTAL = 1; +#include "tst_test.h" -void setup(void); -void cleanup(void); -void sighandler(int); +static int pipefd[2]; +static volatile int sigpipe_cnt; -int main(int ac, char **av) +static void sighandler(int sig) { - int lc; - - int pipefd[2]; /* fds for pipe read/write */ - char wrbuf[BUFSIZ]; - int written, length; - int close_stat; /* exit status of close(read fd) */ - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - /* reset tst_count in case we are looping */ - tst_count = 0; - - TEST(pipe(pipefd)); + if (sig == SIGPIPE) + sigpipe_cnt++; +} - if (TEST_RETURN != 0) { - tst_resm(TFAIL, "call failed unexpectedly"); - continue; - } +static void run(void) +{ + char wrbuf[] = "abcdefghijklmnopqrstuvwxyz"; - if ((close_stat = close(pipefd[0])) == -1) { - tst_brkm(TBROK, cleanup, "close of read side failed"); - } + sigpipe_cnt = 0; - strcpy(wrbuf, "abcdefghijklmnopqrstuvwxyz\0"); - length = strlen(wrbuf); + SAFE_PIPE(pipefd); + SAFE_CLOSE(pipefd[0]); - /* - * the SIGPIPE signal will be caught here or else - * the program will dump core when the signal is - * sent - */ - written = write(pipefd[1], wrbuf, length); - if (written > 0) - tst_brkm(TBROK, cleanup, "write succeeded unexpectedly"); - } - cleanup(); - tst_exit(); + TST_EXP_FAIL2_SILENT(write(pipefd[1], wrbuf, sizeof(wrbuf)), EPIPE); + TST_EXP_EQ_LI(sigpipe_cnt, 1); + SAFE_CLOSE(pipefd[1]); } -/* - * sighandler - catch signals and look for SIGPIPE - */ -void sighandler(int sig) +static void setup(void) { - if (sig != SIGPIPE) - tst_resm(TFAIL, "expected SIGPIPE, got %d", sig); - else - tst_resm(TPASS, "got expected SIGPIPE signal"); + SAFE_SIGNAL(SIGPIPE, sighandler); } -/* - * setup() - performs all ONE TIME setup for this test. - */ -void setup(void) +static void cleanup(void) { - - tst_sig(NOFORK, sighandler, cleanup); - - TEST_PAUSE; + if (pipefd[0] > 0) + SAFE_CLOSE(pipefd[0]); + if (pipefd[1] > 0) + SAFE_CLOSE(pipefd[1]); } -/* - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - */ -void cleanup(void) -{ -} +static struct tst_test test = { + .setup = setup, + .test_all = run, + .cleanup = cleanup +}; diff --git a/testcases/kernel/syscalls/pipe/pipe10.c b/testcases/kernel/syscalls/pipe/pipe10.c index 48f722e3e..018e653da 100644 --- a/testcases/kernel/syscalls/pipe/pipe10.c +++ b/testcases/kernel/syscalls/pipe/pipe10.c @@ -1,164 +1,52 @@ +// 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 + * Copyright (c) International Business Machines Corp., 2001 + * 07/2001 Ported by Wayne Boyer + * Copyright (c) 2023 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> */ -/* - * NAME - * pipe10.c - * - * DESCRIPTION - * Check that parent can open a pipe and have a child read from it - * - * ALGORITHM - * Parent opens pipe, child reads. Passes if child can read all the - * characters written by the parent. - * - * USAGE: <for command-line> - * pipe10 [-c n] [-f] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -f : Turn off functionality Testing. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 07/2001 Ported by Wayne Boyer +/*\ + * [Description] * - * RESTRICTIONS - * None + * Verify that, when a parent process opens a pipe, a child process can + * read from it. */ -#include <errno.h> -#include <unistd.h> -#include <sys/wait.h> -#include <string.h> -#include "test.h" -char *TCID = "pipe10"; -int TST_TOTAL = 1; +#include <stdio.h> +#include "tst_test.h" -void setup(void); -void cleanup(void); +static int fds[2]; -ssize_t do_read(int fd, void *buf, size_t count) +static void run(void) { - ssize_t n; - - do { - n = read(fd, buf, count); - } while (n < 0 && errno == EINTR); - - return n; -} - -int main(int ac, char **av) -{ - int lc; - - int fd[2]; /* fds for pipe read/write */ - char wrbuf[BUFSIZ], rebuf[BUFSIZ]; - int red, written; /* no of chars read and */ - /* written to pipe */ - int length, greater, forkstat; - int retval = 0, status, e_code; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { + int wr_cnt, rd_cnt; + char wrbuf[] = "abcdefghijklmnopqrstuvwxyz"; + char rdbuf[BUFSIZ]; - /* reset tst_count in case we are looping */ - tst_count = 0; + SAFE_PIPE(fds); + wr_cnt = SAFE_WRITE(SAFE_WRITE_ALL, fds[1], wrbuf, sizeof(wrbuf)); - TEST(pipe(fd)); - - if (TEST_RETURN == -1) { - retval = 1; - tst_resm(TFAIL, "pipe creation failed"); - continue; - } - - strcpy(wrbuf, "abcdefghijklmnopqrstuvwxyz"); - length = strlen(wrbuf) + 1; - - written = write(fd[1], wrbuf, length); - - /* did write write at least some chars */ - if ((written < 0) || (written > length)) { - tst_brkm(TBROK, cleanup, "write to pipe failed"); - } - - forkstat = FORK_OR_VFORK(); - - if (forkstat == -1) { - tst_brkm(TBROK, cleanup, "fork() failed"); - } - - if (forkstat == 0) { /* child */ - red = do_read(fd[0], rebuf, written); - - /* did read , get at least some chars */ - if ((red < 0) || (red > written)) { - tst_brkm(TBROK, cleanup, "read pipe failed"); - } - - greater = strcmp(rebuf, wrbuf); - - /* are the strings written and read equal */ - if (greater == 0) { - tst_resm(TPASS, "functionality is correct"); - } else { - retval = 1; - tst_resm(TFAIL, "read & write strings do " - "not match"); - } - exit(retval); - } else { /* parent */ - /* wait for the child to finish */ - wait(&status); - /* make sure the child returned a good exit status */ - e_code = status >> 8; - if (e_code != 0) { - tst_resm(TFAIL, "Failures reported above"); - } - } + if (!SAFE_FORK()) { + rd_cnt = SAFE_READ(1, fds[0], rdbuf, wr_cnt); + TST_EXP_EQ_LU(wr_cnt, rd_cnt); } - cleanup(); - tst_exit(); + tst_reap_children(); + SAFE_CLOSE(fds[0]); + SAFE_CLOSE(fds[1]); } -/* - * setup() - performs all ONE TIME setup for this test. - */ -void setup(void) +static void cleanup(void) { + if (fds[0] > 0) + SAFE_CLOSE(fds[0]); - tst_sig(FORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; + if (fds[1] > 0) + SAFE_CLOSE(fds[1]); } -/* - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - */ -void cleanup(void) -{ -} +static struct tst_test test = { + .test_all = run, + .forks_child = 1, + .cleanup = cleanup +}; diff --git a/testcases/kernel/syscalls/pipe/pipe14.c b/testcases/kernel/syscalls/pipe/pipe14.c new file mode 100644 index 000000000..2d2969d82 --- /dev/null +++ b/testcases/kernel/syscalls/pipe/pipe14.c @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> + */ + +/*\ + * [Description] + * + * Verify that, if the write end of a pipe is closed, then a process reading + * from the pipe will see end-of-file (i.e., read() returns 0) once it has + * read all remaining data in the pipe. + */ + +#include "tst_test.h" + +static int fds[2]; + +static void run(void) +{ + char wrbuf[] = "abcdefghijklmnopqrstuvwxyz"; + char rdbuf[30]; + + memset(rdbuf, 0, sizeof(rdbuf)); + SAFE_PIPE(fds); + + SAFE_WRITE(SAFE_WRITE_ALL, fds[1], wrbuf, sizeof(wrbuf)); + SAFE_CLOSE(fds[1]); + + SAFE_READ(0, fds[0], rdbuf, sizeof(wrbuf)); + + TST_EXP_VAL(SAFE_READ(0, fds[0], rdbuf, 1), 0); + SAFE_CLOSE(fds[0]); +} + +static void cleanup(void) +{ + if (fds[0] > 0) + SAFE_CLOSE(fds[0]); + if (fds[1] > 0) + SAFE_CLOSE(fds[1]); +} + +static struct tst_test test = { + .test_all = run, + .cleanup = cleanup +}; diff --git a/testcases/kernel/syscalls/prctl/prctl04.c b/testcases/kernel/syscalls/prctl/prctl04.c index f6e1f0fea..8b135d611 100644 --- a/testcases/kernel/syscalls/prctl/prctl04.c +++ b/testcases/kernel/syscalls/prctl/prctl04.c @@ -45,6 +45,7 @@ static const struct sock_filter strict_filter[] = { BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, nr))), + BPF_JUMP(BPF_JMP | BPF_JEQ, __NR_waitid, 7, 0), BPF_JUMP(BPF_JMP | BPF_JEQ, __NR_rt_sigprocmask, 6, 0), BPF_JUMP(BPF_JMP | BPF_JEQ, __NR_close, 5, 0), BPF_JUMP(BPF_JMP | BPF_JEQ, __NR_exit, 4, 0), diff --git a/testcases/kernel/syscalls/preadv2/preadv203.c b/testcases/kernel/syscalls/preadv2/preadv203.c index 25c6e1c2e..c87deb674 100644 --- a/testcases/kernel/syscalls/preadv2/preadv203.c +++ b/testcases/kernel/syscalls/preadv2/preadv203.c @@ -159,7 +159,7 @@ static void *writer_thread(void *unused) while (!stop) { int fd = fds[random() % FILES]; - for (j = 0; j < CHUNKS; j++) { + for (j = 0; j < CHUNKS && !stop; j++) { memset(buf, '0' + j, sizeof(buf)); off_t off = CHUNK_SZ * j; diff --git a/testcases/kernel/syscalls/process_madvise/.gitignore b/testcases/kernel/syscalls/process_madvise/.gitignore new file mode 100644 index 000000000..93d2640f7 --- /dev/null +++ b/testcases/kernel/syscalls/process_madvise/.gitignore @@ -0,0 +1 @@ +/process_madvise01 diff --git a/testcases/kernel/syscalls/paging/Makefile b/testcases/kernel/syscalls/process_madvise/Makefile index 044619fb8..ad5b66061 100644 --- a/testcases/kernel/syscalls/paging/Makefile +++ b/testcases/kernel/syscalls/process_madvise/Makefile @@ -1,8 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (c) International Business Machines Corp., 2001 +# Copyright (C) 2023 Linux Test Project, Inc. top_srcdir ?= ../../../.. include $(top_srcdir)/include/mk/testcases.mk - include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/syscalls/process_madvise/process_madvise.h b/testcases/kernel/syscalls/process_madvise/process_madvise.h new file mode 100644 index 000000000..5b227ada0 --- /dev/null +++ b/testcases/kernel/syscalls/process_madvise/process_madvise.h @@ -0,0 +1,101 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +#ifndef PROCESS_MADVISE_H__ +#define PROCESS_MADVISE_H__ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "tst_safe_stdio.h" + +struct addr_mapping { + int size; + int rss; + int pss; + int shared_clean; + int shared_dirty; + int private_clean; + int private_dirty; + int referenced; + int anonymous; + int anon_huge_pages; + int shmem_huge_pages; + int shmem_pmd_mapped; + int swap; + int kernel_page_size; + int mmu_page_size; + int locked; + int protection_key; +}; + +static inline void read_address_mapping(unsigned long address, struct addr_mapping *mapping) +{ + FILE *f; + int found = 0; + char label[BUFSIZ]; + char line[BUFSIZ]; + char smaps[BUFSIZ]; + char ptr_str[BUFSIZ]; + int value; + + snprintf(smaps, BUFSIZ, "/proc/%i/smaps", getpid()); + snprintf(ptr_str, BUFSIZ, "%lx", address); + + f = SAFE_FOPEN(smaps, "r"); + + while (fgets(line, BUFSIZ, f) != NULL) { + if (strncmp(ptr_str, line, strlen(ptr_str)) == 0) + found = 1; + + if (!found) + continue; + + if (found && strncmp(line, "VmFlags", 7) == 0) + break; + + if (sscanf(line, "%31[^:]: %d", label, &value) > 0) { + if (strcmp(label, "Size") == 0) + mapping->size = value; + else if (strcmp(label, "Rss") == 0) + mapping->rss = value; + else if (strcmp(label, "Pss") == 0) + mapping->pss = value; + else if (strcmp(label, "Shared_Clean") == 0) + mapping->shared_clean = value; + else if (strcmp(label, "Shared_Dirty") == 0) + mapping->shared_dirty = value; + else if (strcmp(label, "Private_Clean") == 0) + mapping->private_clean = value; + else if (strcmp(label, "Private_Dirty") == 0) + mapping->private_dirty = value; + else if (strcmp(label, "Referenced") == 0) + mapping->referenced = value; + else if (strcmp(label, "Anonymous") == 0) + mapping->anonymous = value; + else if (strcmp(label, "AnonHugePages") == 0) + mapping->anon_huge_pages = value; + else if (strcmp(label, "ShmemHugePages") == 0) + mapping->shmem_huge_pages = value; + else if (strcmp(label, "ShmemPmdMapped") == 0) + mapping->shmem_pmd_mapped = value; + else if (strcmp(label, "Swap") == 0) + mapping->swap = value; + else if (strcmp(label, "KernelPageSize") == 0) + mapping->kernel_page_size = value; + else if (strcmp(label, "MMUPageSize") == 0) + mapping->mmu_page_size = value; + else if (strcmp(label, "Locked") == 0) + mapping->locked = value; + else if (strcmp(label, "ProtectionKey") == 0) + mapping->protection_key = value; + } + } + + SAFE_FCLOSE(f); +} + +#endif diff --git a/testcases/kernel/syscalls/process_madvise/process_madvise01.c b/testcases/kernel/syscalls/process_madvise/process_madvise01.c new file mode 100644 index 000000000..0fd3c1ef4 --- /dev/null +++ b/testcases/kernel/syscalls/process_madvise/process_madvise01.c @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +/*\ + * [Description] + * + * Allocate anonymous memory pages inside child and reclaim it with + * MADV_PAGEOUT. Then check if memory pages have been swapped out by looking + * at smaps information. + * + * The advice might be ignored for some pages in the range when it is + * not applicable, so test passes if swap memory increases after + * reclaiming memory with MADV_PAGEOUT. + */ + +#define _GNU_SOURCE + +#include <sys/mman.h> +#include "tst_test.h" +#include "lapi/mmap.h" +#include "lapi/syscalls.h" +#include "process_madvise.h" + +#define MEM_CHILD (1 * TST_MB) + +static void **data_ptr; + +static void child_alloc(void) +{ + char data[MEM_CHILD]; + struct addr_mapping map_before; + struct addr_mapping map_after; + + memset(data, 'a', MEM_CHILD); + + tst_res(TINFO, "Allocate memory: %d bytes", MEM_CHILD); + + *data_ptr = SAFE_MMAP(NULL, MEM_CHILD, + PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, 0); + + memset(*data_ptr, 'a', MEM_CHILD); + + memset(&map_before, 0, sizeof(struct addr_mapping)); + read_address_mapping((unsigned long)*data_ptr, &map_before); + + TST_CHECKPOINT_WAKE_AND_WAIT(0); + + memset(&map_after, 0, sizeof(struct addr_mapping)); + read_address_mapping((unsigned long)*data_ptr, &map_after); + + if (memcmp(*data_ptr, data, MEM_CHILD) != 0) { + tst_res(TFAIL, "Dirty memory after reclaiming it"); + return; + } + + SAFE_MUNMAP(*data_ptr, MEM_CHILD); + *data_ptr = NULL; + + TST_EXP_EXPR(map_before.swap < map_after.swap, + "Most of the memory has been swapped out: %dkB out of %dkB", + map_after.swap - map_before.swap, + MEM_CHILD / TST_KB); +} + +static void setup(void) +{ + data_ptr = SAFE_MMAP(NULL, sizeof(void *), + PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, 0); +} + +static void cleanup(void) +{ + if (*data_ptr) + SAFE_MUNMAP(*data_ptr, MEM_CHILD); + + if (data_ptr) + SAFE_MUNMAP(data_ptr, sizeof(void *)); +} + +static void run(void) +{ + int ret; + int pidfd; + pid_t pid_alloc; + struct iovec vec; + + pid_alloc = SAFE_FORK(); + if (!pid_alloc) { + child_alloc(); + return; + } + + TST_CHECKPOINT_WAIT(0); + + tst_res(TINFO, "Reclaim memory using MADV_PAGEOUT"); + + pidfd = SAFE_PIDFD_OPEN(pid_alloc, 0); + + vec.iov_base = *data_ptr; + vec.iov_len = MEM_CHILD; + + ret = tst_syscall(__NR_process_madvise, pidfd, &vec, 1UL, + MADV_PAGEOUT, 0UL); + + if (ret == -1) + tst_brk(TBROK | TERRNO, "process_madvise failed"); + + if (ret != MEM_CHILD) + tst_brk(TBROK, "process_madvise reclaimed only %d bytes", ret); + + TST_CHECKPOINT_WAKE(0); +} + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test_all = run, + .forks_child = 1, + .min_kver = "5.10", + .needs_checkpoints = 1, + .needs_root = 1, + .min_swap_avail = MEM_CHILD / TST_MB, + .needs_kconfigs = (const char *[]) { + "CONFIG_SWAP=y", + NULL + }, +}; diff --git a/testcases/kernel/syscalls/quotactl/quotactl08.c b/testcases/kernel/syscalls/quotactl/quotactl08.c index da1d62a32..0fabb51a5 100644 --- a/testcases/kernel/syscalls/quotactl/quotactl08.c +++ b/testcases/kernel/syscalls/quotactl/quotactl08.c @@ -28,6 +28,7 @@ * - turn off quota with Q_QUOTAOFF flag for group * * It is similar to quotactl01.c, only two difference + * * - use new quotactl_fd syscalls if supports * - quota file hidden in filesystem * diff --git a/testcases/kernel/syscalls/readahead/readahead02.c b/testcases/kernel/syscalls/readahead/readahead02.c index 7acf4bb18..dc03c5931 100644 --- a/testcases/kernel/syscalls/readahead/readahead02.c +++ b/testcases/kernel/syscalls/readahead/readahead02.c @@ -318,6 +318,19 @@ static void test_readahead(unsigned int n) tst_res(TCONF, "Page cache on your system is too small " "to hold whole testfile."); } + + /* + * The time consuming of readahead quite depending on the platform IO + * speed, sometime test timeout when the default max_runtime is used up. + * + * readahead02.c:221: TINFO: Test #2: POSIX_FADV_WILLNEED on file + * readahead02.c:285: TINFO: read_testfile(0) took: 26317623 usec + * readahead02.c:286: TINFO: read_testfile(1) took: 26101484 usec + * + * Here raise the maximum runtime dynamically. + */ + if ((tc+1)->readahead) + tst_set_max_runtime(test.max_runtime + (usec + usec_ra) / 1000000); } @@ -352,7 +365,7 @@ static void setup_readahead_length(void) /* raise bdi limit as much as kernel allows */ ra_new_limit = testfile_size / 1024; while (ra_new_limit > pagesize / 1024) { - FILE_PRINTF(sys_bdi_ra_path, "%d", ra_new_limit); + SAFE_FILE_PRINTF(sys_bdi_ra_path, "%d", ra_new_limit); SAFE_FILE_SCANF(sys_bdi_ra_path, "%d", &ra_limit); if (ra_limit == ra_new_limit) { diff --git a/testcases/kernel/syscalls/readlinkat/readlinkat01.c b/testcases/kernel/syscalls/readlinkat/readlinkat01.c index 985890ebe..b1214c3ae 100644 --- a/testcases/kernel/syscalls/readlinkat/readlinkat01.c +++ b/testcases/kernel/syscalls/readlinkat/readlinkat01.c @@ -1,143 +1,103 @@ -/****************************************************************************** - * +// SPDX-License-Identifier: GPL-2.0-or-later +/* * Copyright (c) International Business Machines Corp., 2006 - * Author: Yi Yang <yyangcdl@cn.ibm.com> * Copyright (c) Cyril Hrubis 2014 <chrubis@suse.cz> + * Copyright (c) Linux Test Project, 2003-2023 + * Author: Yi Yang <yyangcdl@cn.ibm.com> + */ + +/*\ + * [Description] * - * 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 - * - * This test case will verify basic function of readlinkat - * added by kernel 2.6.16 or up. + * Check the basic functionality of the readlinkat() system call. * - *****************************************************************************/ + * - readlinkat() passes if dirfd is directory file descriptor + * and the pathname is relative. + * - readlinkat() passes if the pathname is abspath, then dirfd + * is ignored. + * - readlinkat() passes if dirfd is the special value AT_FDCWD + * and the pathname is relative. + * - readlinkat() passes if pathname is an empty string, in which + * case the call operates on the symbolic link referred to by dirfd. + */ -#define _GNU_SOURCE - -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/time.h> -#include <fcntl.h> #include <stdlib.h> -#include <errno.h> -#include <string.h> -#include <signal.h> -#include "test.h" -#include "safe_macros.h" -#include "lapi/readlinkat.h" - -static void setup(void); -static void cleanup(void); +#include <stdio.h> +#include "tst_test.h" +#include "lapi/fcntl.h" -char *TCID = "readlinkat01"; +#define TEST_FILE "readlink_file" +#define TEST_SYMLINK "readlink_symlink" -static int dir_fd, fd; -static int fd_invalid = 100; +static int file_fd, dir_fd, dir_fd2; static int fd_atcwd = AT_FDCWD; - -#define TEST_SYMLINK "readlink_symlink" -#define TEST_FILE "readlink_file" - -static char abspath[1024]; - -static struct test_case { - int *dir_fd; - const char *path; - const char *exp_buf; - int exp_ret; - int exp_errno; -} test_cases[] = { - {&dir_fd, TEST_SYMLINK, TEST_FILE, sizeof(TEST_FILE)-1, 0}, - {&dir_fd, abspath, TEST_FILE, sizeof(TEST_FILE)-1, 0}, - {&fd, TEST_SYMLINK, NULL, -1, ENOTDIR}, - {&fd_invalid, TEST_SYMLINK, NULL, -1, EBADF}, - {&fd_atcwd, TEST_SYMLINK, TEST_FILE, sizeof(TEST_FILE)-1, 0}, +static const char *abspath; +static const char *testsymlink; +static const char *emptypath; + +static struct tcase { + int *fd; + const char **path; +} tcases[] = { + {&dir_fd, &testsymlink}, + {&dir_fd, &abspath}, + {&file_fd, &abspath}, + {&fd_atcwd, &abspath}, + {&fd_atcwd, &testsymlink}, + {&dir_fd2, &emptypath}, }; -int TST_TOTAL = ARRAY_SIZE(test_cases); - -static void verify_readlinkat(struct test_case *test) +static void verify_readlinkat(unsigned int i) { char buf[1024]; + struct tcase *tc = &tcases[i]; memset(buf, 0, sizeof(buf)); - TEST(readlinkat(*test->dir_fd, test->path, buf, sizeof(buf))); - - if (TEST_RETURN != test->exp_ret) { - tst_resm(TFAIL | TTERRNO, - "readlinkat() returned %ld, expected %d", - TEST_RETURN, test->exp_ret); - return; - } - - if (TEST_ERRNO != test->exp_errno) { - tst_resm(TFAIL | TTERRNO, - "readlinkat() returned %ld, expected %d", - TEST_RETURN, test->exp_ret); - return; - } - - if (test->exp_ret > 0 && strcmp(test->exp_buf, buf)) { - tst_resm(TFAIL, "Unexpected buffer have '%s', expected '%s'", - buf, test->exp_buf); - return; - } - - tst_resm(TPASS | TTERRNO, "readlinkat() returned %ld", TEST_RETURN); -} - -int main(int ac, char **av) -{ - int lc; - int i; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); + TST_EXP_POSITIVE(readlinkat(*tc->fd, *tc->path, buf, sizeof(buf)), + "readlinkat(%d, %s, %s, %ld)", + *tc->fd, *tc->path, buf, sizeof(buf)); - for (lc = 0; TEST_LOOPING(lc); lc++) { - for (i = 0; i < TST_TOTAL; i++) - verify_readlinkat(&test_cases[i]); - } - - cleanup(); - tst_exit(); + if (strcmp(buf, TEST_FILE) == 0) + tst_res(TPASS, "The filename in buffer is correct"); + else + tst_res(TFAIL, "Wrong filename in buffer '%s'", buf); } static void setup(void) { - tst_tmpdir(); char *tmpdir = tst_get_tmpdir(); - snprintf(abspath, sizeof(abspath), "%s/" TEST_SYMLINK, tmpdir); + abspath = tst_aprintf("%s/" TEST_SYMLINK, tmpdir); free(tmpdir); - fd = SAFE_OPEN(cleanup, TEST_FILE, O_CREAT, 0600); - SAFE_SYMLINK(cleanup, TEST_FILE, TEST_SYMLINK); - dir_fd = SAFE_OPEN(cleanup, ".", O_DIRECTORY); - - TEST_PAUSE; + file_fd = SAFE_OPEN(TEST_FILE, O_CREAT, 0600); + SAFE_SYMLINK(TEST_FILE, TEST_SYMLINK); + dir_fd = SAFE_OPEN(".", O_DIRECTORY); + dir_fd2 = SAFE_OPEN(TEST_SYMLINK, O_PATH | O_NOFOLLOW); } static void cleanup(void) { - if (fd > 0 && close(fd)) - tst_resm(TWARN | TERRNO, "Failed to close fd"); + if (file_fd > -1) + SAFE_CLOSE(file_fd); - if (dir_fd > 0 && close(dir_fd)) - tst_resm(TWARN | TERRNO, "Failed to close dir_fd"); + if (dir_fd > -1) + SAFE_CLOSE(dir_fd); - tst_rmdir(); + if (dir_fd2 > -1) + SAFE_CLOSE(dir_fd2); } + +static struct tst_test test = { + .test = verify_readlinkat, + .needs_tmpdir = 1, + .setup = setup, + .cleanup = cleanup, + .bufs = (struct tst_buffers []) { + {&testsymlink, .str = TEST_SYMLINK}, + {&emptypath, .str = ""}, + {}, + }, + .tcnt = ARRAY_SIZE(tcases), +}; diff --git a/testcases/kernel/syscalls/readlinkat/readlinkat02.c b/testcases/kernel/syscalls/readlinkat/readlinkat02.c index d30c1917a..64afb898f 100644 --- a/testcases/kernel/syscalls/readlinkat/readlinkat02.c +++ b/testcases/kernel/syscalls/readlinkat/readlinkat02.c @@ -1,122 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2014 Fujitsu Ltd. + * Copyright (c) Linux Test Project, 2003-2023 * Author: Zeng Linggang <zenglg.jy@cn.fujitsu.com> + */ + +/*\ + * [Description] * - * 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. + * - readlinkat() fails with EINVAL if the bufsiz is 0. * - * 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 Library General Public License for more details. + * - readlinkat() fails with EINVAL if the named file is not a symbolic link. * - * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * - readlinkat() fails with ENOTDIR if the component of the path prefix is + * not a directory. * - */ -/* - * Test Description: - * Verify that, - * 1. bufsiz is 0, EINVAL should be returned. - * 2. The named file is not a symbolic link, EINVAL should be returned. - * 3. The component of the path prefix is not a directory, ENOTDIR should be - * returned. - * 4. pathname is relative and dirfd is a file descriptor referring to a file - * other than a directory, ENOTDIR should be returned. + * - readlinkat() fails with ENOTDIR if the pathname is relative and + * dirfd is a file descriptor referring to a file other than a directory. + * + * - readlinkat() fails with EBADF if the file descriptor is invalid. + * + * - readlinkat() fails with ENOENT when the pathname does not exists. */ -#include <fcntl.h> -#include <unistd.h> -#include <errno.h> - -#include "test.h" -#include "safe_macros.h" -#include "lapi/readlinkat.h" -#include "lapi/syscalls.h" +#include "tst_test.h" #define TEST_FILE "test_file" #define SYMLINK_FILE "symlink_file" #define BUFF_SIZE 256 static int file_fd, dir_fd; +static int fd_invalid = -1; -static struct test_case_t { - int *dirfd; +static struct tcase { + int *fd; const char *pathname; size_t bufsiz; int exp_errno; -} test_cases[] = { +} tcases[] = { {&dir_fd, SYMLINK_FILE, 0, EINVAL}, {&dir_fd, TEST_FILE, BUFF_SIZE, EINVAL}, {&file_fd, SYMLINK_FILE, BUFF_SIZE, ENOTDIR}, {&dir_fd, "test_file/test_file", BUFF_SIZE, ENOTDIR}, + {&fd_invalid, SYMLINK_FILE, BUFF_SIZE, EBADF}, + {&dir_fd, "does_not_exists", BUFF_SIZE, ENOENT}, }; -char *TCID = "readlinkat02"; -int TST_TOTAL = ARRAY_SIZE(test_cases); -static void setup(void); -static void cleanup(void); -static void readlinkat_verify(const struct test_case_t *); - -int main(int argc, char **argv) +static void verify_readlinkat(unsigned int i) { - int i, lc; - - tst_parse_opts(argc, argv, NULL, NULL); - - setup(); + char buf[BUFF_SIZE]; + struct tcase *tc = &tcases[i]; - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - for (i = 0; i < TST_TOTAL; i++) - readlinkat_verify(&test_cases[i]); - } + memset(buf, 0, sizeof(buf)); - cleanup(); - tst_exit(); + TST_EXP_FAIL(readlinkat(*tc->fd, tc->pathname, buf, tc->bufsiz), + tc->exp_errno, "readlinkat(%d, %s, NULL, %ld)", + *tc->fd, tc->pathname, tc->bufsiz); } static void setup(void) { - tst_sig(NOFORK, DEF_HANDLER, cleanup); + dir_fd = SAFE_OPEN(".", O_RDONLY); - TEST_PAUSE; + file_fd = SAFE_OPEN(TEST_FILE, O_RDWR | O_CREAT, 0644); - tst_tmpdir(); - - dir_fd = SAFE_OPEN(cleanup, "./", O_RDONLY); - - file_fd = SAFE_OPEN(cleanup, TEST_FILE, O_RDWR | O_CREAT, 0644); - - SAFE_SYMLINK(cleanup, TEST_FILE, SYMLINK_FILE); -} - -static void readlinkat_verify(const struct test_case_t *test) -{ - char buf[BUFF_SIZE]; - TEST(readlinkat(*test->dirfd, test->pathname, buf, test->bufsiz)); - - if (TEST_RETURN != -1) { - tst_resm(TFAIL, "readlinkat succeeded unexpectedly"); - return; - } - - if (TEST_ERRNO == test->exp_errno) { - tst_resm(TPASS | TTERRNO, "readlinkat failed as expected"); - } else { - tst_resm(TFAIL | TTERRNO, - "readlinkat failed unexpectedly; expected: %d - %s", - test->exp_errno, strerror(test->exp_errno)); - } + SAFE_SYMLINK(TEST_FILE, SYMLINK_FILE); } static void cleanup(void) { - close(dir_fd); - close(file_fd); + if (file_fd > -1) + SAFE_CLOSE(file_fd); - tst_rmdir(); + if (dir_fd > -1) + SAFE_CLOSE(dir_fd); } + +static struct tst_test test = { + .test = verify_readlinkat, + .needs_tmpdir = 1, + .setup = setup, + .cleanup = cleanup, + .tcnt = ARRAY_SIZE(tcases), +}; diff --git a/testcases/kernel/syscalls/recvmsg/recvmsg01.c b/testcases/kernel/syscalls/recvmsg/recvmsg01.c index 3ce7ab027..80c1b3aa9 100644 --- a/testcases/kernel/syscalls/recvmsg/recvmsg01.c +++ b/testcases/kernel/syscalls/recvmsg/recvmsg01.c @@ -1,364 +1,356 @@ +// 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 + * Copyright (c) 2001 Wayne Boyer International Business Machines + * Copyright (c) Linux Test Project, 2002-2022 + * Copyright (c) 2023 Wei Gao <wegao@suse.com> */ -/* - * Test Name: recvmsg01 - * - * Test Description: - * Verify that recvmsg() returns the proper errno for various failure cases - * - * Usage: <for command-line> - * recvmsg01 [-c n] [-e] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -e : Turn on errno logging. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 07/2001 Ported by Wayne Boyer - * - * RESTRICTIONS: - * None. +/*\ + * [Description] * + * Verify that recvmsg() returns the proper errno for various failure cases. */ #include <stdio.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include <fcntl.h> - +#include <stdlib.h> #include <sys/wait.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/signal.h> -#include <sys/uio.h> -#include <sys/un.h> -#include <sys/file.h> - -#include <netinet/in.h> - -#include "test.h" -#include "safe_macros.h" - -char *TCID = "recvmsg01"; -int testno; - -char buf[1024], cbuf[1024]; -int s; /* socket descriptor */ -int passed_fd = -1; /* rights-passing test descriptor */ -struct sockaddr_in sin1, from; -struct sockaddr_un sun1; -struct msghdr msgdat; -struct cmsghdr *control = 0; -int controllen = 0; -struct iovec iov[1]; +#include "tst_test.h" + +#define MSG "from recvmsg01 server" +#define BUF_SIZE 1024 +#define CONTROL_LEN (128 * 1024) + +static char recv_buf[BUF_SIZE], cbuf[BUF_SIZE]; +static int sock; +static struct sockaddr_in sin1, from; +static struct sockaddr_un sun1; +static struct msghdr msgdat; +static struct cmsghdr *control; +static int controllen; +static struct iovec iov[1]; static int sfd; /* shared between do_child and start_server */ static int ufd; /* shared between do_child and start_server */ - -void setup(void); -void setup0(void); -void setup1(void); -void setup2(void); -void setup3(void); -void setup4(void); -void cleanup(void); -void cleanup0(void); -void cleanup1(void); -void cleanup2(void); -void do_child(void); - -void sender(int); -pid_t start_server(struct sockaddr_in *, struct sockaddr_un *); - -struct test_case_t { /* test case structure */ - int domain; /* PF_INET, PF_UNIX, ... */ - int type; /* SOCK_STREAM, SOCK_DGRAM ... */ - int proto; /* protocol number (usually 0 = default) */ +static pid_t pid; +static char tmpsunpath[BUF_SIZE]; + +static void setup_all(void); +static void setup_invalid_sock(int); +static void setup_valid_sock(int); +static void setup_valid_msg_control(int); +static void setup_large_msg_control(int); +static void cleanup_all(void); +static void cleanup_invalid_sock(int); +static void cleanup_close_sock(int); +static void cleanup_reset_all(int); +static void do_child(void); +static pid_t start_server(struct sockaddr_in *, struct sockaddr_un *); + +static struct tcase { + int domain; + int type; + int protocol; struct iovec *iov; int iovcnt; - void *buf; /* recv data buffer */ - int buflen; /* recv buffer length */ + void *recv_buf; + int buflen; struct msghdr *msg; - unsigned flags; - struct sockaddr *from; /* from address */ - int fromlen; /* from address value/result buffer length */ - int retval; /* syscall return value */ - int experrno; /* expected errno */ - void (*setup) (void); - void (*cleanup) (void); + unsigned int flags; + struct sockaddr *from; + int fromlen; + int exp_errno; + void (*setup)(int n); + void (*cleanup)(int n); char *desc; -} tdat[] = { -/* 1 */ - { - PF_INET, SOCK_STREAM, 0, iov, 1, buf, sizeof(buf), &msgdat, 0, - (struct sockaddr *)&from, sizeof(from), - -1, EBADF, setup0, cleanup0, "bad file descriptor"} - , -/* 2 */ +} tcases[] = { { - 0, 0, 0, iov, 1, (void *)buf, sizeof(buf), &msgdat, 0, - (struct sockaddr *)&from, sizeof(from), - -1, ENOTSOCK, setup0, cleanup0, "invalid socket"} - , -/* 3 */ + .domain = PF_INET, + .type = SOCK_STREAM, + .iov = iov, + .iovcnt = 1, + .recv_buf = recv_buf, + .buflen = sizeof(recv_buf), + .msg = &msgdat, + .from = (struct sockaddr *)&from, + .fromlen = sizeof(from), + .exp_errno = EBADF, + .setup = setup_invalid_sock, + .cleanup = cleanup_invalid_sock, + .desc = "bad file descriptor", + }, { - PF_INET, SOCK_STREAM, 0, iov, 1, (void *)buf, sizeof(buf), - &msgdat, 0, (struct sockaddr *)-1, sizeof(from), 0, - ENOTSOCK, setup1, cleanup1, "invalid socket buffer"} - , -/* 4 */ + .domain = PF_INET, + .type = SOCK_STREAM, + .iov = iov, + .iovcnt = 1, + .recv_buf = (void *)recv_buf, + .buflen = sizeof(recv_buf), + .msg = &msgdat, + .from = (struct sockaddr *)&from, + .fromlen = sizeof(from), + .exp_errno = ENOTSOCK, + .setup = setup_invalid_sock, + .cleanup = cleanup_invalid_sock, + .desc = "invalid socket", + }, { - PF_INET, SOCK_STREAM, 0, iov, 1, (void *)buf, sizeof(buf), - &msgdat, -1, (struct sockaddr *)&from, -1, -1, - EINVAL, setup1, cleanup1, "invalid socket length"}, -/* 5 */ + .domain = PF_INET, + .type = SOCK_STREAM, + .iov = iov, + .iovcnt = 1, + .recv_buf = (void *)recv_buf, + .buflen = sizeof(recv_buf), + .msg = &msgdat, + .flags = -1, + .from = (struct sockaddr *)&from, + .fromlen = -1, + .exp_errno = EINVAL, + .setup = setup_valid_sock, + .cleanup = cleanup_close_sock, + .desc = "invalid socket length", + }, { - PF_INET, SOCK_STREAM, 0, iov, 1, (void *)-1, sizeof(buf), - &msgdat, 0, (struct sockaddr *)&from, sizeof(from), - -1, EFAULT, setup1, cleanup1, "invalid recv buffer"} - , -/* 6 */ + .domain = PF_INET, + .type = SOCK_STREAM, + .iov = iov, + .iovcnt = 1, + .recv_buf = (void *)-1, + .buflen = sizeof(recv_buf), + .msg = &msgdat, + .from = (struct sockaddr *)&from, + .fromlen = sizeof(from), + .exp_errno = EFAULT, + .setup = setup_valid_sock, + .cleanup = cleanup_close_sock, + .desc = "invalid recv buffer", + }, { - PF_INET, SOCK_STREAM, 0, 0, 1, (void *)buf, sizeof(buf), - &msgdat, 0, (struct sockaddr *)&from, sizeof(from), - -1, EFAULT, setup1, cleanup1, "invalid iovec buffer"} - , -/* 7 */ + .domain = PF_INET, + .type = SOCK_STREAM, + .iovcnt = 1, + .recv_buf = recv_buf, + .buflen = sizeof(recv_buf), + .msg = &msgdat, + .from = (struct sockaddr *)&from, + .fromlen = sizeof(from), + .exp_errno = EFAULT, + .setup = setup_valid_sock, + .cleanup = cleanup_close_sock, + .desc = "invalid iovec buffer", + }, { - PF_INET, SOCK_STREAM, 0, iov, -1, (void *)buf, sizeof(buf), - &msgdat, 0, (struct sockaddr *)&from, sizeof(from), - -1, EMSGSIZE, setup1, cleanup1, "invalid iovec count"} - , -/* 8 */ + .domain = PF_INET, + .type = SOCK_STREAM, + .iov = iov, + .iovcnt = -1, + .recv_buf = recv_buf, + .buflen = sizeof(recv_buf), + .msg = &msgdat, + .from = (struct sockaddr *)&from, + .fromlen = sizeof(from), + .exp_errno = EMSGSIZE, + .setup = setup_valid_sock, + .cleanup = cleanup_close_sock, + .desc = "invalid iovec count", + }, { - PF_UNIX, SOCK_STREAM, 0, iov, 1, (void *)buf, sizeof(buf), - &msgdat, 0, (struct sockaddr *)&from, sizeof(from), - 0, 0, setup2, cleanup2, "rights reception"} - , -/* 9 */ + .domain = PF_INET, + .type = SOCK_STREAM, + .iov = iov, + .iovcnt = 1, + .recv_buf = recv_buf, + .buflen = sizeof(recv_buf), + .msg = &msgdat, + .from = (struct sockaddr *)&from, + .fromlen = sizeof(from), + .setup = setup_valid_msg_control, + .cleanup = cleanup_reset_all, + .desc = "permission reception", + }, { - PF_INET, SOCK_STREAM, 0, iov, 1, (void *)buf, sizeof(buf), - &msgdat, MSG_OOB, (struct sockaddr *)&from, - sizeof(from), -1, EINVAL, setup1, cleanup1, - "invalid MSG_OOB flag set"} - , -/* 10 */ + .domain = PF_INET, + .type = SOCK_STREAM, + .iov = iov, + .iovcnt = 1, + .recv_buf = recv_buf, + .buflen = sizeof(recv_buf), + .msg = &msgdat, + .flags = MSG_OOB, + .from = (struct sockaddr *)&from, + .fromlen = sizeof(from), + .exp_errno = EINVAL, + .setup = setup_valid_sock, + .cleanup = cleanup_close_sock, + .desc = "invalid MSG_OOB flag set", + }, { - PF_INET, SOCK_STREAM, 0, iov, 1, (void *)buf, sizeof(buf), - &msgdat, MSG_ERRQUEUE, (struct sockaddr *)&from, - sizeof(from), -1, EAGAIN, setup1, cleanup1, - "invalid MSG_ERRQUEUE flag set"} - , -/* 11 */ + .domain = PF_INET, + .type = SOCK_STREAM, + .iov = iov, + .iovcnt = 1, + .recv_buf = recv_buf, + .buflen = sizeof(recv_buf), + .msg = &msgdat, + .flags = MSG_ERRQUEUE, + .from = (struct sockaddr *)&from, + .fromlen = sizeof(from), + .exp_errno = EAGAIN, + .setup = setup_valid_sock, + .cleanup = cleanup_close_sock, + .desc = "invalid MSG_ERRQUEUE flag set", + }, { - PF_UNIX, SOCK_STREAM, 0, iov, 1, (void *)buf, sizeof(buf), - &msgdat, 0, (struct sockaddr *)&from, sizeof(from), - 0, EINVAL, setup3, cleanup2, "invalid cmsg length"} - , -/* 12 */ - { - PF_UNIX, SOCK_STREAM, 0, iov, 1, (void *)buf, sizeof(buf), - &msgdat, 0, (struct sockaddr *)&from, sizeof(from), - 0, 0, setup4, cleanup2, "large cmesg length"} -,}; - -int TST_TOTAL = sizeof(tdat) / sizeof(tdat[0]); - -#ifdef UCLINUX -static char *argv0; -#endif - -int main(int argc, char *argv[]) + .domain = PF_INET, + .type = SOCK_STREAM, + .iov = iov, + .iovcnt = 1, + .recv_buf = recv_buf, + .buflen = sizeof(recv_buf), + .msg = &msgdat, + .from = (struct sockaddr *)&from, + .fromlen = sizeof(from), + .setup = setup_large_msg_control, + .cleanup = cleanup_reset_all, + .desc = "large cmesg length", + }, + +}; + +static void run(unsigned int n) { - int lc; - - tst_parse_opts(argc, argv, NULL, NULL); -#ifdef UCLINUX - argv0 = argv[0]; - maybe_run_child(&do_child, "dd", &sfd, &ufd); -#endif - - setup(); - - for (lc = 0; TEST_LOOPING(lc); ++lc) { - tst_count = 0; - for (testno = 0; testno < TST_TOTAL; ++testno) { - if ((tst_kvercmp(3, 17, 0) < 0) - && (tdat[testno].flags & MSG_ERRQUEUE) - && (tdat[testno].type & SOCK_STREAM)) { - tst_resm(TCONF, "skip MSG_ERRQUEUE test, " - "it's supported from 3.17"); - continue; - } + struct tcase *tc = &tcases[n]; + int ret = tc->exp_errno ? -1 : 0; - tdat[testno].setup(); - - /* setup common to all tests */ - iov[0].iov_base = tdat[testno].buf; - iov[0].iov_len = tdat[testno].buflen; - msgdat.msg_name = tdat[testno].from; - msgdat.msg_namelen = tdat[testno].fromlen; - msgdat.msg_iov = tdat[testno].iov; - msgdat.msg_iovlen = tdat[testno].iovcnt; - msgdat.msg_control = control; - msgdat.msg_controllen = controllen; - msgdat.msg_flags = 0; - - TEST(recvmsg(s, tdat[testno].msg, tdat[testno].flags)); - if (TEST_RETURN >= 0) - TEST_RETURN = 0; /* all nonzero equal here */ - if (TEST_RETURN != tdat[testno].retval || - (TEST_RETURN < 0 && - TEST_ERRNO != tdat[testno].experrno)) { - tst_resm(TFAIL, "%s ; returned" - " %ld (expected %d), errno %d (expected" - " %d)", tdat[testno].desc, - TEST_RETURN, tdat[testno].retval, - TEST_ERRNO, tdat[testno].experrno); - } else { - tst_resm(TPASS, "%s successful", - tdat[testno].desc); - } - tdat[testno].cleanup(); - } + if ((tst_kvercmp(3, 17, 0) < 0) + && (tc->flags & MSG_ERRQUEUE) + && (tc->type & SOCK_STREAM)) { + tst_res(TCONF, "MSG_ERRQUEUE requires kernel >= 3.17"); + return; + } + + setup_all(); + tc->setup(n); + + iov[0].iov_base = tc->recv_buf; + iov[0].iov_len = tc->buflen; + msgdat.msg_name = tc->from; + msgdat.msg_namelen = tc->fromlen; + msgdat.msg_iov = tc->iov; + msgdat.msg_iovlen = tc->iovcnt; + msgdat.msg_control = control; + msgdat.msg_controllen = controllen; + msgdat.msg_flags = 0; + + TEST(recvmsg(sock, tc->msg, tc->flags)); + if (TST_RET >= 0) + TST_RET = 0; + + if (TST_RET != ret) { + tst_res(TFAIL | TTERRNO, "%s: expected %d, returned %ld", + tc->desc, ret, TST_RET); + } else if (TST_ERR != tc->exp_errno) { + tst_res(TFAIL | TTERRNO, + "%s: expected %s", + tc->desc, tst_strerrno(tc->exp_errno)); + } else { + tst_res(TPASS, "%s passed", tc->desc); } - cleanup(); - tst_exit(); + tc->cleanup(n); + cleanup_all(); } -pid_t pid; -char tmpsunpath[1024]; -void setup(void) +static void setup_all(void) { int tfd; - TEST_PAUSE; - tst_tmpdir(); + sun1.sun_family = AF_UNIX; + (void)strcpy(tmpsunpath, "udsockXXXXXX"); tfd = mkstemp(tmpsunpath); - close(tfd); - unlink(tmpsunpath); - sun1.sun_family = AF_UNIX; + SAFE_CLOSE(tfd); + SAFE_UNLINK(tmpsunpath); (void)strcpy(sun1.sun_path, tmpsunpath); - - signal(SIGPIPE, SIG_IGN); - + SAFE_SIGNAL(SIGPIPE, SIG_IGN); pid = start_server(&sin1, &sun1); } -void cleanup(void) +static void cleanup_all(void) { if (pid > 0) { (void)kill(pid, SIGKILL); /* kill server */ wait(NULL); } - if (tmpsunpath[0] != '\0') - (void)unlink(tmpsunpath); - tst_rmdir(); + if (tmpsunpath[0] != '\0') + (void)SAFE_UNLINK(tmpsunpath); } -void setup0(void) +static void setup_invalid_sock(int n) { - if (tdat[testno].experrno == EBADF) - s = 400; /* anything not an open file */ - else if ((s = open("/dev/null", O_WRONLY)) == -1) - tst_brkm(TBROK | TERRNO, cleanup, "open(/dev/null) failed"); + if (tcases[n].exp_errno == EBADF) + sock = 400; /* anything not an open file */ + else + sock = SAFE_OPEN("/dev/null", O_WRONLY); } -void cleanup0(void) +static void cleanup_invalid_sock(int n) { - s = -1; + if (tcases[n].exp_errno == EBADF) + sock = -1; + else + SAFE_CLOSE(sock); } -void setup1(void) +static void setup_valid_sock(int n) { fd_set rdfds; struct timeval timeout; - int n; - - s = SAFE_SOCKET(cleanup, tdat[testno].domain, tdat[testno].type, - tdat[testno].proto); - if (tdat[testno].type == SOCK_STREAM) { - if (tdat[testno].domain == PF_INET) { - SAFE_CONNECT(cleanup, s, (struct sockaddr *)&sin1, - sizeof(sin1)); + + sock = SAFE_SOCKET(tcases[n].domain, tcases[n].type, tcases[n].protocol); + + if (tcases[n].type == SOCK_STREAM) { + if (tcases[n].domain == PF_INET) { + SAFE_CONNECT(sock, (struct sockaddr *)&sin1, sizeof(sin1)); /* Wait for something to be readable, else we won't detect EFAULT on recv */ FD_ZERO(&rdfds); - FD_SET(s, &rdfds); + FD_SET(sock, &rdfds); timeout.tv_sec = 2; timeout.tv_usec = 0; - n = select(s + 1, &rdfds, 0, 0, &timeout); - if (n != 1 || !FD_ISSET(s, &rdfds)) - tst_brkm(TBROK, cleanup, - "client setup1 failed - no message ready in 2 sec"); - } else if (tdat[testno].domain == PF_UNIX) { - SAFE_CONNECT(cleanup, s, (struct sockaddr *)&sun1, - sizeof(sun1)); + n = select(sock + 1, &rdfds, 0, 0, &timeout); + + if (n != 1 || !FD_ISSET(sock, &rdfds)) + tst_brk(TBROK, "no message ready in %d sec", (int)timeout.tv_sec); + + } else if (tcases[n].domain == PF_UNIX) { + SAFE_CONNECT(sock, (struct sockaddr *)&sun1, sizeof(sun1)); } } } -void setup2(void) +static void setup_valid_msg_control(int n) { - setup1(); - if (write(s, "R", 1) < 0) - tst_brkm(TBROK | TERRNO, cleanup, "test setup failed: write:"); + setup_valid_sock(n); + SAFE_SEND(1, sock, "R", 1, 0); control = (struct cmsghdr *)cbuf; controllen = control->cmsg_len = sizeof(cbuf); } -void setup3(void) +static void setup_large_msg_control(int n) { - setup2(); - controllen = sizeof(struct cmsghdr) - 1; + setup_valid_msg_control(n); + controllen = CONTROL_LEN; } -void setup4(void) +static void cleanup_close_sock(int n LTP_ATTRIBUTE_UNUSED) { - setup2(); - controllen = 128 * 1024; + SAFE_CLOSE(sock); } -void cleanup1(void) +static void cleanup_reset_all(int n LTP_ATTRIBUTE_UNUSED) { - (void)close(s); - close(ufd); - close(sfd); - s = -1; -} + SAFE_CLOSE(sock); -void cleanup2(void) -{ - close(ufd); - close(sfd); - (void)close(s); - s = -1; - - if (passed_fd >= 0) - (void)close(passed_fd); - passed_fd = -1; control = 0; controllen = 0; } @@ -373,63 +365,70 @@ pid_t start_server(struct sockaddr_in *ssin, struct sockaddr_un *ssun) ssin->sin_addr.s_addr = INADDR_ANY; /* set up inet socket */ - sfd = socket(PF_INET, SOCK_STREAM, 0); - if (sfd < 0) { - tst_brkm(TBROK | TERRNO, cleanup, "server socket failed"); - return -1; - } - if (bind(sfd, (struct sockaddr *)ssin, sizeof(*ssin)) < 0) { - tst_brkm(TBROK | TERRNO, cleanup, "server bind failed"); - return -1; - } - if (listen(sfd, 10) < 0) { - tst_brkm(TBROK | TERRNO, cleanup, "server listen failed"); - return -1; - } - SAFE_GETSOCKNAME(cleanup, sfd, (struct sockaddr *)ssin, &slen); + sfd = SAFE_SOCKET(PF_INET, SOCK_STREAM, 0); + SAFE_BIND(sfd, (struct sockaddr *)ssin, sizeof(*ssin)); + SAFE_LISTEN(sfd, 10); + SAFE_GETSOCKNAME(sfd, (struct sockaddr *)ssin, &slen); /* set up UNIX-domain socket */ - ufd = socket(PF_UNIX, SOCK_STREAM, 0); - if (ufd < 0) { - tst_brkm(TBROK | TERRNO, cleanup, "server UD socket failed"); - return -1; - } - if (bind(ufd, (struct sockaddr *)ssun, sizeof(*ssun))) { - tst_brkm(TBROK | TERRNO, cleanup, "server UD bind failed"); - return -1; - } - if (listen(ufd, 10) < 0) { - tst_brkm(TBROK | TERRNO, cleanup, "server UD listen failed"); - return -1; - } + ufd = SAFE_SOCKET(PF_UNIX, SOCK_STREAM, 0); + SAFE_BIND(ufd, (struct sockaddr *)ssun, sizeof(*ssun)); + SAFE_LISTEN(ufd, 10); - switch ((pid = FORK_OR_VFORK())) { - case 0: /* child */ -#ifdef UCLINUX - if (self_exec(argv0, "dd", sfd, ufd) < 0) - tst_brkm(TBROK | TERRNO, cleanup, - "server self_exec failed"); -#else + pid = SAFE_FORK(); + if (!pid) { do_child(); -#endif - break; - case -1: - tst_brkm(TBROK | TERRNO, cleanup, "server fork failed"); - /* fall through */ - default: /* parent */ - (void)close(sfd); - (void)close(ufd); - return pid; + exit(1); } - exit(1); + + SAFE_CLOSE(sfd); + SAFE_CLOSE(ufd); + + return pid; +} + +/* for permission test */ +static void sender(int fd) +{ + struct msghdr mh = {}; + struct cmsghdr *control; + char tmpfn[BUF_SIZE] = ""; + char snd_cbuf[BUF_SIZE] = ""; + int tfd; + + (void)strcpy(tmpfn, "smtXXXXXX"); + tfd = mkstemp(tmpfn); + if (tfd < 0) + return; + + /* set up cmsghdr */ + control = (struct cmsghdr *)snd_cbuf; + control->cmsg_len = sizeof(struct cmsghdr) + 4; + control->cmsg_level = SOL_SOCKET; + control->cmsg_type = SCM_RIGHTS; + *(int *)CMSG_DATA(control) = tfd; + + /* set up msghdr */ + iov[0].iov_base = MSG; + iov[0].iov_len = sizeof(MSG); + mh.msg_iov = iov; + mh.msg_iovlen = 1; + mh.msg_flags = 0; + mh.msg_control = control; + mh.msg_controllen = control->cmsg_len; + + /* do it */ + SAFE_SENDMSG(sizeof(MSG), fd, &mh, 0); + SAFE_CLOSE(tfd); + (void)SAFE_UNLINK(tmpfn); } -void do_child(void) +static void do_child(void) { struct sockaddr_in fsin; struct sockaddr_un fsun; fd_set afds, rfds; - int nfds, cc, fd; + int nfds, fd; FD_ZERO(&afds); FD_SET(sfd, &afds); @@ -455,19 +454,19 @@ void do_child(void) int newfd; fromlen = sizeof(fsin); - newfd = accept(sfd, (struct sockaddr *)&fsin, &fromlen); + newfd = SAFE_ACCEPT(sfd, (struct sockaddr *)&fsin, &fromlen); if (newfd >= 0) { FD_SET(newfd, &afds); nfds = MAX(nfds, newfd + 1); /* send something back */ - (void)write(newfd, "hoser\n", 6); + SAFE_SEND(1, newfd, "hi", 2, 0); } } if (FD_ISSET(ufd, &rfds)) { int newfd; fromlen = sizeof(fsun); - newfd = accept(ufd, (struct sockaddr *)&fsun, &fromlen); + newfd = SAFE_ACCEPT(ufd, (struct sockaddr *)&fsun, &fromlen); if (newfd >= 0) { FD_SET(newfd, &afds); nfds = MAX(nfds, newfd + 1); @@ -475,55 +474,22 @@ void do_child(void) } for (fd = 0; fd < nfds; ++fd) if (fd != sfd && fd != ufd && FD_ISSET(fd, &rfds)) { - char rbuf[1024]; + char rbuf[BUF_SIZE]; - cc = read(fd, rbuf, sizeof(rbuf)); - if (cc && rbuf[0] == 'R') + TEST(read(fd, rbuf, sizeof(rbuf))); + if (TST_RET > 0 && rbuf[0] == 'R') sender(fd); - if (cc == 0 || (cc < 0 && errno != EINTR)) { - (void)close(fd); + if (TST_RET == 0 || (TST_RET < 0 && TST_ERR != EINTR)) { + close(fd); FD_CLR(fd, &afds); } } } } -#define TM "from recvmsg01 server" - -/* special for rights-passing test */ -void sender(int fd) -{ - struct msghdr mh; - struct cmsghdr *control; - char tmpfn[1024], snd_cbuf[1024]; - int tfd; - - (void)strcpy(tmpfn, "smtXXXXXX"); - tfd = mkstemp(tmpfn); - if (tfd < 0) - return; - - memset(&mh, 0x00, sizeof(mh)); - - /* set up cmsghdr */ - control = (struct cmsghdr *)snd_cbuf; - memset(control, 0x00, sizeof(struct cmsghdr)); - control->cmsg_len = sizeof(struct cmsghdr) + 4; - control->cmsg_level = SOL_SOCKET; - control->cmsg_type = SCM_RIGHTS; - *(int *)CMSG_DATA(control) = tfd; - - /* set up msghdr */ - iov[0].iov_base = TM; - iov[0].iov_len = sizeof(TM); - mh.msg_iov = iov; - mh.msg_iovlen = 1; - mh.msg_flags = 0; - mh.msg_control = control; - mh.msg_controllen = control->cmsg_len; - - /* do it */ - (void)sendmsg(fd, &mh, 0); - (void)close(tfd); - (void)unlink(tmpfn); -} +static struct tst_test test = { + .test = run, + .tcnt = ARRAY_SIZE(tcases), + .forks_child = 1, + .needs_tmpdir = 1, +}; diff --git a/testcases/kernel/syscalls/sbrk/sbrk01.c b/testcases/kernel/syscalls/sbrk/sbrk01.c index ce26b1503..c99fb0106 100644 --- a/testcases/kernel/syscalls/sbrk/sbrk01.c +++ b/testcases/kernel/syscalls/sbrk/sbrk01.c @@ -1,111 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. - * AUTHOR : William Roske - * CO-PILOT : Dave Fenner - * - * 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. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * 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. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ - * - */ -/* - * DESCRIPTION - * 1.) test sbrk(8192) should return successfully. - * 2.) test sbrk(-8192) should return successfully. + * AUTHOR : William Roske, CO-PILOT : Dave Fenner + * Copyright (c) 2023 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> */ -#include <unistd.h> -#include <errno.h> -#include <string.h> -#include <signal.h> -#include <sys/types.h> - -#include "test.h" +/*\ + * [Description] + * + * Verify that sbrk() successfully increments or decrements the program's + * data break. + */ -char *TCID = "sbrk01"; +#include "tst_test.h" -static struct test_case_t { +static struct tcase { long increment; -} test_cases[] = { +} tcases[] = { + {0}, {8192}, - {-8192}, + {-8192} }; -static void setup(void); -static void sbrk_verify(const struct test_case_t *); -static void cleanup(void); - -int TST_TOTAL = ARRAY_SIZE(test_cases); - -int main(int ac, char **av) +static void run(unsigned int i) { - int lc; - int i; - - tst_parse_opts(ac, av, NULL, NULL); + struct tcase *tc = &tcases[i]; - setup(); + TESTPTR(sbrk(tc->increment)); - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - for (i = 0; i < TST_TOTAL; i++) - sbrk_verify(&test_cases[i]); - } - - cleanup(); - tst_exit(); - -} - -static void setup(void) -{ - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; + if (TST_RET_PTR == (void *) -1) + tst_res(TFAIL | TTERRNO, "sbrk(%ld) failed", tc->increment); + else + tst_res(TPASS, "sbrk(%ld) returned %p", tc->increment, TST_RET_PTR); } -static void sbrk_verify(const struct test_case_t *test) -{ - void *tret; - - tret = sbrk(test->increment); - TEST_ERRNO = errno; - - if (tret == (void *)-1) { - tst_resm(TFAIL | TTERRNO, "sbrk - Increase by %ld bytes failed", - test->increment); - } else { - tst_resm(TPASS, "sbrk - Increase by %ld bytes returned %p", - test->increment, tret); - } -} - -static void cleanup(void) -{ -} +static struct tst_test test = { + .test = run, + .tcnt = ARRAY_SIZE(tcases) +}; diff --git a/testcases/kernel/syscalls/sbrk/sbrk02.c b/testcases/kernel/syscalls/sbrk/sbrk02.c index 84744ef90..7fccc4d3a 100644 --- a/testcases/kernel/syscalls/sbrk/sbrk02.c +++ b/testcases/kernel/syscalls/sbrk/sbrk02.c @@ -1,101 +1,52 @@ +// SPDX-License-Identifier: GPL-2.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. + * Copyright (c) 2023 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> */ -/* - * DESCRIPTION - * Check sbrk() with error condition that should produce ENOMEM. - */ - -#include <errno.h> -#include <unistd.h> -#include "test.h" -#define INC 16*1024*1024 +/*\ + * [Description] + * + * Verify that sbrk() on failure sets errno to ENOMEM. + */ -char *TCID = "sbrk02"; -int TST_TOTAL = 1; -static void setup(void); -static void sbrk_verify(void); -static void cleanup(void); +#include "tst_test.h" +#define INC (16*1024*1024) static long increment = INC; -int main(int argc, char *argv[]) +static void run(void) { - int lc; - int i; - - tst_parse_opts(argc, argv, NULL, NULL); - - setup(); + TESTPTR(sbrk(increment)); - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - for (i = 0; i < TST_TOTAL; i++) - sbrk_verify(); + if (TST_RET_PTR != (void *)-1) { + tst_res(TFAIL, "sbrk(%ld) unexpectedly passed and returned %p, " + "expected (void *)-1 with errno=%d", + increment, TST_RET_PTR, ENOMEM); + return; } - cleanup(); - tst_exit(); + if (TST_ERR == ENOMEM) + tst_res(TPASS | TTERRNO, "sbrk(%ld) failed as expected", increment); + else + tst_res(TFAIL | TTERRNO, "sbrk(%ld) failed but unexpected errno, " + "expected errno=%d - %s", + increment, ENOMEM, strerror(ENOMEM)); } static void setup(void) { void *ret = NULL; - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - /* call sbrk until it fails or increment overflows */ while (ret != (void *)-1 && increment > 0) { ret = sbrk(increment); increment += INC; } - tst_resm(TINFO | TERRNO, "setup() bailing inc: %ld, ret: %p, sbrk: %p", - increment, ret, sbrk(0)); - - errno = 0; -} - -static void sbrk_verify(void) -{ - void *tret; - - tret = sbrk(increment); - TEST_ERRNO = errno; - - if (tret != (void *)-1) { - tst_resm(TFAIL, - "sbrk(%ld) returned %p, expected (void *)-1, errno=%d", - increment, tret, ENOMEM); - return; - } - - if (TEST_ERRNO == ENOMEM) { - tst_resm(TPASS | TTERRNO, "sbrk(%ld) failed as expected", - increment); - } else { - tst_resm(TFAIL | TTERRNO, - "sbrk(%ld) failed unexpectedly; expected: %d - %s", - increment, ENOMEM, strerror(ENOMEM)); - } } -static void cleanup(void) -{ -} +static struct tst_test test = { + .test_all = run, + .setup = setup +}; diff --git a/testcases/kernel/syscalls/sched_rr_get_interval/sched_rr_get_interval01.c b/testcases/kernel/syscalls/sched_rr_get_interval/sched_rr_get_interval01.c index 447242159..597de4665 100644 --- a/testcases/kernel/syscalls/sched_rr_get_interval/sched_rr_get_interval01.c +++ b/testcases/kernel/syscalls/sched_rr_get_interval/sched_rr_get_interval01.c @@ -69,7 +69,7 @@ static void run(void) } if (proc_flag) - TST_ASSERT_INT("/proc/sys/kernel/sched_rr_timeslice_ms", tst_ts_to_ms(tp)); + TST_ASSERT_INT(PROC_SCHED_RR_TIMESLICE_MS, tst_ts_to_ms(tp)); } static struct tst_test test = { @@ -79,6 +79,7 @@ static struct tst_test test = { .needs_root = 1, .tags = (const struct tst_tag[]) { {"linux-git", "975e155ed873"}, + {"linux-git", "c7fcb99877f9"}, {} } }; diff --git a/testcases/kernel/syscalls/sendfile/sendfile04.c b/testcases/kernel/syscalls/sendfile/sendfile04.c index 9a8ec08b9..4fa748137 100644 --- a/testcases/kernel/syscalls/sendfile/sendfile04.c +++ b/testcases/kernel/syscalls/sendfile/sendfile04.c @@ -14,6 +14,7 @@ * [Algorithm] * * Given wrong address or protected buffer as OFFSET argument to sendfile: + * * - a wrong address is created by munmap a buffer allocated by mmap * - a protected buffer is created by mmap with specifying protection */ diff --git a/testcases/kernel/syscalls/setgroups/.gitignore b/testcases/kernel/syscalls/setgroups/.gitignore index 0649a3425..9de928241 100644 --- a/testcases/kernel/syscalls/setgroups/.gitignore +++ b/testcases/kernel/syscalls/setgroups/.gitignore @@ -4,5 +4,3 @@ /setgroups02_16 /setgroups03 /setgroups03_16 -/setgroups04 -/setgroups04_16 diff --git a/testcases/kernel/syscalls/setgroups/setgroups01.c b/testcases/kernel/syscalls/setgroups/setgroups01.c index fed7f8e5a..9a5b77e93 100644 --- a/testcases/kernel/syscalls/setgroups/setgroups01.c +++ b/testcases/kernel/syscalls/setgroups/setgroups01.c @@ -1,202 +1,39 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) Linux Test Project, 2003-2023 * - * 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. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * 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. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ - * + * Author: William Roske + * CO-PILOT: Dave Fenner */ -/* $Id: setgroups01.c,v 1.7 2009/11/02 13:57:18 subrata_modak Exp $ */ -/********************************************************** - * - * OS Test - Silicon Graphics, Inc. - * - * TEST IDENTIFIER : setgroups01 - * - * EXECUTED BY : root - * - * TEST TITLE : Basic test for setgroups(2) - * - * PARENT DOCUMENT : usctpl01 - * - * TEST CASE TOTAL : 1 - * - * WALL CLOCK TIME : 1 - * - * CPU TYPES : ALL - * - * AUTHOR : William Roske - * - * CO-PILOT : Dave Fenner - * - * DATE STARTED : 03/30/92 - * - * INITIAL RELEASE : UNICOS 7.0 - * - * TEST CASES - * - * 1.) setgroups(2) returns...(See Description) - * - * INPUT SPECIFICATIONS - * The standard options for system call tests are accepted. - * (See the parse_opts(3) man page). - * - * OUTPUT SPECIFICATIONS - *$ - * DURATION - * Terminates - with frequency and infinite modes. - * - * SIGNALS - * Uses SIGUSR1 to pause before test if option set. - * (See the parse_opts(3) man page). - * - * RESOURCES - * None - * - * ENVIRONMENTAL NEEDS - * No run-time environmental needs. - * - * SPECIAL PROCEDURAL REQUIREMENTS - * None - * - * INTERCASE DEPENDENCIES - * None - * - * DETAILED DESCRIPTION - * This is a Phase I test for the setgroups(2) system call. It is intended - * to provide a limited exposure of the system call, for now. It - * should/will be extended when full functional tests are written for - * setgroups(2). - * - * Setup: - * Setup signal handling. - * Pause for SIGUSR1 if option specified. - * - * Test: - * Loop if the proper options are given. - * Execute system call - * Check return code, if system call failed (return=-1) - * Log the errno and Issue a FAIL message. - * Otherwise, Issue a PASS message. - * - * Cleanup: - * Print errno log and/or timing stats if options given - * - * - *#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#**/ - -#include <errno.h> -#include <string.h> -#include <signal.h> -#include <sys/param.h> -#include <unistd.h> -#include <grp.h> -#include "test.h" - -#include "compat_16.h" +/*\ + * [Description] + * + * Check the basic functionality of the setgroups() system call. + */ -void setup(); -void cleanup(); +#include "tst_test.h" +#include "compat_tst_16.h" -TCID_DEFINE(setgroups01); -int TST_TOTAL = 1; +static int len = NGROUPS; -int len = NGROUPS, ngrps = 0; -GID_T list[NGROUPS]; +static GID_T list[NGROUPS]; -int main(int ac, char **av) +static void verify_setgroups(void) { - int lc; - - /*************************************************************** - * parse standard options - ***************************************************************/ - tst_parse_opts(ac, av, NULL, NULL); - - /*************************************************************** - * perform global setup for test - ***************************************************************/ - setup(); - - /*************************************************************** - * check looping state if -c option given - ***************************************************************/ - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* - * Call setgroups(2) - */ - TEST(SETGROUPS(cleanup, ngrps, list)); - - /* check return code */ - if (TEST_RETURN == -1) { - tst_resm(TFAIL, - "setgroups(%d, list) Failed, errno=%d : %s", - len, TEST_ERRNO, strerror(TEST_ERRNO)); - } else { - tst_resm(TPASS, - "setgroups(%d, list) returned %ld", - len, TEST_RETURN); - } - - } - - cleanup(); - tst_exit(); + TST_EXP_POSITIVE(SETGROUPS(1, list), "setgroups()"); } -/*************************************************************** - * setup() - performs all ONE TIME setup for this test. - ***************************************************************/ -void setup(void) +static void setup(void) { - - tst_require_root(); - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - ngrps = GETGROUPS(cleanup, len, list); - if (ngrps == -1) { - tst_brkm(TBROK, cleanup, - "getgroups(%d, list) Failure. errno=%d : %s", - len, errno, strerror(errno)); - } + len = GETGROUPS(NGROUPS, list); + if (len < 0) + tst_brk(TBROK | TERRNO, "getgroups() Failed"); } -/*************************************************************** - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - ***************************************************************/ -void cleanup(void) -{ - -} +static struct tst_test test = { + .test_all = verify_setgroups, + .setup = setup, + .needs_root = 1, +}; diff --git a/testcases/kernel/syscalls/setgroups/setgroups02.c b/testcases/kernel/syscalls/setgroups/setgroups02.c index de23a4a7f..2b7f95c87 100644 --- a/testcases/kernel/syscalls/setgroups/setgroups02.c +++ b/testcases/kernel/syscalls/setgroups/setgroups02.c @@ -1,180 +1,43 @@ +// 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 + * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) Linux Test Project, 2003-2023 + * 07/2001 Ported by Wayne Boyer */ -/* - * Test Name: setgroups02 - * - * Test Description: - * Verify that, only root process can invoke setgroups() system call to - * set the supplementary group IDs of the process. - * - * Expected Result: - * The call succeeds in setting all the supplementary group IDs of the - * calling process. The new group should be set in the process supplemental - * group list. - * - * Algorithm: - * Setup: - * Setup signal handling. - * Pause for SIGUSR1 if option specified. - * - * Test: - * Loop if the proper options are given. - * Execute system call - * Check return code, if system call failed (return=-1) - * Log the errno and Issue a FAIL message. - * Otherwise, - * Verify the Functionality of system call - * if successful, - * Issue Functionality-Pass message. - * Otherwise, - * Issue Functionality-Fail message. - * Cleanup: - * Print errno log and/or timing stats if options given - * - * Usage: <for command-line> - * setgroups02 [-c n] [-f] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -f : Turn off functionality Testing. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 07/2001 Ported by Wayne Boyer - * - * RESTRICTIONS: - * This test should be run by 'super-user' (root) only. +/*\ + * [Description] * + * Check that root process can setgroups() supplementary group ID and verify + * that getgroups() returns the previously set ID. */ -#include <sys/types.h> -#include <unistd.h> -#include <errno.h> -#include <pwd.h> -#include <grp.h> -#include <sys/param.h> - -#include "test.h" - -#include "compat_16.h" -#define TESTUSER "nobody" - -TCID_DEFINE(setgroups02); -int TST_TOTAL = 1; /* Total number of test conditions */ -GID_T groups_list[NGROUPS]; /* Array to hold gids for getgroups() */ - -struct passwd *user_info; /* struct. to hold test user info */ -void setup(); /* setup function for the test */ -void cleanup(); /* cleanup function for the test */ - -int main(int ac, char **av) -{ - int lc, i; - int gidsetsize = 1; /* only one GID, the GID of TESTUSER */ - int PASS_FLAG = 0; /* used for checking group array */ - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* - * Call setgroups() to set supplimentary group IDs of - * the calling super-user process to gid of TESTUSER. - */ - TEST(SETGROUPS(cleanup, gidsetsize, groups_list)); - - if (TEST_RETURN == -1) { - tst_resm(TFAIL, "setgroups(%d, groups_list) Failed, " - "errno=%d : %s", gidsetsize, TEST_ERRNO, - strerror(TEST_ERRNO)); - continue; - } +#include <pwd.h> - /* - * Call getgroups(2) to verify that - * setgroups(2) successfully set the - * supp. gids of TESTUSER. - */ - groups_list[0] = '\0'; - if (GETGROUPS(cleanup, gidsetsize, groups_list) < 0) { - tst_brkm(TFAIL, cleanup, "getgroups() Fails, " - "error=%d", errno); - } - for (i = 0; i < NGROUPS; i++) { - if (groups_list[i] == user_info->pw_gid) { - tst_resm(TPASS, - "Functionality of setgroups" - "(%d, groups_list) successful", - gidsetsize); - PASS_FLAG = 1; - } - } - if (PASS_FLAG == 0) { - tst_resm(TFAIL, "Supplimentary gid %d not set " - "for the process", user_info->pw_gid); - } - } +#include "tst_test.h" +#include "compat_tst_16.h" - cleanup(); - tst_exit(); -} +static GID_T *groups_get, *groups_set; -/* - * setup() - performs all ONE TIME setup for this test. - * - * Make sure the test process uid is root. - * Get the supplimentrary group id of test user from /etc/passwd file. - */ -void setup(void) +static void verify_setgroups(void) { + groups_set[0] = 42; - tst_require_root(); - - tst_sig(NOFORK, DEF_HANDLER, cleanup); + TST_EXP_PASS(SETGROUPS(1, groups_set)); - TEST_PAUSE; + TST_EXP_VAL(GETGROUPS(1, groups_get), 1); - /* Get the group id info. of TESTUSER from /etc/passwd */ - if ((user_info = getpwnam(TESTUSER)) == NULL) { - tst_brkm(TFAIL, cleanup, "getpwnam(2) of %s Failed", TESTUSER); - } + TST_EXP_EQ_LI(groups_get[0], groups_set[0]); - if (!GID_SIZE_CHECK(user_info->pw_gid)) { - tst_brkm(TBROK, - cleanup, - "gid returned from getpwnam is too large for testing setgroups16"); - } - - groups_list[0] = user_info->pw_gid; + groups_get[0] = 0; } -/* - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - */ -void cleanup(void) -{ - -} +static struct tst_test test = { + .test_all = verify_setgroups, + .bufs = (struct tst_buffers []) { + {&groups_get, .size = sizeof(GID_T)}, + {&groups_set, .size = sizeof(GID_T)}, + {}, + }, + .needs_root = 1, +}; diff --git a/testcases/kernel/syscalls/setgroups/setgroups03.c b/testcases/kernel/syscalls/setgroups/setgroups03.c index 490b06996..fbf8de0bb 100644 --- a/testcases/kernel/syscalls/setgroups/setgroups03.c +++ b/testcases/kernel/syscalls/setgroups/setgroups03.c @@ -1,222 +1,75 @@ +// 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 + * Copyright (C) Bull S.A. 2001 + * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) Linux Test Project, 2003-2023 + * 07/2001 Ported by Wayne Boyer + * 05/2002 Ported by Andre Merlier */ -/* - * Test Name: setgroups03 - * - * Test Description: - * Verify that, - * 1. setgroups() fails with -1 and sets errno to EINVAL if the size - * argument value is > NGROUPS - * 2. setgroups() fails with -1 and sets errno to EPERM if the - * calling process is not super-user. +/*\ + * [Description] * - * Expected Result: - * setgroups() should fail with return value -1 and set expected errno. + * Test for EINVAL, EPERM, EFAULT errors. * - * Algorithm: - * Setup: - * Setup signal handling. - * Pause for SIGUSR1 if option specified. + * - setgroups() fails with EINVAL if the size argument value is > NGROUPS. * - * Test: - * Loop if the proper options are given. - * Execute system call - * Check return code, if system call failed (return=-1) - * if errno set == expected errno - * Issue sys call fails with expected return value and errno. - * Otherwise, - * Issue sys call fails with unexpected errno. - * Otherwise, - * Issue sys call returns unexpected value. - * - * Cleanup: - * Print errno log and/or timing stats if options given - * - * Usage: <for command-line> - * setgroups03 [-c n] [-e] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -f : Turn off functionality Testing. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 07/2001 Ported by Wayne Boyer - * - * RESTRICTIONS: - * This test should be executed by 'non-super-user' only. + * - setgroups() fails with EPERM if the calling process is not super-user. * + * - setgroups() fails with EFAULT if the list has an invalid address. */ -#include <limits.h> -#include <sys/types.h> -#include <unistd.h> -#include <errno.h> -#include <pwd.h> -#include <grp.h> -#include "test.h" +#include <pwd.h> +#include <stdlib.h> -#include "compat_16.h" +#include "tst_test.h" +#include "compat_tst_16.h" #define TESTUSER "nobody" -char nobody_uid[] = "nobody"; -struct passwd *ltpuser; +static GID_T *glist1, *glist2, *glist3; +static struct passwd *user_info; -TCID_DEFINE(setgroups03); -int TST_TOTAL = 2; - -GID_T *groups_list; /* Array to hold gids for getgroups() */ - -int setup1(); /* setup function to test error EPERM */ -void setup(); /* setup function for the test */ -void cleanup(); /* cleanup function for the test */ - -struct test_case_t { /* test case struct. to hold ref. test cond's */ - size_t gsize_add; - int list; - char *desc; +static struct tcase { + int gsize; + GID_T **glist; int exp_errno; - int (*setupfunc) (); -} Test_cases[] = { - { - 1, 1, "Size is > sysconf(_SC_NGROUPS_MAX)", EINVAL, NULL}, { - 0, 2, "Permission denied, not super-user", EPERM, setup1} +} tcases[] = { + {NGROUPS + 1, &glist1, EINVAL}, + {1, &glist2, EPERM}, + {NGROUPS, &glist3, EFAULT}, }; -int main(int ac, char **av) -{ - int lc; - int gidsetsize; /* total no. of groups */ - int i; - char *test_desc; /* test specific error message */ - int ngroups_max = sysconf(_SC_NGROUPS_MAX); /* max no. of groups in the current system */ - - tst_parse_opts(ac, av, NULL, NULL); - - groups_list = malloc(ngroups_max * sizeof(GID_T)); - if (groups_list == NULL) { - tst_brkm(TBROK, NULL, "malloc failed to alloc %zu errno " - " %d ", ngroups_max * sizeof(GID_T), errno); - } - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - for (i = 0; i < TST_TOTAL; i++) { - if (Test_cases[i].setupfunc != NULL) { - Test_cases[i].setupfunc(); - } - - gidsetsize = ngroups_max + Test_cases[i].gsize_add; - test_desc = Test_cases[i].desc; - - /* - * Call setgroups() to test different test conditions - * verify that it fails with -1 return value and - * sets appropriate errno. - */ - TEST(SETGROUPS(cleanup, gidsetsize, groups_list)); - - if (TEST_RETURN != -1) { - tst_resm(TFAIL, "setgroups(%d) returned %ld, " - "expected -1, errno=%d", gidsetsize, - TEST_RETURN, Test_cases[i].exp_errno); - continue; - } - - if (TEST_ERRNO == Test_cases[i].exp_errno) { - tst_resm(TPASS, - "setgroups(%d) fails, %s, errno=%d", - gidsetsize, test_desc, TEST_ERRNO); - } else { - tst_resm(TFAIL, "setgroups(%d) fails, %s, " - "errno=%d, expected errno=%d", - gidsetsize, test_desc, TEST_ERRNO, - Test_cases[i].exp_errno); - } - } - - } - - cleanup(); - - tst_exit(); -} - -/* - * setup() - performs all ONE TIME setup for this test. - * - * Call individual test specific setup functions. - */ -void setup(void) +static void verify_setgroups(unsigned int i) { - tst_require_root(); + struct tcase *tc = &tcases[i]; - tst_sig(NOFORK, DEF_HANDLER, cleanup); + if (tc->exp_errno == EPERM) + SAFE_SETEUID(user_info->pw_uid); - TEST_PAUSE; + TST_EXP_FAIL(SETGROUPS(tc->gsize, *tc->glist), tc->exp_errno, + "setgroups(%d, groups_list)", tc->gsize); + if (tc->exp_errno == EPERM) + SAFE_SETEUID(0); } -/* - * setup1 - Setup function to test setgroups() which returns -1 - * and sets errno to EPERM. - * - * Get the user info. from /etc/passwd file. - * This function returns 0 on success. - */ -int setup1(void) +static void setup(void) { - struct passwd *user_info; /* struct. to hold test user info */ - -/* Switch to nobody user for correct error code collection */ - ltpuser = getpwnam(nobody_uid); - if (seteuid(ltpuser->pw_uid) == -1) { - tst_resm(TINFO, "setreuid failed to " - "to set the effective uid to %d", ltpuser->pw_uid); - perror("setreuid"); - } - - if ((user_info = getpwnam(TESTUSER)) == NULL) { - tst_brkm(TFAIL, cleanup, "getpwnam(2) of %s Failed", TESTUSER); - } - - if (!GID_SIZE_CHECK(user_info->pw_gid)) { - tst_brkm(TBROK, - cleanup, - "gid returned from getpwnam is too large for testing setgroups16"); - } - groups_list[0] = user_info->pw_gid; - return 0; + user_info = SAFE_GETPWNAM(TESTUSER); + glist2[0] = 42; + glist3 = tst_get_bad_addr(NULL); } -/* - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - */ -void cleanup(void) -{ - -} +static struct tst_test test = { + .test = verify_setgroups, + .tcnt = ARRAY_SIZE(tcases), + .bufs = (struct tst_buffers []) { + {&glist1, .size = sizeof(GID_T) * (NGROUPS + 1)}, + {&glist2, .size = sizeof(GID_T)}, + {&user_info, .size = sizeof(struct passwd)}, + {}, + }, + .setup = setup, + .needs_root = 1, +}; diff --git a/testcases/kernel/syscalls/setgroups/setgroups04.c b/testcases/kernel/syscalls/setgroups/setgroups04.c deleted file mode 100644 index 971c86bd2..000000000 --- a/testcases/kernel/syscalls/setgroups/setgroups04.c +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (C) Bull S.A. 2001 - * 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: setgroups04 - * - * Test Description: - * Verify that, setgroups() fails with -1 and sets errno to EFAULT if the list has an invalid address. - * - * Expected Result: - * setgroups() should fail with return value -1 and set expected errno. - * - * Algorithm: - * Setup: - * Setup signal handling. - * Pause for SIGUSR1 if option specified. - * - * Test: - * Loop if the proper options are given. - * Execute system call - * Check return code, if system call failed (return=-1) - * if errno set == expected errno - * Issue sys call fails with expected return value and errno. - * Otherwise, - * Issue sys call fails with unexpected errno. - * Otherwise, - * Issue sys call returns unexpected value. - * - * Cleanup: - * Print errno log and/or timing stats if options given - * - * Usage: <for command-line> - * setgroups04 [-c n] [-e] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -f : Turn off functionality Testing. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 05/2002 Ported by André Merlier - * - * RESTRICTIONS: - * none. - * - */ -#include <sys/types.h> -#include <sys/param.h> -#include <unistd.h> -#include <errno.h> -#include <pwd.h> -#include <grp.h> - -#include "test.h" - -#include "compat_16.h" - -TCID_DEFINE(setgroups04); -int TST_TOTAL = 1; - -GID_T groups_list[NGROUPS]; - -void setup(); /* setup function for the test */ -void cleanup(); /* cleanup function for the test */ - -#if !defined(UCLINUX) - -int main(int ac, char **av) -{ - int lc; - int gidsetsize; /* total no. of groups */ - char *test_desc; /* test specific error message */ - - tst_parse_opts(ac, av, NULL, NULL); - - /* Perform setup for test */ - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - gidsetsize = NGROUPS; - test_desc = "EFAULT"; - - /* - * Call setgroups() to test condition - * verify that it fails with -1 return value and - * sets appropriate errno. - */ - TEST(SETGROUPS(cleanup, gidsetsize, sbrk(0))); - - if (TEST_RETURN != -1) { - tst_resm(TFAIL, "setgroups() returned %ld, " - "expected -1, errno=%d", TEST_RETURN, - EFAULT); - } else { - - if (TEST_ERRNO == EFAULT) { - tst_resm(TPASS, - "setgroups() fails with expected " - "error EFAULT errno:%d", TEST_ERRNO); - } else { - tst_resm(TFAIL, "setgroups() fails, %s, " - "errno=%d, expected errno=%d", - test_desc, TEST_ERRNO, EFAULT); - } - } - - } - - cleanup(); - tst_exit(); - -} - -#else - -int main(void) -{ - tst_resm(TINFO, "test is not available on uClinux"); - tst_exit(); -} - -#endif /* if !defined(UCLINUX) */ - -/* - * setup() - */ -void setup(void) -{ - tst_require_root(); - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - -} - -/* - * cleanup() - */ -void cleanup(void) -{ - -} diff --git a/testcases/kernel/syscalls/setpgid/setpgid02.c b/testcases/kernel/syscalls/setpgid/setpgid02.c index 4b63afee8..b380d7df4 100644 --- a/testcases/kernel/syscalls/setpgid/setpgid02.c +++ b/testcases/kernel/syscalls/setpgid/setpgid02.c @@ -13,15 +13,15 @@ * - EINVAL when given pgid is less than 0. * - ESRCH when pid is not the calling process and not a child of * the calling process. - * - EPERM when an attempt was made to move a process into a process - * group in a different session. + * - EPERM when an attempt was made to move a process into a nonexisting + * process group. */ #include <errno.h> #include <unistd.h> #include "tst_test.h" -static pid_t pgid, pid, ppid, init_pgid; +static pid_t pgid, pid, ppid, inval_pgid; static pid_t negative_pid = -1; static struct tcase { @@ -31,7 +31,7 @@ static struct tcase { } tcases[] = { {&pid, &negative_pid, EINVAL}, {&ppid, &pgid, ESRCH}, - {&pid, &init_pgid, EPERM} + {&pid, &inval_pgid, EPERM} }; static void setup(void) @@ -41,10 +41,10 @@ static void setup(void) pgid = getpgrp(); /* - * Getting pgid of init/systemd process to use it as a - * process group from a different session for EPERM test + * pid_max would not be in use by another process and guarantees that + * it corresponds to an invalid PGID, generating EPERM. */ - init_pgid = SAFE_GETPGID(1); + SAFE_FILE_SCANF("/proc/sys/kernel/pid_max", "%d\n", &inval_pgid); } static void run(unsigned int n) diff --git a/testcases/kernel/syscalls/setpgid/setpgid03.c b/testcases/kernel/syscalls/setpgid/setpgid03.c index 79ca23e08..9ce2603d8 100644 --- a/testcases/kernel/syscalls/setpgid/setpgid03.c +++ b/testcases/kernel/syscalls/setpgid/setpgid03.c @@ -9,7 +9,9 @@ /*\ * [Description] * - * Tests setpgid() erorrs: + * Tests setpgid(2) errors: + * + * - EPERM The process specified by pid must not be a session leader. * * - EPERM The calling process, process specified by pid and the target * process group must be in the same session. @@ -43,6 +45,8 @@ static void run(void) TST_CHECKPOINT_WAIT(0); TST_EXP_FAIL(setpgid(child_pid, getppid()), EPERM); + /* Child did setsid(), so its PGID is set to its PID. */ + TST_EXP_FAIL(setpgid(0, child_pid), EPERM); TST_CHECKPOINT_WAKE(0); diff --git a/testcases/kernel/syscalls/setreuid/setreuid04.c b/testcases/kernel/syscalls/setreuid/setreuid04.c index 8eed90df0..06ffa32b0 100644 --- a/testcases/kernel/syscalls/setreuid/setreuid04.c +++ b/testcases/kernel/syscalls/setreuid/setreuid04.c @@ -1,141 +1,49 @@ +// 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 - * * Ported by John George + * Copyright (c) 2022 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> */ -/* - * Test that root can change the real and effective uid to an - * unpriviledged user. +/*\ + * [Description] + * + * Verify that root user can change the real and effective uid to an + * unprivileged user. */ -#include <errno.h> -#include <stdlib.h> #include <pwd.h> -#include <sys/wait.h> - -#include "test.h" -#include "compat_16.h" - -TCID_DEFINE(setreuid04); - -static uid_t neg_one = -1; - -static struct passwd nobody, root; - -/* - * The following structure contains all test data. Each structure in the array - * is used for a separate test. The tests are executed in the for loop below. - */ - -struct test_data_t { - uid_t *real_uid; - uid_t *eff_uid; - struct passwd *exp_real_usr; - struct passwd *exp_eff_usr; - char *test_msg; -} test_data[] = { - { - &neg_one, &neg_one, &root, &root, "After setreuid(-1, nobody),"}, { -&nobody.pw_uid, &nobody.pw_uid, &nobody, &nobody, - "After setreuid(-1, -1),"},}; - -int TST_TOTAL = ARRAY_SIZE(test_data); - -static void setup(void); -static void cleanup(void); -static void uid_verify(struct passwd *, struct passwd *, char *); - -int main(int ac, char **av) -{ - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - int i, pid; - - tst_count = 0; +#include "tst_test.h" +#include "compat_tst_16.h" - if ((pid = FORK_OR_VFORK()) == -1) { - tst_brkm(TBROK, cleanup, "fork failed"); - } else if (pid == 0) { /* child */ - - for (i = 0; i < TST_TOTAL; i++) { - - /* Set the real or effective user id */ - TEST(SETREUID(cleanup, *test_data[i].real_uid, - *test_data[i].eff_uid)); - - if (TEST_RETURN != -1) { - tst_resm(TPASS, "setreuid(%d, %d) " - "succeeded as expected.", - *test_data[i].real_uid, - *test_data[i].eff_uid); - } else { - tst_resm(TFAIL, "setreuid(%d, %d) " - "did not return as expected.", - *test_data[i].real_uid, - *test_data[i].eff_uid); - } - - uid_verify(test_data[i].exp_real_usr, - test_data[i].exp_eff_usr, - test_data[i].test_msg); - } - tst_exit(); - } else { /* parent */ - tst_record_childstatus(cleanup, pid); - } - } - cleanup(); - tst_exit(); -} +static uid_t root_uid, nobody_uid; static void setup(void) { - tst_require_root(); - - tst_sig(FORK, DEF_HANDLER, cleanup); - - if (getpwnam("nobody") == NULL) - tst_brkm(TBROK, NULL, "nobody must be a valid user."); + struct passwd *nobody; - root = *(getpwnam("root")); - UID16_CHECK(root.pw_uid, setreuid, cleanup); + root_uid = getuid(); + nobody = SAFE_GETPWNAM("nobody"); + nobody_uid = nobody->pw_uid; - nobody = *(getpwnam("nobody")); - UID16_CHECK(nobody.pw_uid, setreuid, cleanup); - - TEST_PAUSE; + UID16_CHECK(nobody_uid, setreuid); + UID16_CHECK(root_uid, setreuid); } -static void cleanup(void) +static void run(void) { -} + if (!SAFE_FORK()) { + TST_EXP_PASS(SETREUID(nobody_uid, nobody_uid)); -static void uid_verify(struct passwd *ru, struct passwd *eu, char *when) -{ - if ((getuid() != ru->pw_uid) || (geteuid() != eu->pw_uid)) { - tst_resm(TFAIL, "ERROR: %s real uid = %d; effective uid = %d", - when, getuid(), geteuid()); - tst_resm(TINFO, "Expected: real uid = %d; effective uid = %d", - ru->pw_uid, eu->pw_uid); + TST_EXP_EQ_LI(GETUID(), nobody_uid); + TST_EXP_EQ_LI(GETEUID(), nobody_uid); } + tst_reap_children(); } + +static struct tst_test test = { + .setup = setup, + .test_all = run, + .needs_root = 1, + .forks_child = 1 +}; diff --git a/testcases/kernel/syscalls/setreuid/setreuid07.c b/testcases/kernel/syscalls/setreuid/setreuid07.c index ff222cd00..5faf3cb7f 100644 --- a/testcases/kernel/syscalls/setreuid/setreuid07.c +++ b/testcases/kernel/syscalls/setreuid/setreuid07.c @@ -1,192 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0-later /* * Copyright (c) Kerlabs 2008. * Copyright (c) International Business Machines Corp., 2008 - * - * 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 - * * Created by Renaud Lottiaux + * Copyright (c) 2023 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> */ -/* +/*\ + * [Description] + * * Check if setreuid behaves correctly with file permissions. * The test creates a file as ROOT with permissions 0644, does a setreuid * and then tries to open the file with RDWR permissions. * The same test is done in a fork to check if new UIDs are correctly - * passed to the son. + * passed to the child process. */ -#include <errno.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/wait.h> -#include <fcntl.h> -#include <unistd.h> #include <pwd.h> +#include <stdlib.h> -#include "test.h" -#include "safe_macros.h" -#include "compat_16.h" +#include "tst_test.h" +#include "compat_tst_16.h" -TCID_DEFINE(setreuid07); -int TST_TOTAL = 1; +#define TEMPFILE "testfile" -static char testfile[256] = ""; static struct passwd *ltpuser; -static int fd = -1; - -static void setup(void); -static void cleanup(void); -static void do_master_child(void); - -int main(int ac, char **av) +static void setup(void) { - pid_t pid; + int fd; - tst_parse_opts(ac, av, NULL, NULL); + ltpuser = SAFE_GETPWNAM("nobody"); - setup(); - - pid = FORK_OR_VFORK(); - if (pid < 0) - tst_brkm(TBROK, cleanup, "Fork failed"); - - if (pid == 0) - do_master_child(); - - tst_record_childstatus(cleanup, pid); - - cleanup(); - tst_exit(); + UID16_CHECK(ltpuser->pw_uid, setreuid); + fd = SAFE_OPEN(TEMPFILE, O_CREAT | O_RDWR, 0644); + SAFE_CLOSE(fd); } -static void do_master_child(void) +static void run(void) { - int lc; - int pid; - int status; - - for (lc = 0; TEST_LOOPING(lc); lc++) { - int tst_fd; - - tst_count = 0; - - if (SETREUID(NULL, 0, ltpuser->pw_uid) == -1) { - perror("setreuid failed"); - exit(TFAIL); - } - - /* Test 1: Check the process with new uid cannot open the file - * with RDWR permissions. - */ - TEST(tst_fd = open(testfile, O_RDWR)); - - if (TEST_RETURN != -1) { - printf("open succeeded unexpectedly\n"); - close(tst_fd); - exit(TFAIL); - } - - if (TEST_ERRNO == EACCES) { - printf("open failed with EACCES as expected\n"); - } else { - perror("open failed unexpectedly"); - exit(TFAIL); - } - - /* Test 2: Check a son process cannot open the file - * with RDWR permissions. - */ - pid = FORK_OR_VFORK(); - if (pid < 0) - tst_brkm(TBROK, cleanup, "Fork failed"); - - if (pid == 0) { - int tst_fd2; - - /* Test to open the file in son process */ - TEST(tst_fd2 = open(testfile, O_RDWR)); - - if (TEST_RETURN != -1) { - printf("call succeeded unexpectedly\n"); - close(tst_fd2); - exit(TFAIL); - } - - if (TEST_ERRNO == EACCES) { - printf("open failed with EACCES as expected\n"); - exit(TPASS); - } else { - printf("open failed unexpectedly\n"); - exit(TFAIL); - } - } else { - /* Wait for son completion */ - if (waitpid(pid, &status, 0) == -1) { - perror("waitpid failed"); - exit(TFAIL); - } - if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) - exit(WEXITSTATUS(status)); - } - - /* Test 3: Fallback to initial uid and check we can again open - * the file with RDWR permissions. - */ - tst_count++; - if (SETREUID(NULL, 0, 0) == -1) { - perror("setreuid failed"); - exit(TFAIL); - } + pid_t pid; - TEST(tst_fd = open(testfile, O_RDWR)); + TST_EXP_PASS_SILENT(SETREUID(-1, ltpuser->pw_uid)); + TST_EXP_FAIL2(open(TEMPFILE, O_RDWR), EACCES); - if (TEST_RETURN == -1) { - perror("open failed unexpectedly"); - exit(TFAIL); - } else { - printf("open call succeeded\n"); - close(tst_fd); - } + pid = SAFE_FORK(); + if (pid == 0) { + TST_EXP_FAIL2(open(TEMPFILE, O_RDWR), EACCES); + exit(0); } - exit(TPASS); -} + tst_reap_children(); -static void setup(void) -{ - tst_require_root(); - - ltpuser = getpwnam("nobody"); - if (ltpuser == NULL) - tst_brkm(TBROK, NULL, "nobody must be a valid user."); - - tst_tmpdir(); - - sprintf(testfile, "setreuid07file%d.tst", getpid()); - - /* Create test file */ - fd = SAFE_OPEN(cleanup, testfile, O_CREAT | O_RDWR, 0644); - - tst_sig(FORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; + TST_EXP_PASS_SILENT(SETREUID(-1, 0)); + TST_EXP_FD(open(TEMPFILE, O_RDWR)); + SAFE_CLOSE(TST_RET); } -static void cleanup(void) -{ - close(fd); - - tst_rmdir(); -} +static struct tst_test test = { + .setup = setup, + .test_all = run, + .needs_root = 1, + .forks_child = 1 +}; diff --git a/testcases/kernel/syscalls/setsockopt/setsockopt02.c b/testcases/kernel/syscalls/setsockopt/setsockopt02.c index e7621538b..3349c9970 100644 --- a/testcases/kernel/syscalls/setsockopt/setsockopt02.c +++ b/testcases/kernel/syscalls/setsockopt/setsockopt02.c @@ -96,4 +96,8 @@ static struct tst_test test = { .needs_root = 1, .setup = setup, .cleanup = cleanup, + .tags = (const struct tst_tag[]) { + {"CVE", "2017-7308"}, + {} + } }; diff --git a/testcases/kernel/syscalls/setsockopt/setsockopt08.c b/testcases/kernel/syscalls/setsockopt/setsockopt08.c index 5fc1a8b8e..7f8243de1 100644 --- a/testcases/kernel/syscalls/setsockopt/setsockopt08.c +++ b/testcases/kernel/syscalls/setsockopt/setsockopt08.c @@ -26,57 +26,63 @@ * ->targetsize: if OTOH the user specified ->u.user.target_size is * too small, then the memset() destination address calculated by * adding ->targetsize to the payload start will not point at, but - * into or even past the padding. For the table's last entry's target - * record, this will result in an out-of-bounds write past the - * destination buffer allocated for the converted table. The code - * below will create a (compat) table such that the converted table's - * calculated size will fit exactly into a slab size of 1024 bytes and - * that the memset() in xt_compat_target_from_user() will write past - * this slab. + * into or even past the padding. + * + * For the table's last entry's target record, this will result in an + * out-of-bounds write past the destination buffer allocated for the converted + * table. The code below will create a (compat) table such that the converted + * table's calculated size will fit exactly into a slab size of 1024 bytes and + * that the memset() in xt_compat_target_from_user() will write past this slab. * * The table will consist of - * - the mandatory struct compat_ipt_replace header, - * - a single entry consisting of - * - the mandatory compat_ipt_entry header - * - a single 'state' match entry of appropriate size for + * + * * the mandatory struct compat_ipt_replace header, + * * a single entry consisting of + * ** the mandatory compat_ipt_entry header + * ** a single 'state' match entry of appropriate size for * controlling the out-of-bounds write when converting * the target entry following next, - * - a single 'REJECT' target entry. + * ** a single 'REJECT' target entry. + * * The kernel will transform this into a buffer containing (in * this order) - * - a xt_table_info - * - a single entry consisting of - * - its ipt_entry header - * - a single 'state' match entry - * - followed by a single 'REJECT' target entry. + * + * * a xt_table_info + * * a single entry consisting of + * ** its ipt_entry header + * ** a single 'state' match entry + * ** followed by a single 'REJECT' target entry. * * The expected sizes for the 'state' match entries as well as the * 'REJECT' target are the size of the base header struct (32 bytes) - * plus the size of an unsigned int (4 bytes) each. In the course of - * the compat => non-compat conversion, the kernel will insert four - * bytes of padding after the unsigned int payload (c.f. 'off' - * adjustments via xt_compat_match_offset() and - * xt_compat_target_offset() in xt_compat_match_from_user() and - * xt_compat_target_from_user() resp.). This code is based on the - * premise that the user sets the given ->u.user.match_size or - * ->u.user.target_size consistent to the COMPAT_XT_ALIGN()ed payload - * size as specified by the corresponding xt_match instance's - * ->matchsize or xt_target instance's ->targetsize. That is, the - * padding gets inserted unconditionally during the transformation, + * plus the size of an unsigned int (4 bytes) each. + * + * In the course of the compat => non-compat conversion, the kernel will insert + * four bytes of padding after the unsigned int payload (c.f. 'off' adjustments + * via xt_compat_match_offset() and xt_compat_target_offset() in + * xt_compat_match_from_user() and xt_compat_target_from_user() resp.). + * + * This code is based on the premise that the user sets the given + * ->u.user.match_size or ->u.user.target_size consistent to the + * COMPAT_XT_ALIGN()ed payload size as specified by the corresponding xt_match + * instance's ->matchsize or xt_target instance's ->targetsize. + * + * That is, the padding gets inserted unconditionally during the transformation, * independent of the actual values of ->u.user.match_size or - * ->u.user.target_size and the result ends up getting layed out with - * proper alignment only if said values match the expectations. That's - * not a problem in itself, but this unconditional insertion of - * padding must be taken into account in the match_size calculation - * below. + * ->u.user.target_size and the result ends up getting layed out with proper + * alignment only if said values match the expectations. + * + * That's not a problem in itself, but this unconditional insertion of padding + * must be taken into account in the match_size calculation below. * * For the match_size calculation below, note that the chosen * target slab size is 1024 and that - * - sizeof(xt_table_info) = 64 - * - sizeof(ipt_entry) = 112 - * - the kernel will insert four bytes of padding + * + * * sizeof(xt_table_info) = 64 + * * sizeof(ipt_entry) = 112 + * * the kernel will insert four bytes of padding * after the match and target entries each. - * - sizeof(struct xt_entry_target) = 32 + * * sizeof(struct xt_entry_target) = 32 */ #include <netinet/in.h> diff --git a/testcases/kernel/syscalls/sockioctl/sockioctl01.c b/testcases/kernel/syscalls/sockioctl/sockioctl01.c index 51dac9c16..ff3738f32 100644 --- a/testcases/kernel/syscalls/sockioctl/sockioctl01.c +++ b/testcases/kernel/syscalls/sockioctl/sockioctl01.c @@ -52,7 +52,7 @@ static struct ifreq ifr; static int sinlen; static int optval; -static char buf[8192]; +static struct ifreq buf[200]; static void setup(void); static void setup0(void); @@ -218,7 +218,7 @@ static void setup2(void) s = SAFE_SOCKET(cleanup, tdat[testno].domain, tdat[testno].type, tdat[testno].proto); ifc.ifc_len = sizeof(buf); - ifc.ifc_buf = buf; + ifc.ifc_buf = (char *)buf; } static void setup3(void) diff --git a/testcases/kernel/syscalls/stat/stat01.c b/testcases/kernel/syscalls/stat/stat01.c index e0dbfbf2f..365cdac8a 100644 --- a/testcases/kernel/syscalls/stat/stat01.c +++ b/testcases/kernel/syscalls/stat/stat01.c @@ -8,9 +8,9 @@ /*\ * [Description] * - * Verify that, stat(2) succeeds to get the status of a file and fills the - * stat structure elements regardless of whether process has or doesn't - * have read access to the file. + * Verify that, stat(2) succeeds to get the status of a file and fills the + * stat structure elements regardless of whether process has or doesn't + * have read access to the file. */ #include <pwd.h> diff --git a/testcases/kernel/syscalls/statvfs/statvfs02.c b/testcases/kernel/syscalls/statvfs/statvfs02.c index 8aaa47318..6f36530bf 100644 --- a/testcases/kernel/syscalls/statvfs/statvfs02.c +++ b/testcases/kernel/syscalls/statvfs/statvfs02.c @@ -10,6 +10,7 @@ * [Description] * * Verify that statvfs() fails with: + * * - EFAULT when path points to an invalid address. * - ELOOP when too many symbolic links were encountered in translating path. * - ENAMETOOLONG when path is too long. diff --git a/testcases/kernel/syscalls/statx/.gitignore b/testcases/kernel/syscalls/statx/.gitignore index 1cea43c0d..f6a423eed 100644 --- a/testcases/kernel/syscalls/statx/.gitignore +++ b/testcases/kernel/syscalls/statx/.gitignore @@ -7,3 +7,6 @@ /statx07 /statx08 /statx09 +/statx10 +/statx11 +/statx12 diff --git a/testcases/kernel/syscalls/statx/statx01.c b/testcases/kernel/syscalls/statx/statx01.c index 68f56549f..f9c2748d2 100644 --- a/testcases/kernel/syscalls/statx/statx01.c +++ b/testcases/kernel/syscalls/statx/statx01.c @@ -33,6 +33,7 @@ #include "tst_test.h" #include "tst_safe_macros.h" #include "lapi/stat.h" +#include "lapi/fcntl.h" #include "tst_safe_stdio.h" #include <string.h> #include <inttypes.h> diff --git a/testcases/kernel/syscalls/statx/statx02.c b/testcases/kernel/syscalls/statx/statx02.c index a8e868d7a..5ed80894d 100644 --- a/testcases/kernel/syscalls/statx/statx02.c +++ b/testcases/kernel/syscalls/statx/statx02.c @@ -28,6 +28,7 @@ #include "tst_test.h" #include "tst_safe_macros.h" #include "lapi/stat.h" +#include "lapi/fcntl.h" #define TESTFILE "test_temp" #define LINK_FILE "test_temp_ln" diff --git a/testcases/kernel/syscalls/statx/statx03.c b/testcases/kernel/syscalls/statx/statx03.c index b88809063..2465d8773 100644 --- a/testcases/kernel/syscalls/statx/statx03.c +++ b/testcases/kernel/syscalls/statx/statx03.c @@ -24,6 +24,7 @@ #include "tst_safe_macros.h" #include "tst_get_bad_addr.h" #include "lapi/stat.h" +#include "lapi/fcntl.h" #define TESTFILE "test_file" #define MODE 0644 diff --git a/testcases/kernel/syscalls/statx/statx04.c b/testcases/kernel/syscalls/statx/statx04.c index 3923b7f8e..58296bd24 100644 --- a/testcases/kernel/syscalls/statx/statx04.c +++ b/testcases/kernel/syscalls/statx/statx04.c @@ -52,10 +52,11 @@ */ #define _GNU_SOURCE +#include <stdlib.h> #include "tst_test.h" #include "lapi/fs.h" -#include <stdlib.h> #include "lapi/stat.h" +#include "lapi/fcntl.h" #define MOUNT_POINT "mntpoint" #define TESTDIR MOUNT_POINT "/testdir" diff --git a/testcases/kernel/syscalls/statx/statx05.c b/testcases/kernel/syscalls/statx/statx05.c index f62dadd5c..9781b3e70 100644 --- a/testcases/kernel/syscalls/statx/statx05.c +++ b/testcases/kernel/syscalls/statx/statx05.c @@ -27,6 +27,7 @@ #include "tst_test.h" #include "lapi/fs.h" #include "lapi/stat.h" +#include "lapi/fcntl.h" #define MNTPOINT "mnt_point" #define TESTDIR_FLAGGED MNTPOINT"/test_dir1" diff --git a/testcases/kernel/syscalls/statx/statx06.c b/testcases/kernel/syscalls/statx/statx06.c index fa75982b0..1771dff49 100644 --- a/testcases/kernel/syscalls/statx/statx06.c +++ b/testcases/kernel/syscalls/statx/statx06.c @@ -111,10 +111,10 @@ static void test_statx(unsigned int test_nr) clock_wait_tick(); SAFE_CLOCK_GETTIME(CLOCK_REALTIME, &after_time); - TEST(statx(AT_FDCWD, TEST_FILE, 0, STATX_ALL, &buff)); + TEST(statx(AT_FDCWD, TEST_FILE, 0, STATX_BASIC_STATS | STATX_BTIME, &buff)); if (TST_RET != 0) { tst_brk(TFAIL | TTERRNO, - "statx(AT_FDCWD, %s, 0, STATX_ALL, &buff)", + "statx(AT_FDCWD, %s, 0, STATX_BASIC_STATS | STATX_BTIME, &buff)", TEST_FILE); } diff --git a/testcases/kernel/syscalls/statx/statx07.c b/testcases/kernel/syscalls/statx/statx07.c index 8cb3e9b6d..4dbf83e18 100644 --- a/testcases/kernel/syscalls/statx/statx07.c +++ b/testcases/kernel/syscalls/statx/statx07.c @@ -27,12 +27,7 @@ * but mode has been chaged in server file. * * The support for SYNC flags was implemented in NFS in: - * - * commit 9ccee940bd5b766b6dab6c1a80908b9490a4850d - * Author: Trond Myklebust <trond.myklebust@primarydata.com> - * Date: Thu Jan 4 17:46:09 2018 -0500 - * - * Support statx() mask and query flags parameters + * 9ccee940bd5b ("Support statx() mask and query flags parameters") */ #define _GNU_SOURCE @@ -44,6 +39,7 @@ #include <sys/mount.h> #include "tst_test.h" #include "lapi/stat.h" +#include "lapi/fcntl.h" #define MODE(X) (X & (~S_IFMT)) #define FLAG_NAME(x) .flag = x, .flag_name = #x @@ -67,15 +63,15 @@ static int get_mode(char *file_name, int flag_type, char *flag_name) { struct statx buf; - TEST(statx(AT_FDCWD, file_name, flag_type, STATX_ALL, &buf)); + TEST(statx(AT_FDCWD, file_name, flag_type, STATX_BASIC_STATS, &buf)); if (TST_RET == -1) { tst_brk(TFAIL | TST_ERR, - "statx(AT_FDCWD, %s, %s, STATX_ALL, &buf)", + "statx(AT_FDCWD, %s, %s, STATX_BASIC_STATS, &buf)", file_name, flag_name); } - tst_res(TINFO, "statx(AT_FDCWD, %s, %s, STATX_ALL, &buf) = %o", + tst_res(TINFO, "statx(AT_FDCWD, %s, %s, STATX_BASIC_STATS, &buf) = %o", file_name, flag_name, buf.stx_mode); return buf.stx_mode; diff --git a/testcases/kernel/syscalls/statx/statx08.c b/testcases/kernel/syscalls/statx/statx08.c index 10b1ca460..64b36986d 100644 --- a/testcases/kernel/syscalls/statx/statx08.c +++ b/testcases/kernel/syscalls/statx/statx08.c @@ -26,6 +26,7 @@ #include "lapi/fs.h" #include <stdlib.h> #include "lapi/stat.h" +#include "lapi/fcntl.h" #define MOUNT_POINT "mntpoint" #define TESTDIR_FLAGGED MOUNT_POINT"/test_dir1" diff --git a/testcases/kernel/syscalls/statx/statx09.c b/testcases/kernel/syscalls/statx/statx09.c index aea329e08..6e75ff3ec 100644 --- a/testcases/kernel/syscalls/statx/statx09.c +++ b/testcases/kernel/syscalls/statx/statx09.c @@ -20,10 +20,12 @@ #define _GNU_SOURCE #include <sys/mount.h> #include <stdlib.h> +#include <stdio.h> #include "tst_test.h" #include "lapi/fs.h" #include "lapi/fsverity.h" #include "lapi/stat.h" +#include "lapi/fcntl.h" #include <inttypes.h> #define MNTPOINT "mnt_point" @@ -79,8 +81,10 @@ static void flag_setup(void) { int fd, attr, ret; struct fsverity_enable_arg enable; + struct stat statbuf; fd = SAFE_OPEN(TESTFILE_FLAGGED, O_RDONLY, 0664); + SAFE_FSTAT(fd, &statbuf); ret = ioctl(fd, FS_IOC_GETFLAGS, &attr); if (ret < 0) { @@ -93,7 +97,7 @@ static void flag_setup(void) memset(&enable, 0, sizeof(enable)); enable.version = 1; enable.hash_algorithm = hash_algorithms[0]; - enable.block_size = 4096; + enable.block_size = statbuf.st_blksize; enable.salt_size = 0; enable.salt_ptr = (intptr_t)NULL; enable.sig_size = 0; @@ -117,6 +121,12 @@ static void flag_setup(void) static void setup(void) { + char opt_bsize[32]; + const char *const fs_opts[] = {"-O verity", opt_bsize, NULL}; + + snprintf(opt_bsize, sizeof(opt_bsize), "-b %i", getpagesize()); + SAFE_MKFS(tst_device->dev, tst_device->fs_type, fs_opts, NULL); + TEST(mount(tst_device->dev, MNTPOINT, tst_device->fs_type, 0, NULL)); if (TST_RET) { if (TST_ERR == EINVAL) @@ -144,10 +154,9 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .needs_root = 1, + .needs_device = 1, .mntpoint = MNTPOINT, - .format_device = 1, .dev_fs_type = "ext4", - .dev_fs_opts = (const char *const []){"-O verity", NULL}, .needs_kconfigs = (const char *[]) { "CONFIG_FS_VERITY", NULL diff --git a/testcases/kernel/syscalls/statx/statx10.c b/testcases/kernel/syscalls/statx/statx10.c new file mode 100644 index 000000000..42106285e --- /dev/null +++ b/testcases/kernel/syscalls/statx/statx10.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 FUJITSU LIMITED. All rights reserved. + * Author: Yang Xu <xuyang2018.jy@fujitsu.com> + */ + +/*\ + * [Description] + * + * It is a basic test for STATX_DIOALIGN mask on ext4 and xfs filesystem. + * + * - STATX_DIOALIGN Want stx_dio_mem_align and stx_dio_offset_align value + * + * Check these two values are nonzero under dio situation when STATX_DIOALIGN + * in the request mask. + * + * On ext4, files that use certain filesystem features (data journaling, + * encryption, and verity) fall back to buffered I/O. But ltp creates own + * filesystem by enabling mount_device in tst_test struct. If we set block + * device to LTP_DEV environment, we use this block device to mount by using + * default mount option. Otherwise, use loop device to simuate it. So it can + * avoid these above situations and don't fall back to buffered I/O. + * + * Minimum Linux version required is v6.1. + */ + +#define _GNU_SOURCE +#include <sys/types.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdbool.h> +#include "tst_test.h" +#include "lapi/stat.h" +#include "lapi/fcntl.h" + +#define MNTPOINT "mnt_point" +#define TESTFILE MNTPOINT"/testfile" + +static void verify_statx(void) +{ + struct statx buf; + + TST_EXP_PASS_SILENT(statx(AT_FDCWD, TESTFILE, 0, STATX_DIOALIGN, &buf), + "statx(AT_FDCWD, %s, 0, STATX_DIOALIGN, &buf)", TESTFILE); + + if (!(buf.stx_mask & STATX_DIOALIGN)) { + tst_res(TCONF, "Filesystem does not support STATX_DIOALIGN"); + return; + } + +#ifdef HAVE_STRUCT_STATX_STX_DIO_MEM_ALIGN + if (buf.stx_dio_mem_align != 0) + tst_res(TPASS, "stx_dio_mem_align:%u", buf.stx_dio_mem_align); + else + tst_res(TFAIL, "stx_dio_mem_align was 0, but DIO should be supported"); + + if (buf.stx_dio_offset_align != 0) + tst_res(TPASS, "stx_dio_offset_align:%u", buf.stx_dio_offset_align); + else + tst_res(TFAIL, "stx_dio_offset_align was 0, but DIO should be supported"); +#else + tst_res(TCONF, "glibc statx struct miss stx_dio_mem_align field"); +#endif +} + +static void setup(void) +{ + int fd = -1; + + if (strcmp(tst_device->fs_type, "xfs") && strcmp(tst_device->fs_type, "ext4")) + tst_brk(TCONF, "This test only supports ext4 and xfs"); + + SAFE_FILE_PRINTF(TESTFILE, "AAAA"); + fd = open(TESTFILE, O_RDWR | O_DIRECT); + if (fd == -1) { + if (errno == EINVAL) + tst_brk(TCONF, + "The regular file is not on a filesystem that support DIO"); + else + tst_brk(TBROK | TERRNO, + "The regular file is open with O_RDWR | O_DIRECT failed"); + } + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .test_all = verify_statx, + .setup = setup, + .needs_root = 1, + .mntpoint = MNTPOINT, + .mount_device = 1, + .all_filesystems = 1, +}; diff --git a/testcases/kernel/syscalls/statx/statx11.c b/testcases/kernel/syscalls/statx/statx11.c new file mode 100644 index 000000000..653050855 --- /dev/null +++ b/testcases/kernel/syscalls/statx/statx11.c @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 FUJITSU LIMITED. All rights reserved. + * Author: Yang Xu <xuyang2018.jy@fujitsu.com> + */ + +/*\ + * [Description] + * + * It is a basic test for STATX_DIOALIGN mask on block device. + * + * - STATX_DIOALIGN Want stx_dio_mem_align and stx_dio_offset_align value + * + * These two values are tightly coupled to the kernel's current DIO + * restrictions on block devices. + * + * Minimum Linux version required is v6.1. + */ + +#define _GNU_SOURCE +#include <sys/types.h> +#include <sys/mount.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdbool.h> +#include <stdio.h> +#include "tst_test.h" +#include "lapi/stat.h" + +static char sys_bdev_dma_path[1024], sys_bdev_logical_path[1024]; + +static void verify_statx(void) +{ + struct statx buf; + + TST_EXP_PASS_SILENT(statx(AT_FDCWD, tst_device->dev, 0, STATX_DIOALIGN, &buf), + "statx(AT_FDCWD, %s, 0, STATX_DIOALIGN, &buf)", tst_device->dev); + + if (!(buf.stx_mask & STATX_DIOALIGN)) { + tst_res(TCONF, "Filesystem does not support STATX_DIOALIGN"); + return; + } + +#ifdef HAVE_STRUCT_STATX_STX_DIO_MEM_ALIGN + /* + * This test is tightly coupled to the kernel's current DIO restrictions + * on block devices. The general rule of DIO needing to be aligned to the + * block device's logical block size was relaxed to allow user buffers + * (but not file offsets) aligned to the DMA alignment instead. See v6.0 + * commit bf8d08532bc1 ("iomap: add support for dma aligned direct-io") and + * they are subject to further change in the future. + * Also can see commit 2d985f8c6b9 ("vfs: support STATX_DIOALIGN on block devices). + */ + TST_ASSERT_ULONG(sys_bdev_dma_path, buf.stx_dio_mem_align - 1); + TST_ASSERT_ULONG(sys_bdev_logical_path, buf.stx_dio_offset_align); +#else + tst_res(TCONF, "glibc statx struct miss stx_dio_mem_align field"); +#endif +} + +static void setup(void) +{ + char full_name[256]; + char *dev_name; + + strcpy(full_name, tst_device->dev); + dev_name = SAFE_BASENAME(full_name); + sprintf(sys_bdev_logical_path, "/sys/block/%s/queue/logical_block_size", dev_name); + + /* + * Since /sys/block/%s/queue doesn't exist for partition, we need to + * use a while to search block device instead of partition. + */ + while (access(sys_bdev_logical_path, F_OK) != 0) { + dev_name[strlen(dev_name)-1] = '\0'; + sprintf(sys_bdev_logical_path, "/sys/block/%s/queue/logical_block_size", dev_name); + } + + sprintf(sys_bdev_dma_path, "/sys/block/%s/queue/dma_alignment", dev_name); + if (access(sys_bdev_dma_path, F_OK) != 0) + tst_brk(TCONF, "dma_alignment sysfs file doesn't exist"); +} + +static struct tst_test test = { + .test_all = verify_statx, + .setup = setup, + .needs_device = 1, + .needs_root = 1, +}; diff --git a/testcases/kernel/syscalls/statx/statx12.c b/testcases/kernel/syscalls/statx/statx12.c new file mode 100644 index 000000000..432f1cb77 --- /dev/null +++ b/testcases/kernel/syscalls/statx/statx12.c @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 FUJITSU LIMITED. All rights reserved. + * Author: Yang Xu <xuyang2018.jy@fujitsu.com> + */ + +/*\ + * [Description] + * + * It is a basic test for STATX_ATTR_MOUNT_ROOT flag. + * + * This flag indicates whether the path or fd refers to the root of a mount + * or not. + * + * Minimum Linux version required is v5.8. + */ + +#define _GNU_SOURCE +#include <unistd.h> +#include <stdlib.h> +#include <stdbool.h> +#include <stdio.h> +#include "tst_test.h" +#include "lapi/stat.h" + +#define MNTPOINT "mntpoint" +#define TESTFILE MNTPOINT"/testfile" + +static int dir_fd = -1, file_fd = -1; + +static struct tcase { + const char *path; + bool mnt_root; + int *fd; +} tcases[] = { + {MNTPOINT, 1, &dir_fd}, + {TESTFILE, 0, &file_fd} +}; + +static void verify_statx(unsigned int n) +{ + struct tcase *tc = &tcases[n/2]; + struct statx buf; + bool flag = n % 2; + + if (flag) { + tst_res(TINFO, "Testing %s with STATX_ATTR_MOUNT_ROOT by fd", + tc->path); + TST_EXP_PASS_SILENT(statx(*tc->fd, "", AT_EMPTY_PATH, 0, &buf)); + } else { + tst_res(TINFO, "Testing %s with STATX_ATTR_MOUNT_ROOT by path", + tc->path); + TST_EXP_PASS_SILENT(statx(AT_FDCWD, tc->path, 0, 0, &buf)); + } + + if (!(buf.stx_attributes_mask & STATX_ATTR_MOUNT_ROOT)) { + tst_res(TCONF, "Filesystem does not support STATX_ATTR_MOUNT_ROOT"); + return; + } + + if (buf.stx_attributes & STATX_ATTR_MOUNT_ROOT) { + tst_res(tc->mnt_root ? TPASS : TFAIL, + "STATX_ATTR_MOUNT_ROOT flag is set"); + } else { + tst_res(tc->mnt_root ? TFAIL : TPASS, + "STATX_ATTR_MOUNT_ROOT flag is not set"); + } +} + +static void setup(void) +{ + SAFE_CREAT(TESTFILE, 0755); + dir_fd = SAFE_OPEN(MNTPOINT, O_DIRECTORY); + file_fd = SAFE_OPEN(TESTFILE, O_RDWR); +} + +static void cleanup(void) +{ + if (dir_fd > -1) + SAFE_CLOSE(dir_fd); + + if (file_fd > -1) + SAFE_CLOSE(file_fd); +} + +static struct tst_test test = { + .test = verify_statx, + .setup = setup, + .cleanup = cleanup, + .mntpoint = MNTPOINT, + .mount_device = 1, + .all_filesystems = 1, + .needs_root = 1, + .tcnt = 2 * ARRAY_SIZE(tcases) +}; diff --git a/testcases/kernel/syscalls/switch/endian_switch01.c b/testcases/kernel/syscalls/switch/endian_switch01.c index bee35184a..fac9e2382 100644 --- a/testcases/kernel/syscalls/switch/endian_switch01.c +++ b/testcases/kernel/syscalls/switch/endian_switch01.c @@ -2,7 +2,7 @@ /* * Copyright (c) International Business Machines Corp., 2008 * Copyright (c) Paul Mackerras, IBM Corp., 2008 - * Copyright (c) 2018 Linux Test Project + * Copyright (c) 2018-2023 Linux Test Project */ /* @@ -17,14 +17,17 @@ #include <elf.h> #include <sys/types.h> #include <sys/wait.h> + #include "tst_test.h" #if defined(__powerpc64__) || defined(__powerpc__) + # ifndef PPC_FEATURE_TRUE_LE -# define PPC_FEATURE_TRUE_LE 0x00000002 +# define PPC_FEATURE_TRUE_LE 0x00000002 # endif -# define TST_NO_DEFAULT_MAIN +# ifdef HAVE_GETAUXVAL +# include <sys/auxv.h> /* * Make minimal call to 0x1ebe. If we get ENOSYS then syscall is not @@ -42,6 +45,9 @@ void check_le_switch_supported(void) exit(errno); } + if (!(getauxval(AT_HWCAP) & PPC_FEATURE_TRUE_LE)) + tst_brk(TCONF, "Processor does not support little-endian mode"); + SAFE_WAIT(&status); if (WIFSIGNALED(status)) { int sig = WTERMSIG(status); @@ -96,18 +102,9 @@ static struct tst_test test = { .forks_child = 1, }; -int main4(int argc, char **argv, LTP_ATTRIBUTE_UNUSED char **envp, - unsigned long *auxv) -{ - for (; *auxv != AT_NULL && *auxv != AT_HWCAP; auxv += 2) - ; - - if (!(auxv[0] == AT_HWCAP && (auxv[1] & PPC_FEATURE_TRUE_LE))) - tst_brk(TCONF, "Processor does not support little-endian mode"); - - tst_run_tcases(argc, argv, &test); - return 0; -} +# else +TST_TEST_TCONF("Toolchain does not have <sys/auxv.h>"); +# endif /* HAVE_GETAUXVAL */ #else /* defined (__powerpc64__) || (__powerpc__) */ TST_TEST_TCONF("This system does not support running of switch() syscall"); diff --git a/testcases/kernel/syscalls/symlink/symlink01.c b/testcases/kernel/syscalls/symlink/symlink01.c index eba64f9bd..8cf0c8f1c 100644 --- a/testcases/kernel/syscalls/symlink/symlink01.c +++ b/testcases/kernel/syscalls/symlink/symlink01.c @@ -658,10 +658,10 @@ int creat_symlink(char *path1, char *path2, char *_path3) path1, errno, strerror(errno)); return 0; } else { - sprintf(Buf, "symlink(%s, %s) was succesful.\n", path1, path2); + sprintf(Buf, "symlink(%s, %s) was successful.\n", path1, path2); strcat(Buffer, Buf); #if DEBUG - tst_resm(TPASS, "symlink(%s, %s) was succesful.", path1, path2); + tst_resm(TPASS, "symlink(%s, %s) was successful.", path1, path2); #endif } return 1; @@ -685,10 +685,10 @@ int creat_object(char *path1, char *_path2, char *_path3) path1, errno, strerror(errno)); return 0; } else { - sprintf(Buf, "creat(%s, %#o) was succesful.\n", path1, MODE); + sprintf(Buf, "creat(%s, %#o) was successful.\n", path1, MODE); strcat(Buffer, Buf); #if DEBUG - tst_resm(TPASS, "creat(%s, %#o) was succesful.", path1, MODE); + tst_resm(TPASS, "creat(%s, %#o) was successful.", path1, MODE); #endif } if (close(fd) == -1) { diff --git a/testcases/kernel/syscalls/timerfd/timerfd_create01.c b/testcases/kernel/syscalls/timerfd/timerfd_create01.c index 3d70b84f0..18a233586 100644 --- a/testcases/kernel/syscalls/timerfd/timerfd_create01.c +++ b/testcases/kernel/syscalls/timerfd/timerfd_create01.c @@ -1,95 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * 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. + * Zeng Linggang <zenglg.jy@cn.fujitsu.com> + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> */ -/* - * DESCRIPTION - * Verify that, - * 1. The clockid argument is neither CLOCK_MONOTONIC nor CLOCK_REALTIME, - * EINVAL would return. - * 2. flags is invalid, EINVAL would return. +/*\ + * [Description] + * + * This test verifies that: + * - clockid argument is neither CLOCK_MONOTONIC nor CLOCK_REALTIME, + * EINVAL would return. + * - flags is invalid, EINVAL would return. */ -#define _GNU_SOURCE - #include <errno.h> -#include "test.h" -#include "lapi/timerfd.h" - -char *TCID = "timerfd_create01"; +#include "tst_test.h" +#include "tst_safe_timerfd.h" static struct test_case_t { int clockid; int flags; int exp_errno; -} test_cases[] = { - {-1, 0, EINVAL}, - {0, -1, EINVAL}, +} tcases[] = { + { -1, 0, EINVAL }, + { 0, -1, EINVAL }, }; -int TST_TOTAL = ARRAY_SIZE(test_cases); -static void setup(void); -static void timerfd_create_verify(const struct test_case_t *); -static void cleanup(void); - -int main(int argc, char *argv[]) +static void run(unsigned int i) { - int lc; - int i; - - tst_parse_opts(argc, argv, NULL, NULL); + struct test_case_t *test = &tcases[i]; - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - for (i = 0; i < TST_TOTAL; i++) - timerfd_create_verify(&test_cases[i]); - } - - cleanup(); - tst_exit(); + TST_EXP_FAIL(timerfd_create(test->clockid, test->flags), test->exp_errno); } -static void setup(void) -{ - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; -} - -static void timerfd_create_verify(const struct test_case_t *test) -{ - TEST(timerfd_create(test->clockid, test->flags)); - - if (TEST_RETURN != -1) { - tst_resm(TFAIL, "timerfd_create() succeeded unexpectedly"); - return; - } - - if (TEST_ERRNO == test->exp_errno) { - tst_resm(TPASS | TTERRNO, - "timerfd_create() failed as expected"); - } else { - tst_resm(TFAIL | TTERRNO, - "timerfd_create() failed unexpectedly; expected: " - "%d - %s", test->exp_errno, strerror(test->exp_errno)); - } -} - -static void cleanup(void) -{ -} +static struct tst_test test = { + .test = run, + .tcnt = ARRAY_SIZE(tcases), +}; diff --git a/testcases/kernel/syscalls/uname/uname04.c b/testcases/kernel/syscalls/uname/uname04.c index 2d0851c8b..885368c24 100644 --- a/testcases/kernel/syscalls/uname/uname04.c +++ b/testcases/kernel/syscalls/uname/uname04.c @@ -79,4 +79,8 @@ static void run(unsigned int test_nr) static struct tst_test test = { .test = run, .tcnt = 2, + .tags = (const struct tst_tag[]) { + {"CVE", "2012-0957"}, + {} + } }; diff --git a/testcases/kernel/syscalls/utils/compat_uid.h b/testcases/kernel/syscalls/utils/compat_uid.h index 94e54f310..7a345a654 100644 --- a/testcases/kernel/syscalls/utils/compat_uid.h +++ b/testcases/kernel/syscalls/utils/compat_uid.h @@ -26,7 +26,7 @@ #include "tst_common.h" #ifdef TST_USE_COMPAT16_SYSCALL -typedef __kernel_old_uid_t UID_T; +typedef unsigned short UID_T; int UID_SIZE_CHECK(uid_t uid) { /* See high2lowuid in linux/highuid.h diff --git a/testcases/kernel/syscalls/utils/ioprio.h b/testcases/kernel/syscalls/utils/ioprio.h deleted file mode 100644 index 07220945c..000000000 --- a/testcases/kernel/syscalls/utils/ioprio.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef __IOPRIO_H__ -#define __IOPRIO_H__ - -//---------------------------------------------------------------------------- -// Copy of the 2.6.18 kernel header (linux/ioprio.h) -// - -/* - * Gives us 8 prio classes with 13-bits of data for each class - */ -#define IOPRIO_BITS (16) -#define IOPRIO_CLASS_SHIFT (13) -#define IOPRIO_PRIO_MASK ((1UL << IOPRIO_CLASS_SHIFT) - 1) - -#define IOPRIO_PRIO_CLASS(mask) ((mask) >> IOPRIO_CLASS_SHIFT) -#define IOPRIO_PRIO_DATA(mask) ((mask) & IOPRIO_PRIO_MASK) -#define IOPRIO_PRIO_VALUE(class, data) (((class) << IOPRIO_CLASS_SHIFT) | data) - -#define ioprio_valid(mask) (IOPRIO_PRIO_CLASS((mask)) != IOPRIO_CLASS_NONE) - -/* - * These are the io priority groups as implemented by CFQ. RT is the realtime - * class, it always gets premium service. BE is the best-effort scheduling - * class, the default for any process. IDLE is the idle scheduling class, it - * is only served when no one else is using the disk. - */ -enum { - IOPRIO_CLASS_NONE, - IOPRIO_CLASS_RT, - IOPRIO_CLASS_BE, - IOPRIO_CLASS_IDLE, -}; - -/* - * 8 best effort priority levels are supported - */ -#define IOPRIO_BE_NR (8) - -enum { - IOPRIO_WHO_PROCESS = 1, - IOPRIO_WHO_PGRP, - IOPRIO_WHO_USER, -}; -//----------------------------------------------------------------------------- - -#endif /* __IOPRIO_H__ */ diff --git a/testcases/kernel/syscalls/utime/utime02.c b/testcases/kernel/syscalls/utime/utime02.c index 54693899e..fdcd40f66 100644 --- a/testcases/kernel/syscalls/utime/utime02.c +++ b/testcases/kernel/syscalls/utime/utime02.c @@ -11,6 +11,7 @@ * Verify that the system call utime() successfully changes the last * access and modification times of a file to the current time, * under the following constraints: + * * - The times argument is NULL. * - The user ID of the process is not "root". * - The file is owned by the user ID of the process. diff --git a/testcases/kernel/syscalls/utime/utime04.c b/testcases/kernel/syscalls/utime/utime04.c index 67e40127d..7b820ab06 100644 --- a/testcases/kernel/syscalls/utime/utime04.c +++ b/testcases/kernel/syscalls/utime/utime04.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) International Business Machines Corp., 2001 - * 07/2001 ported by John George - * Copyright (c) 2022 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> + * Copyright (c) International Business Machines Corp., 2001 + * 07/2001 ported by John George + * Copyright (c) 2022 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> */ /*\ @@ -11,6 +11,7 @@ * Verify that the system call utime() successfully changes the last * access and modification times of a file to the values specified by * times argument, under the following constraints: + * * - The times argument is not NULL. * - The user ID of the process is "root". */ diff --git a/testcases/kernel/syscalls/utime/utime05.c b/testcases/kernel/syscalls/utime/utime05.c index ce0aa5dbf..941a3ccee 100644 --- a/testcases/kernel/syscalls/utime/utime05.c +++ b/testcases/kernel/syscalls/utime/utime05.c @@ -11,6 +11,7 @@ * Verify that the system call utime() successfully changes the last * access and modification times of a file to the values specified by * times argument, under the following constraints: + * * - The times argument is not NULL. * - The user ID of the process is not "root". * - The file is owned by the user ID of the process. diff --git a/testcases/kernel/syscalls/utime/utime06.c b/testcases/kernel/syscalls/utime/utime06.c index 9057c29da..3ba62a316 100644 --- a/testcases/kernel/syscalls/utime/utime06.c +++ b/testcases/kernel/syscalls/utime/utime06.c @@ -9,11 +9,12 @@ * [Description] * * Verify that system call utime() fails with - * - EACCES when times argument is NULL and user does not have rights - * to modify the file. + * + * - EACCES when times argument is NULL and user does not have rights to modify + * the file. * - ENOENT when specified file does not exist. - * - EPERM when times argument is not NULL and user does not have rights - * to modify the file. + * - EPERM when times argument is not NULL and user does not have rights to + * modify the file. * - EROFS when the path resides on a read-only filesystem. */ diff --git a/testcases/kernel/syscalls/utimensat/utimensat01.c b/testcases/kernel/syscalls/utimensat/utimensat01.c index 71a0e8d0e..efcb5c7a4 100644 --- a/testcases/kernel/syscalls/utimensat/utimensat01.c +++ b/testcases/kernel/syscalls/utimensat/utimensat01.c @@ -233,7 +233,7 @@ static void run(unsigned int i) dfd = SAFE_OPEN(TEST_DIR, tc->oflags); if (tc->pathname) { - fd = SAFE_OPEN(tc->pathname, O_WRONLY | O_CREAT); + fd = SAFE_OPEN(tc->pathname, O_WRONLY | O_CREAT, 0200); pathname = tc->pathname; SAFE_CHMOD(tc->pathname, tc->mode); reset_time(pathname, dfd, tc->flags, i); diff --git a/testcases/kernel/syscalls/write/write02.c b/testcases/kernel/syscalls/write/write02.c index 2f630ab65..ab38dce77 100644 --- a/testcases/kernel/syscalls/write/write02.c +++ b/testcases/kernel/syscalls/write/write02.c @@ -2,27 +2,24 @@ /* * Copyright (c) 2017 Carlo Marcelo Arenas Belon <carlo@gmail.com> * Copyright (c) 2018 Cyril Hrubis <chrubis@suse.cz> + * Copyright (c) Linux Test Project, 2003-2023 */ -/* + +/*\ + * [Description] + * * Tests for a special case NULL buffer with size 0 is expected to return 0. */ -#include <errno.h> #include "tst_test.h" static int fd; static void verify_write(void) { - TEST(write(fd, NULL, 0)); - - if (TST_RET != 0) { - tst_res(TFAIL | TTERRNO, - "write() should have succeeded with ret=0"); - return; - } + TST_EXP_POSITIVE(write(fd, NULL, 0)); - tst_res(TPASS, "write(fd, NULL, 0) == 0"); + TST_EXP_EXPR(TST_RET == 0, "write(fd, NULL, %ld) == %d", TST_RET, 0); } static void setup(void) diff --git a/testcases/kernel/syscalls/write/write04.c b/testcases/kernel/syscalls/write/write04.c index afbac0f09..a5d62e0f5 100644 --- a/testcases/kernel/syscalls/write/write04.c +++ b/testcases/kernel/syscalls/write/write04.c @@ -28,7 +28,7 @@ static void verify_write(void) { char wbuf[8 * page_size]; - TST_EXP_FAIL(write(wfd, wbuf, sizeof(wbuf)), EAGAIN); + TST_EXP_FAIL2(write(wfd, wbuf, sizeof(wbuf)), EAGAIN); } static void setup(void) diff --git a/testcases/kernel/syscalls/write/write05.c b/testcases/kernel/syscalls/write/write05.c index 79769621c..b907624a8 100644 --- a/testcases/kernel/syscalls/write/write05.c +++ b/testcases/kernel/syscalls/write/write05.c @@ -1,19 +1,22 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * 07/2001 Ported by John George - * 04/2002 wjhuie sigset cleanups - * 08/2007 Ricardo Salveti de Araujo <rsalveti@linux.vnet.ibm.com> + * Copyright (c) International Business Machines Corp., 2001 + * 07/2001 Ported by John George + * 04/2002 wjhuie sigset cleanups + * 08/2007 Ricardo Salveti de Araujo <rsalveti@linux.vnet.ibm.com> + * Copyright (c) Linux Test Project, 2002-2023 */ -/* - * DESCRIPTION +/*\ + * [Description] + * * Check the return value, and errnos of write(2) + * * - when the file descriptor is invalid - EBADF * - when the buf parameter is invalid - EFAULT * - on an attempt to write to a pipe that is not open for reading - EPIPE */ + #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> @@ -42,7 +45,7 @@ static struct tcase { {&pipefd[1], &buf, sizeof(buf), EPIPE}, }; -static int sigpipe_cnt; +static volatile int sigpipe_cnt; static void sighandler(int sig) { @@ -56,26 +59,12 @@ static void verify_write(unsigned int i) sigpipe_cnt = 0; - TEST(write(*tc->fd, *tc->buf, tc->size)); - - if (TST_RET != -1) { - tst_res(TFAIL, "write() succeeded unexpectedly"); - return; - } - - if (TST_ERR != tc->exp_errno) { - tst_res(TFAIL | TTERRNO, - "write() failed unexpectedly, expected %s", - tst_strerrno(tc->exp_errno)); + TST_EXP_FAIL2(write(*tc->fd, *tc->buf, tc->size), tc->exp_errno); + if (TST_RET != -1) return; - } - if (tc->exp_errno == EPIPE && sigpipe_cnt != 1) { + if (tc->exp_errno == EPIPE && sigpipe_cnt != 1) tst_res(TFAIL, "sigpipe_cnt = %i", sigpipe_cnt); - return; - } - - tst_res(TPASS | TTERRNO, "write() failed expectedly"); } static void setup(void) |