* [PATCH 0/2] faccessat test improvements
@ 2024-10-16 19:21 Siddhesh Poyarekar
2024-10-16 19:21 ` [PATCH 1/2] tst-faccessat.c: Port to libsupport Siddhesh Poyarekar
` (6 more replies)
0 siblings, 7 replies; 16+ messages in thread
From: Siddhesh Poyarekar @ 2024-10-16 19:21 UTC (permalink / raw)
To: libc-alpha; +Cc: carlos
Cleaned up current test for faccessat and added an xtest to verify
behaviour with different real and effective user/group combinations.
Siddhesh Poyarekar (2):
tst-faccessat.c: Port to libsupport
io: Add setuid tests for faccessat
io/Makefile | 4 +
io/tst-faccessat-setuid.c | 163 ++++++++++++++++++++++++++++
io/tst-faccessat.c | 219 +++++++++++---------------------------
support/Makefile | 1 +
support/xdup.c | 30 ++++++
support/xunistd.h | 1 +
6 files changed, 262 insertions(+), 156 deletions(-)
create mode 100644 io/tst-faccessat-setuid.c
create mode 100644 support/xdup.c
--
2.46.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 1/2] tst-faccessat.c: Port to libsupport
2024-10-16 19:21 [PATCH 0/2] faccessat test improvements Siddhesh Poyarekar
@ 2024-10-16 19:21 ` Siddhesh Poyarekar
2024-11-06 15:08 ` Adhemerval Zanella Netto
2024-10-16 19:21 ` [PATCH 2/2] io: Add setuid tests for faccessat Siddhesh Poyarekar
` (5 subsequent siblings)
6 siblings, 1 reply; 16+ messages in thread
From: Siddhesh Poyarekar @ 2024-10-16 19:21 UTC (permalink / raw)
To: libc-alpha; +Cc: carlos
Use libsupport convenience functions and macros instead of the old
test-skeleton. Also add a new xdup() convenience wrapper function.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
---
io/tst-faccessat.c | 219 +++++++++++++--------------------------------
support/Makefile | 1 +
support/xdup.c | 30 +++++++
support/xunistd.h | 1 +
4 files changed, 95 insertions(+), 156 deletions(-)
create mode 100644 support/xdup.c
diff --git a/io/tst-faccessat.c b/io/tst-faccessat.c
index b90954e318..609cdddaf7 100644
--- a/io/tst-faccessat.c
+++ b/io/tst-faccessat.c
@@ -1,6 +1,23 @@
-/* Test for faccessat function. */
-
-#include <dirent.h>
+/* Test for faccessat function.
+ Copyright (C) 2006-2024 Free Software Foundation, Inc.
+ Copyright The GNU Toolchain Authors.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
@@ -8,47 +25,19 @@
#include <unistd.h>
#include <sys/stat.h>
+#include <support/check.h>
+#include <support/temp_file.h>
+#include <support/test-driver.h>
+#include <support/xdirent.h>
#include <support/xunistd.h>
-static void prepare (void);
-#define PREPARE(argc, argv) prepare ()
-
-static int do_test (void);
-#define TEST_FUNCTION do_test ()
-
-#include "../test-skeleton.c"
-
static int dir_fd;
static void
-prepare (void)
+prepare (int argc, char **argv)
{
- size_t test_dir_len = strlen (test_dir);
- static const char dir_name[] = "/tst-faccessat.XXXXXX";
-
- size_t dirbuflen = test_dir_len + sizeof (dir_name);
- char *dirbuf = malloc (dirbuflen);
- if (dirbuf == NULL)
- {
- puts ("out of memory");
- exit (1);
- }
-
- snprintf (dirbuf, dirbuflen, "%s%s", test_dir, dir_name);
- if (mkdtemp (dirbuf) == NULL)
- {
- puts ("cannot create temporary directory");
- exit (1);
- }
-
- add_temp_file (dirbuf);
-
- dir_fd = open (dirbuf, O_RDONLY | O_DIRECTORY);
- if (dir_fd == -1)
- {
- puts ("cannot open directory");
- exit (1);
- }
+ dir_fd = xopen (support_create_temp_directory ("tst-faccessat."),
+ O_RDONLY | O_DIRECTORY, 0);
}
@@ -56,159 +45,77 @@ static int
do_test (void)
{
/* fdopendir takes over the descriptor, make a copy. */
- int dupfd = dup (dir_fd);
- if (dupfd == -1)
- {
- puts ("dup failed");
- return 1;
- }
- if (lseek (dupfd, 0, SEEK_SET) != 0)
- {
- puts ("1st lseek failed");
- return 1;
- }
+ int dupfd = xdup (dir_fd);
+ xlseek (dupfd, 0, SEEK_SET);
/* The directory should be empty save the . and .. files. */
- DIR *dir = fdopendir (dupfd);
- if (dir == NULL)
- {
- puts ("fdopendir failed");
- return 1;
- }
+ DIR *dir = xfdopendir (dupfd);
+
struct dirent64 *d;
- while ((d = readdir64 (dir)) != NULL)
+ while ((d = xreaddir64 (dir)) != NULL)
if (strcmp (d->d_name, ".") != 0 && strcmp (d->d_name, "..") != 0)
- {
- printf ("temp directory contains file \"%s\"\n", d->d_name);
- return 1;
- }
- closedir (dir);
+ FAIL_EXIT1 ("temp directory contains file \"%s\"\n", d->d_name);
+ xclosedir (dir);
/* Try to create a file. */
int fd = openat (dir_fd, "some-file", O_CREAT|O_RDWR|O_EXCL, 0666);
if (fd == -1)
{
if (errno == ENOSYS)
- {
- puts ("*at functions not supported");
- return 0;
- }
+ FAIL_UNSUPPORTED ("*at functions not supported");
- puts ("file creation failed");
- return 1;
+ FAIL_EXIT1 ("file creation failed");
}
xwrite (fd, "hello", 5);
puts ("file created");
/* Before closing the file, try using this file descriptor to open
another file. This must fail. */
- if (faccessat (fd, "should-not-work", F_OK, AT_EACCESS) != -1)
- {
- puts ("faccessat using descriptor for normal file worked");
- return 1;
- }
- if (errno != ENOTDIR)
- {
- puts ("\
-error for faccessat using descriptor for normal file not ENOTDIR ");
- return 1;
- }
-
- close (fd);
+ TEST_VERIFY_EXIT (faccessat (fd, "should-not-work", F_OK, AT_EACCESS) == -1);
+ TEST_VERIFY_EXIT (errno == ENOTDIR);
- int result = 0;
+ xclose (fd);
- if (faccessat (dir_fd, "some-file", F_OK, AT_EACCESS))
- {
- printf ("faccessat F_OK: %m\n");
- result = 1;
- }
- if (faccessat (dir_fd, "some-file", W_OK, AT_EACCESS))
- {
- printf ("faccessat W_OK: %m\n");
- result = 1;
- }
+ TEST_VERIFY (faccessat (dir_fd, "some-file", F_OK, AT_EACCESS) == 0);
+ TEST_VERIFY (faccessat (dir_fd, "some-file", W_OK, AT_EACCESS) == 0);
errno = 0;
- if (faccessat (dir_fd, "some-file", X_OK, AT_EACCESS) == 0
- || errno != EACCES)
- {
- printf ("faccessat X_OK on nonexecutable: %m\n");
- result = 1;
- }
+ TEST_VERIFY (faccessat (dir_fd, "some-file", X_OK, AT_EACCESS) != 0
+ && errno == EACCES);
if (fchmodat (dir_fd, "some-file", 0400, 0) != 0)
- {
- printf ("fchownat failed: %m\n");
- return 1;
- }
+ FAIL_EXIT1 ("fchownat failed: %m\n");
- if (faccessat (dir_fd, "some-file", R_OK, AT_EACCESS))
- {
- printf ("faccessat R_OK: %m\n");
- result = 1;
- }
+ TEST_VERIFY (faccessat (dir_fd, "some-file", R_OK, AT_EACCESS) == 0);
+ /* Write would succeed only for EUID root, otherwise this test should
+ fail. */
errno = 0;
- if (faccessat (dir_fd, "some-file", W_OK, AT_EACCESS) == 0
- ? (geteuid () != 0) : (errno != EACCES))
- {
- printf ("faccessat W_OK on unwritable file: %m\n");
- result = 1;
- }
+ TEST_VERIFY (faccessat (dir_fd, "some-file", W_OK, AT_EACCESS) == 0
+ ? (geteuid () == 0) : (errno == EACCES));
/* Create a file descriptor which is closed again right away. */
- int dir_fd2 = dup (dir_fd);
- if (dir_fd2 == -1)
- {
- puts ("dup failed");
- return 1;
- }
+ int dir_fd2 = xdup (dir_fd);
close (dir_fd2);
/* With the file descriptor closed the next call must fail. */
- if (faccessat (dir_fd2, "some-file", F_OK, AT_EACCESS) != -1)
- {
- puts ("faccessat using closed descriptor succeeded");
- return 1;
- }
- if (errno != EBADF)
- {
- puts ("faccessat using closed descriptor did not set EBADF");
- return 1;
- }
+ TEST_VERIFY_EXIT (faccessat (dir_fd2, "some-file", F_OK, AT_EACCESS)
+ == -1);
+ TEST_VERIFY_EXIT (errno == EBADF);
/* Same with a non-existing file. */
- if (faccessat (dir_fd2, "non-existing-file", F_OK, AT_EACCESS) != -1)
- {
- puts ("2nd faccessat using closed descriptor succeeded");
- return 1;
- }
- if (errno != EBADF)
- {
- puts ("2nd faccessat using closed descriptor did not set EBADF");
- return 1;
- }
+ TEST_VERIFY_EXIT (faccessat (dir_fd2, "non-existing-file", F_OK, AT_EACCESS)
+ == -1);
+ TEST_VERIFY_EXIT (errno == EBADF);
- if (unlinkat (dir_fd, "some-file", 0) != 0)
- {
- puts ("unlinkat failed");
- result = 1;
- }
+ TEST_VERIFY (unlinkat (dir_fd, "some-file", 0) == 0);
- close (dir_fd);
+ xclose (dir_fd);
- fd = faccessat (-1, "some-file", F_OK, AT_EACCESS);
- if (fd != -1)
- {
- puts ("faccessat using -1 descriptor succeeded");
- return 1;
- }
- if (errno != EBADF)
- {
- puts ("faccessat using -1 descriptor did not set EBADF");
- return 1;
- }
+ TEST_VERIFY_EXIT (faccessat (-1, "some-file", F_OK, AT_EACCESS) == -1);
+ TEST_VERIFY_EXIT (errno == EBADF);
- return result;
+ return 0;
}
+#define PREPARE prepare
+#include <support/test-driver.c>
diff --git a/support/Makefile b/support/Makefile
index 84e2419775..099f5ebb9c 100644
--- a/support/Makefile
+++ b/support/Makefile
@@ -128,6 +128,7 @@ libsupport-routines = \
xcopy_file_range \
xdlfcn \
xdlmopen \
+ xdup \
xdup2 \
xfchmod \
xfclose \
diff --git a/support/xdup.c b/support/xdup.c
new file mode 100644
index 0000000000..1eab317354
--- /dev/null
+++ b/support/xdup.c
@@ -0,0 +1,30 @@
+/* dup with error checking.
+ Copyright The GNU Toolchain Authors.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <support/xunistd.h>
+#include <support/check.h>
+
+int
+xdup (int from)
+{
+ int ret = dup (from);
+ if (ret < 0)
+ FAIL_EXIT1 ("dup (%d): %m", from);
+
+ return ret;
+}
diff --git a/support/xunistd.h b/support/xunistd.h
index 204951bce7..0c6d837ac0 100644
--- a/support/xunistd.h
+++ b/support/xunistd.h
@@ -35,6 +35,7 @@ pid_t xfork (void);
pid_t xwaitpid (pid_t, int *status, int flags);
void xpipe (int[2]);
void xdup2 (int, int);
+int xdup (int);
int xopen (const char *path, int flags, mode_t);
void support_check_stat_fd (const char *name, int fd, int result);
void support_check_stat_path (const char *name, const char *path, int result);
--
2.46.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 2/2] io: Add setuid tests for faccessat
2024-10-16 19:21 [PATCH 0/2] faccessat test improvements Siddhesh Poyarekar
2024-10-16 19:21 ` [PATCH 1/2] tst-faccessat.c: Port to libsupport Siddhesh Poyarekar
@ 2024-10-16 19:21 ` Siddhesh Poyarekar
2024-11-06 15:09 ` Adhemerval Zanella Netto
2024-11-06 13:14 ` [ping1][PATCH 0/2] faccessat test improvements Siddhesh Poyarekar
` (4 subsequent siblings)
6 siblings, 1 reply; 16+ messages in thread
From: Siddhesh Poyarekar @ 2024-10-16 19:21 UTC (permalink / raw)
To: libc-alpha; +Cc: carlos
Add a new test tst-faccessat-setuid that iterates through real and
effective UID/GID combination and tests the faccessat() interface for
default and AT_EACCESS flags.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
---
io/Makefile | 4 +
io/tst-faccessat-setuid.c | 163 ++++++++++++++++++++++++++++++++++++++
2 files changed, 167 insertions(+)
create mode 100644 io/tst-faccessat-setuid.c
diff --git a/io/Makefile b/io/Makefile
index a8d575e9ce..3ae26a5aa3 100644
--- a/io/Makefile
+++ b/io/Makefile
@@ -232,6 +232,10 @@ tests := \
tst-utimes \
# tests
+xtests := \
+ tst-faccessat-setuid \
+ #xtests
+
tests-time64 := \
tst-fcntl-time64 \
tst-fts-time64 \
diff --git a/io/tst-faccessat-setuid.c b/io/tst-faccessat-setuid.c
new file mode 100644
index 0000000000..aab0261914
--- /dev/null
+++ b/io/tst-faccessat-setuid.c
@@ -0,0 +1,163 @@
+/* Smoke test for faccessat with different UID/GID combinations. Needs root
+ access.
+ Copyright The GNU Toolchain Authors.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <pwd.h>
+
+#include <support/check.h>
+#include <support/namespace.h>
+#include <support/support.h>
+#include <support/temp_file.h>
+#include <support/test-driver.h>
+#include <support/xdirent.h>
+#include <support/xunistd.h>
+
+#define SOMEFILE "some-file"
+
+static int dir_fd;
+uid_t users[3];
+gid_t groups[3];
+
+struct test_case
+{
+ int mode;
+ uid_t uid;
+ uid_t euid;
+ gid_t gid;
+ gid_t egid;
+ int flags;
+ bool succeeds;
+};
+
+static void
+run_one_test_child (void *in)
+{
+ struct test_case *t = (struct test_case *) in;
+
+ printf ("TEST: MODE=%s, UID=%d, EUID=%d, GID=%d, EGID=%d, FLAGS=%s: ",
+ t->mode == R_OK ? "R_OK" : "W_OK", t->uid, t->euid, t->gid, t->egid,
+ t->flags ? "AT_EACCESS" : "0");
+
+ if (setregid (t->gid, t->egid) != 0)
+ FAIL_EXIT1 ("Could not change group: %m\n");
+ if (setreuid (t->uid, t->euid) != 0)
+ FAIL_EXIT1 ("Could not change user: %m\n");
+
+ if (faccessat (dir_fd, SOMEFILE, t->mode, t->flags) != 0 && t->succeeds)
+ FAIL_EXIT1 ("faccessat failed: %m\n");
+
+ if (!t->succeeds && errno != EACCES)
+ FAIL_EXIT1 ("Unexpected faccessat failure: %m\n");
+
+ printf ("OK%s\n", !t->succeeds ? " (FAILED with EACCES)" : "");
+}
+
+static void
+run_one_test (int mode, int u, int eu, int g, int eg, int flags, bool succeeds)
+{
+ struct test_case t =
+ {mode, users[u], users[eu], groups[g], groups[eg], flags, succeeds};
+ support_isolate_in_subprocess (run_one_test_child, &t);
+}
+
+static int
+do_test (void)
+{
+
+ /* We need to start as root. */
+ if (getuid () != 0)
+ FAIL_UNSUPPORTED ("Test needs to be run as root (UID 0)\n");
+
+ /* Collect 3 distinct users and groups to test with. */
+ struct passwd *ent = NULL;
+ int count = 0;
+ while ((ent = getpwent ()) != NULL && count < 3)
+ {
+ if (ent->pw_uid == 0 || ent->pw_gid == 0)
+ continue;
+
+ int i = count;
+ bool skip = false;
+ while (i > 0)
+ if (groups[--i] == ent->pw_gid)
+ skip = true;
+
+ if (skip)
+ continue;
+
+ users[count] = ent->pw_uid;
+ groups[count++] = ent->pw_gid;
+ }
+
+ if (count < 3)
+ FAIL_UNSUPPORTED ("Not enough users in the system to do this test\n");
+
+ printf ("Testing with UID/GID:\n");
+ while (--count >= 0)
+ printf (" UID: %d, GID: %d\n", users[count], groups[count]);
+ printf ("\n");
+
+ char *tempdir = support_create_temp_directory ("tst-faccessat-setuid.");
+ dir_fd = xopen (tempdir, O_RDONLY | O_DIRECTORY, 0);
+
+ xfchmod (dir_fd, 0777);
+
+ /* Now, create a file in it, which will be our test case. */
+
+ int fd = openat (dir_fd, SOMEFILE, O_CREAT|O_RDWR|O_EXCL, 0640);
+ if (fd == -1)
+ {
+ if (errno == ENOSYS)
+ FAIL_UNSUPPORTED ("*at functions not supported");
+
+ FAIL_EXIT1 ("file creation failed");
+ }
+ xwrite (fd, "hello", 5);
+
+ if (fchown (fd, users[0], groups[1]) == -1)
+ FAIL_EXIT1 ("fchown failed: %m\n");
+ xclose (fd);
+
+ char *somefile = xasprintf ("%s/" SOMEFILE, tempdir);
+ add_temp_file (somefile);
+
+ /* Finally, run through the combinations. */
+ for (int u = 0; u < 3; u++)
+ for (int eu = 0; eu < 3; eu++)
+ for (int g = 0; g < 3; g++)
+ for (int eg = 0; eg < 3; eg++)
+ {
+ run_one_test (R_OK, u, eu, g, eg, 0, u == 0 || g == 1);
+ run_one_test (W_OK, u, eu, g, eg, 0, u == 0);
+ run_one_test (R_OK, u, eu, g, eg, AT_EACCESS, eu == 0 || eg == 1);
+ run_one_test (W_OK, u, eu, g, eg, AT_EACCESS, eu == 0);
+ }
+
+ xclose (dir_fd);
+ free (tempdir);
+ free (somefile);
+
+ return 0;
+}
+#include <support/test-driver.c>
--
2.46.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [ping1][PATCH 0/2] faccessat test improvements
2024-10-16 19:21 [PATCH 0/2] faccessat test improvements Siddhesh Poyarekar
2024-10-16 19:21 ` [PATCH 1/2] tst-faccessat.c: Port to libsupport Siddhesh Poyarekar
2024-10-16 19:21 ` [PATCH 2/2] io: Add setuid tests for faccessat Siddhesh Poyarekar
@ 2024-11-06 13:14 ` Siddhesh Poyarekar
2024-11-08 17:45 ` [PATCH v2 0/3] " Siddhesh Poyarekar
` (3 subsequent siblings)
6 siblings, 0 replies; 16+ messages in thread
From: Siddhesh Poyarekar @ 2024-11-06 13:14 UTC (permalink / raw)
To: libc-alpha; +Cc: carlos
Ping!
On 2024-10-16 15:21, Siddhesh Poyarekar wrote:
> Cleaned up current test for faccessat and added an xtest to verify
> behaviour with different real and effective user/group combinations.
>
> Siddhesh Poyarekar (2):
> tst-faccessat.c: Port to libsupport
> io: Add setuid tests for faccessat
>
> io/Makefile | 4 +
> io/tst-faccessat-setuid.c | 163 ++++++++++++++++++++++++++++
> io/tst-faccessat.c | 219 +++++++++++---------------------------
> support/Makefile | 1 +
> support/xdup.c | 30 ++++++
> support/xunistd.h | 1 +
> 6 files changed, 262 insertions(+), 156 deletions(-)
> create mode 100644 io/tst-faccessat-setuid.c
> create mode 100644 support/xdup.c
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 1/2] tst-faccessat.c: Port to libsupport
2024-10-16 19:21 ` [PATCH 1/2] tst-faccessat.c: Port to libsupport Siddhesh Poyarekar
@ 2024-11-06 15:08 ` Adhemerval Zanella Netto
2024-11-06 15:11 ` Siddhesh Poyarekar
0 siblings, 1 reply; 16+ messages in thread
From: Adhemerval Zanella Netto @ 2024-11-06 15:08 UTC (permalink / raw)
To: Siddhesh Poyarekar, libc-alpha; +Cc: carlos
On 16/10/24 16:21, Siddhesh Poyarekar wrote:
> Use libsupport convenience functions and macros instead of the old
> test-skeleton. Also add a new xdup() convenience wrapper function.
>
> Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
LGTM, some minor comments below.
> ---
> io/tst-faccessat.c | 219 +++++++++++++--------------------------------
> support/Makefile | 1 +
> support/xdup.c | 30 +++++++
> support/xunistd.h | 1 +
> 4 files changed, 95 insertions(+), 156 deletions(-)
> create mode 100644 support/xdup.c
>
> diff --git a/io/tst-faccessat.c b/io/tst-faccessat.c
> index b90954e318..609cdddaf7 100644
> --- a/io/tst-faccessat.c
> +++ b/io/tst-faccessat.c
> @@ -1,6 +1,23 @@
> -/* Test for faccessat function. */
> -
> -#include <dirent.h>
> +/* Test for faccessat function.
> + Copyright (C) 2006-2024 Free Software Foundation, Inc.
> + Copyright The GNU Toolchain Authors.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library 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
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, see
> + <https://www.gnu.org/licenses/>. */
> +
> +#include <errno.h>
> #include <fcntl.h>
> #include <stdio.h>
> #include <stdlib.h>
> @@ -8,47 +25,19 @@
> #include <unistd.h>
> #include <sys/stat.h>
>
> +#include <support/check.h>
> +#include <support/temp_file.h>
> +#include <support/test-driver.h>
> +#include <support/xdirent.h>
> #include <support/xunistd.h>
>
> -static void prepare (void);
> -#define PREPARE(argc, argv) prepare ()
> -
> -static int do_test (void);
> -#define TEST_FUNCTION do_test ()
> -
> -#include "../test-skeleton.c"
> -
> static int dir_fd;
>
> static void
> -prepare (void)
> +prepare (int argc, char **argv)
> {
> - size_t test_dir_len = strlen (test_dir);
> - static const char dir_name[] = "/tst-faccessat.XXXXXX";
> -
> - size_t dirbuflen = test_dir_len + sizeof (dir_name);
> - char *dirbuf = malloc (dirbuflen);
> - if (dirbuf == NULL)
> - {
> - puts ("out of memory");
> - exit (1);
> - }
> -
> - snprintf (dirbuf, dirbuflen, "%s%s", test_dir, dir_name);
> - if (mkdtemp (dirbuf) == NULL)
> - {
> - puts ("cannot create temporary directory");
> - exit (1);
> - }
> -
> - add_temp_file (dirbuf);
> -
> - dir_fd = open (dirbuf, O_RDONLY | O_DIRECTORY);
> - if (dir_fd == -1)
> - {
> - puts ("cannot open directory");
> - exit (1);
> - }
> + dir_fd = xopen (support_create_temp_directory ("tst-faccessat."),
> + O_RDONLY | O_DIRECTORY, 0);
> }
>
>
> @@ -56,159 +45,77 @@ static int
> do_test (void)
> {
> /* fdopendir takes over the descriptor, make a copy. */
> - int dupfd = dup (dir_fd);
> - if (dupfd == -1)
> - {
> - puts ("dup failed");
> - return 1;
> - }
> - if (lseek (dupfd, 0, SEEK_SET) != 0)
> - {
> - puts ("1st lseek failed");
> - return 1;
> - }
> + int dupfd = xdup (dir_fd);
> + xlseek (dupfd, 0, SEEK_SET);
>
> /* The directory should be empty save the . and .. files. */
> - DIR *dir = fdopendir (dupfd);
> - if (dir == NULL)
> - {
> - puts ("fdopendir failed");
> - return 1;
> - }
> + DIR *dir = xfdopendir (dupfd);
> +
> struct dirent64 *d;
> - while ((d = readdir64 (dir)) != NULL)
> + while ((d = xreaddir64 (dir)) != NULL)
> if (strcmp (d->d_name, ".") != 0 && strcmp (d->d_name, "..") != 0)
> - {
> - printf ("temp directory contains file \"%s\"\n", d->d_name);
> - return 1;
> - }
> - closedir (dir);
> + FAIL_EXIT1 ("temp directory contains file \"%s\"\n", d->d_name);
> + xclosedir (dir);
>
> /* Try to create a file. */
> int fd = openat (dir_fd, "some-file", O_CREAT|O_RDWR|O_EXCL, 0666);
> if (fd == -1)
> {
> if (errno == ENOSYS)
> - {
> - puts ("*at functions not supported");
> - return 0;
> - }
> + FAIL_UNSUPPORTED ("*at functions not supported");
>
> - puts ("file creation failed");
> - return 1;
> + FAIL_EXIT1 ("file creation failed");
> }
> xwrite (fd, "hello", 5);
> puts ("file created");
>
> /* Before closing the file, try using this file descriptor to open
> another file. This must fail. */
> - if (faccessat (fd, "should-not-work", F_OK, AT_EACCESS) != -1)
> - {
> - puts ("faccessat using descriptor for normal file worked");
> - return 1;
> - }
> - if (errno != ENOTDIR)
> - {
> - puts ("\
> -error for faccessat using descriptor for normal file not ENOTDIR ");
> - return 1;
> - }
> -
> - close (fd);
> + TEST_VERIFY_EXIT (faccessat (fd, "should-not-work", F_OK, AT_EACCESS) == -1);
> + TEST_VERIFY_EXIT (errno == ENOTDIR);
>
> - int result = 0;
> + xclose (fd);
>
> - if (faccessat (dir_fd, "some-file", F_OK, AT_EACCESS))
> - {
> - printf ("faccessat F_OK: %m\n");
> - result = 1;
> - }
> - if (faccessat (dir_fd, "some-file", W_OK, AT_EACCESS))
> - {
> - printf ("faccessat W_OK: %m\n");
> - result = 1;
> - }
> + TEST_VERIFY (faccessat (dir_fd, "some-file", F_OK, AT_EACCESS) == 0);
> + TEST_VERIFY (faccessat (dir_fd, "some-file", W_OK, AT_EACCESS) == 0);
>
> errno = 0;
> - if (faccessat (dir_fd, "some-file", X_OK, AT_EACCESS) == 0
> - || errno != EACCES)
> - {
> - printf ("faccessat X_OK on nonexecutable: %m\n");
> - result = 1;
> - }
> + TEST_VERIFY (faccessat (dir_fd, "some-file", X_OK, AT_EACCESS) != 0
> + && errno == EACCES);
Maybe move the errno to a different TEST_VERIFY, so on a possibly failure
it would be easier to sort out what has failed.
>
> if (fchmodat (dir_fd, "some-file", 0400, 0) != 0)
> - {
> - printf ("fchownat failed: %m\n");
> - return 1;
> - }
> + FAIL_EXIT1 ("fchownat failed: %m\n");
>
> - if (faccessat (dir_fd, "some-file", R_OK, AT_EACCESS))
> - {
> - printf ("faccessat R_OK: %m\n");
> - result = 1;
> - }
> + TEST_VERIFY (faccessat (dir_fd, "some-file", R_OK, AT_EACCESS) == 0);
>
> + /* Write would succeed only for EUID root, otherwise this test should
> + fail. */
> errno = 0;
> - if (faccessat (dir_fd, "some-file", W_OK, AT_EACCESS) == 0
> - ? (geteuid () != 0) : (errno != EACCES))
> - {
> - printf ("faccessat W_OK on unwritable file: %m\n");
> - result = 1;
> - }
> + TEST_VERIFY (faccessat (dir_fd, "some-file", W_OK, AT_EACCESS) == 0
> + ? (geteuid () == 0) : (errno == EACCES));
>
> /* Create a file descriptor which is closed again right away. */
> - int dir_fd2 = dup (dir_fd);
> - if (dir_fd2 == -1)
> - {
> - puts ("dup failed");
> - return 1;
> - }
> + int dir_fd2 = xdup (dir_fd);
> close (dir_fd2);
>
> /* With the file descriptor closed the next call must fail. */
> - if (faccessat (dir_fd2, "some-file", F_OK, AT_EACCESS) != -1)
> - {
> - puts ("faccessat using closed descriptor succeeded");
> - return 1;
> - }
> - if (errno != EBADF)
> - {
> - puts ("faccessat using closed descriptor did not set EBADF");
> - return 1;
> - }
> + TEST_VERIFY_EXIT (faccessat (dir_fd2, "some-file", F_OK, AT_EACCESS)
> + == -1);
> + TEST_VERIFY_EXIT (errno == EBADF);
>
> /* Same with a non-existing file. */
> - if (faccessat (dir_fd2, "non-existing-file", F_OK, AT_EACCESS) != -1)
> - {
> - puts ("2nd faccessat using closed descriptor succeeded");
> - return 1;
> - }
> - if (errno != EBADF)
> - {
> - puts ("2nd faccessat using closed descriptor did not set EBADF");
> - return 1;
> - }
> + TEST_VERIFY_EXIT (faccessat (dir_fd2, "non-existing-file", F_OK, AT_EACCESS)
> + == -1);
> + TEST_VERIFY_EXIT (errno == EBADF);
>
> - if (unlinkat (dir_fd, "some-file", 0) != 0)
> - {
> - puts ("unlinkat failed");
> - result = 1;
> - }
> + TEST_VERIFY (unlinkat (dir_fd, "some-file", 0) == 0);
>
> - close (dir_fd);
> + xclose (dir_fd);
>
> - fd = faccessat (-1, "some-file", F_OK, AT_EACCESS);
> - if (fd != -1)
> - {
> - puts ("faccessat using -1 descriptor succeeded");
> - return 1;
> - }
> - if (errno != EBADF)
> - {
> - puts ("faccessat using -1 descriptor did not set EBADF");
> - return 1;
> - }
> + TEST_VERIFY_EXIT (faccessat (-1, "some-file", F_OK, AT_EACCESS) == -1);
> + TEST_VERIFY_EXIT (errno == EBADF);
>
> - return result;
> + return 0;
> }
> +#define PREPARE prepare
> +#include <support/test-driver.c>
> diff --git a/support/Makefile b/support/Makefile
> index 84e2419775..099f5ebb9c 100644
> --- a/support/Makefile
> +++ b/support/Makefile
> @@ -128,6 +128,7 @@ libsupport-routines = \
> xcopy_file_range \
> xdlfcn \
> xdlmopen \
> + xdup \
> xdup2 \
> xfchmod \
> xfclose \
> diff --git a/support/xdup.c b/support/xdup.c
> new file mode 100644
> index 0000000000..1eab317354
> --- /dev/null
> +++ b/support/xdup.c
> @@ -0,0 +1,30 @@
> +/* dup with error checking.
> + Copyright The GNU Toolchain Authors.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library 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
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, see
> + <https://www.gnu.org/licenses/>. */
> +
> +#include <support/xunistd.h>
> +#include <support/check.h>
> +
> +int
> +xdup (int from)
> +{
> + int ret = dup (from);
> + if (ret < 0)
> + FAIL_EXIT1 ("dup (%d): %m", from);
> +
> + return ret;
> +}
> diff --git a/support/xunistd.h b/support/xunistd.h
> index 204951bce7..0c6d837ac0 100644
> --- a/support/xunistd.h
> +++ b/support/xunistd.h
> @@ -35,6 +35,7 @@ pid_t xfork (void);
> pid_t xwaitpid (pid_t, int *status, int flags);
> void xpipe (int[2]);
> void xdup2 (int, int);
> +int xdup (int);
> int xopen (const char *path, int flags, mode_t);
> void support_check_stat_fd (const char *name, int fd, int result);
> void support_check_stat_path (const char *name, const char *path, int result);
I think the usual way is to add libsupport additions in a different
patch, so backports would be easier.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 2/2] io: Add setuid tests for faccessat
2024-10-16 19:21 ` [PATCH 2/2] io: Add setuid tests for faccessat Siddhesh Poyarekar
@ 2024-11-06 15:09 ` Adhemerval Zanella Netto
2024-11-06 15:13 ` Siddhesh Poyarekar
0 siblings, 1 reply; 16+ messages in thread
From: Adhemerval Zanella Netto @ 2024-11-06 15:09 UTC (permalink / raw)
To: Siddhesh Poyarekar, libc-alpha; +Cc: carlos
On 16/10/24 16:21, Siddhesh Poyarekar wrote:
> Add a new test tst-faccessat-setuid that iterates through real and
> effective UID/GID combination and tests the faccessat() interface for
> default and AT_EACCESS flags.
>
> Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
> ---
> io/Makefile | 4 +
> io/tst-faccessat-setuid.c | 163 ++++++++++++++++++++++++++++++++++++++
> 2 files changed, 167 insertions(+)
> create mode 100644 io/tst-faccessat-setuid.c
>
> diff --git a/io/Makefile b/io/Makefile
> index a8d575e9ce..3ae26a5aa3 100644
> --- a/io/Makefile
> +++ b/io/Makefile
> @@ -232,6 +232,10 @@ tests := \
> tst-utimes \
> # tests
>
> +xtests := \
> + tst-faccessat-setuid \
> + #xtests
> +
Can't we use support_become_root and make it a container test? It became
moot to add a new xtests, since it is not usually tested on make check
and not everyone knows about the make xcheck.
> tests-time64 := \
> tst-fcntl-time64 \
> tst-fts-time64 \
> diff --git a/io/tst-faccessat-setuid.c b/io/tst-faccessat-setuid.c
> new file mode 100644
> index 0000000000..aab0261914
> --- /dev/null
> +++ b/io/tst-faccessat-setuid.c
> @@ -0,0 +1,163 @@
> +/* Smoke test for faccessat with different UID/GID combinations. Needs root
> + access.
> + Copyright The GNU Toolchain Authors.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library 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
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, see
> + <https://www.gnu.org/licenses/>. */
> +
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <sys/types.h>
> +#include <pwd.h>
> +
> +#include <support/check.h>
> +#include <support/namespace.h>
> +#include <support/support.h>
> +#include <support/temp_file.h>
> +#include <support/test-driver.h>
> +#include <support/xdirent.h>
> +#include <support/xunistd.h>
> +
> +#define SOMEFILE "some-file"
> +
> +static int dir_fd;
> +uid_t users[3];
> +gid_t groups[3];
> +
> +struct test_case
> +{
> + int mode;
> + uid_t uid;
> + uid_t euid;
> + gid_t gid;
> + gid_t egid;
> + int flags;
> + bool succeeds;
> +};
> +
> +static void
> +run_one_test_child (void *in)
> +{
> + struct test_case *t = (struct test_case *) in;
> +
> + printf ("TEST: MODE=%s, UID=%d, EUID=%d, GID=%d, EGID=%d, FLAGS=%s: ",
> + t->mode == R_OK ? "R_OK" : "W_OK", t->uid, t->euid, t->gid, t->egid,
> + t->flags ? "AT_EACCESS" : "0");
> +
> + if (setregid (t->gid, t->egid) != 0)
> + FAIL_EXIT1 ("Could not change group: %m\n");
> + if (setreuid (t->uid, t->euid) != 0)
> + FAIL_EXIT1 ("Could not change user: %m\n");
> +
> + if (faccessat (dir_fd, SOMEFILE, t->mode, t->flags) != 0 && t->succeeds)
> + FAIL_EXIT1 ("faccessat failed: %m\n");
> +
> + if (!t->succeeds && errno != EACCES)
> + FAIL_EXIT1 ("Unexpected faccessat failure: %m\n");
> +
> + printf ("OK%s\n", !t->succeeds ? " (FAILED with EACCES)" : "");
> +}
> +
> +static void
> +run_one_test (int mode, int u, int eu, int g, int eg, int flags, bool succeeds)
> +{
> + struct test_case t =
> + {mode, users[u], users[eu], groups[g], groups[eg], flags, succeeds};
> + support_isolate_in_subprocess (run_one_test_child, &t);
> +}
> +
> +static int
> +do_test (void)
> +{
> +
> + /* We need to start as root. */
> + if (getuid () != 0)
> + FAIL_UNSUPPORTED ("Test needs to be run as root (UID 0)\n");
> +
> + /* Collect 3 distinct users and groups to test with. */
> + struct passwd *ent = NULL;
> + int count = 0;
> + while ((ent = getpwent ()) != NULL && count < 3)
> + {
> + if (ent->pw_uid == 0 || ent->pw_gid == 0)
> + continue;
> +
> + int i = count;
> + bool skip = false;
> + while (i > 0)
> + if (groups[--i] == ent->pw_gid)
> + skip = true;
> +
> + if (skip)
> + continue;
> +
> + users[count] = ent->pw_uid;
> + groups[count++] = ent->pw_gid;
> + }
> +
> + if (count < 3)
> + FAIL_UNSUPPORTED ("Not enough users in the system to do this test\n");
> +
> + printf ("Testing with UID/GID:\n");
> + while (--count >= 0)
> + printf (" UID: %d, GID: %d\n", users[count], groups[count]);
> + printf ("\n");
> +
> + char *tempdir = support_create_temp_directory ("tst-faccessat-setuid.");
> + dir_fd = xopen (tempdir, O_RDONLY | O_DIRECTORY, 0);
> +
> + xfchmod (dir_fd, 0777);
> +
> + /* Now, create a file in it, which will be our test case. */
> +
> + int fd = openat (dir_fd, SOMEFILE, O_CREAT|O_RDWR|O_EXCL, 0640);
> + if (fd == -1)
> + {
> + if (errno == ENOSYS)
> + FAIL_UNSUPPORTED ("*at functions not supported");
> +
> + FAIL_EXIT1 ("file creation failed");
> + }
> + xwrite (fd, "hello", 5);
> +
> + if (fchown (fd, users[0], groups[1]) == -1)
> + FAIL_EXIT1 ("fchown failed: %m\n");
> + xclose (fd);
> +
> + char *somefile = xasprintf ("%s/" SOMEFILE, tempdir);
> + add_temp_file (somefile);
> +
> + /* Finally, run through the combinations. */
> + for (int u = 0; u < 3; u++)
> + for (int eu = 0; eu < 3; eu++)
> + for (int g = 0; g < 3; g++)
> + for (int eg = 0; eg < 3; eg++)
> + {
> + run_one_test (R_OK, u, eu, g, eg, 0, u == 0 || g == 1);
> + run_one_test (W_OK, u, eu, g, eg, 0, u == 0);
> + run_one_test (R_OK, u, eu, g, eg, AT_EACCESS, eu == 0 || eg == 1);
> + run_one_test (W_OK, u, eu, g, eg, AT_EACCESS, eu == 0);
> + }
> +
> + xclose (dir_fd);
> + free (tempdir);
> + free (somefile);
> +
> + return 0;
> +}
> +#include <support/test-driver.c>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 1/2] tst-faccessat.c: Port to libsupport
2024-11-06 15:08 ` Adhemerval Zanella Netto
@ 2024-11-06 15:11 ` Siddhesh Poyarekar
0 siblings, 0 replies; 16+ messages in thread
From: Siddhesh Poyarekar @ 2024-11-06 15:11 UTC (permalink / raw)
To: Adhemerval Zanella Netto, libc-alpha; +Cc: carlos
On 2024-11-06 10:08, Adhemerval Zanella Netto wrote:
>
>
> On 16/10/24 16:21, Siddhesh Poyarekar wrote:
>> Use libsupport convenience functions and macros instead of the old
>> test-skeleton. Also add a new xdup() convenience wrapper function.
>>
>> Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
>
> LGTM, some minor comments below.
>
>> ---
>> io/tst-faccessat.c | 219 +++++++++++++--------------------------------
>> support/Makefile | 1 +
>> support/xdup.c | 30 +++++++
>> support/xunistd.h | 1 +
>> 4 files changed, 95 insertions(+), 156 deletions(-)
>> create mode 100644 support/xdup.c
>>
>> diff --git a/io/tst-faccessat.c b/io/tst-faccessat.c
>> index b90954e318..609cdddaf7 100644
>> --- a/io/tst-faccessat.c
>> +++ b/io/tst-faccessat.c
>> @@ -1,6 +1,23 @@
>> -/* Test for faccessat function. */
>> -
>> -#include <dirent.h>
>> +/* Test for faccessat function.
>> + Copyright (C) 2006-2024 Free Software Foundation, Inc.
>> + Copyright The GNU Toolchain Authors.
>> + This file is part of the GNU C Library.
>> +
>> + The GNU C Library is free software; you can redistribute it and/or
>> + modify it under the terms of the GNU Lesser General Public
>> + License as published by the Free Software Foundation; either
>> + version 2.1 of the License, or (at your option) any later version.
>> +
>> + The GNU C Library 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
>> + Lesser General Public License for more details.
>> +
>> + You should have received a copy of the GNU Lesser General Public
>> + License along with the GNU C Library; if not, see
>> + <https://www.gnu.org/licenses/>. */
>> +
>> +#include <errno.h>
>> #include <fcntl.h>
>> #include <stdio.h>
>> #include <stdlib.h>
>> @@ -8,47 +25,19 @@
>> #include <unistd.h>
>> #include <sys/stat.h>
>>
>> +#include <support/check.h>
>> +#include <support/temp_file.h>
>> +#include <support/test-driver.h>
>> +#include <support/xdirent.h>
>> #include <support/xunistd.h>
>>
>> -static void prepare (void);
>> -#define PREPARE(argc, argv) prepare ()
>> -
>> -static int do_test (void);
>> -#define TEST_FUNCTION do_test ()
>> -
>> -#include "../test-skeleton.c"
>> -
>> static int dir_fd;
>>
>> static void
>> -prepare (void)
>> +prepare (int argc, char **argv)
>> {
>> - size_t test_dir_len = strlen (test_dir);
>> - static const char dir_name[] = "/tst-faccessat.XXXXXX";
>> -
>> - size_t dirbuflen = test_dir_len + sizeof (dir_name);
>> - char *dirbuf = malloc (dirbuflen);
>> - if (dirbuf == NULL)
>> - {
>> - puts ("out of memory");
>> - exit (1);
>> - }
>> -
>> - snprintf (dirbuf, dirbuflen, "%s%s", test_dir, dir_name);
>> - if (mkdtemp (dirbuf) == NULL)
>> - {
>> - puts ("cannot create temporary directory");
>> - exit (1);
>> - }
>> -
>> - add_temp_file (dirbuf);
>> -
>> - dir_fd = open (dirbuf, O_RDONLY | O_DIRECTORY);
>> - if (dir_fd == -1)
>> - {
>> - puts ("cannot open directory");
>> - exit (1);
>> - }
>> + dir_fd = xopen (support_create_temp_directory ("tst-faccessat."),
>> + O_RDONLY | O_DIRECTORY, 0);
>> }
>>
>>
>> @@ -56,159 +45,77 @@ static int
>> do_test (void)
>> {
>> /* fdopendir takes over the descriptor, make a copy. */
>> - int dupfd = dup (dir_fd);
>> - if (dupfd == -1)
>> - {
>> - puts ("dup failed");
>> - return 1;
>> - }
>> - if (lseek (dupfd, 0, SEEK_SET) != 0)
>> - {
>> - puts ("1st lseek failed");
>> - return 1;
>> - }
>> + int dupfd = xdup (dir_fd);
>> + xlseek (dupfd, 0, SEEK_SET);
>>
>> /* The directory should be empty save the . and .. files. */
>> - DIR *dir = fdopendir (dupfd);
>> - if (dir == NULL)
>> - {
>> - puts ("fdopendir failed");
>> - return 1;
>> - }
>> + DIR *dir = xfdopendir (dupfd);
>> +
>> struct dirent64 *d;
>> - while ((d = readdir64 (dir)) != NULL)
>> + while ((d = xreaddir64 (dir)) != NULL)
>> if (strcmp (d->d_name, ".") != 0 && strcmp (d->d_name, "..") != 0)
>> - {
>> - printf ("temp directory contains file \"%s\"\n", d->d_name);
>> - return 1;
>> - }
>> - closedir (dir);
>> + FAIL_EXIT1 ("temp directory contains file \"%s\"\n", d->d_name);
>> + xclosedir (dir);
>>
>> /* Try to create a file. */
>> int fd = openat (dir_fd, "some-file", O_CREAT|O_RDWR|O_EXCL, 0666);
>> if (fd == -1)
>> {
>> if (errno == ENOSYS)
>> - {
>> - puts ("*at functions not supported");
>> - return 0;
>> - }
>> + FAIL_UNSUPPORTED ("*at functions not supported");
>>
>> - puts ("file creation failed");
>> - return 1;
>> + FAIL_EXIT1 ("file creation failed");
>> }
>> xwrite (fd, "hello", 5);
>> puts ("file created");
>>
>> /* Before closing the file, try using this file descriptor to open
>> another file. This must fail. */
>> - if (faccessat (fd, "should-not-work", F_OK, AT_EACCESS) != -1)
>> - {
>> - puts ("faccessat using descriptor for normal file worked");
>> - return 1;
>> - }
>> - if (errno != ENOTDIR)
>> - {
>> - puts ("\
>> -error for faccessat using descriptor for normal file not ENOTDIR ");
>> - return 1;
>> - }
>> -
>> - close (fd);
>> + TEST_VERIFY_EXIT (faccessat (fd, "should-not-work", F_OK, AT_EACCESS) == -1);
>> + TEST_VERIFY_EXIT (errno == ENOTDIR);
>>
>> - int result = 0;
>> + xclose (fd);
>>
>> - if (faccessat (dir_fd, "some-file", F_OK, AT_EACCESS))
>> - {
>> - printf ("faccessat F_OK: %m\n");
>> - result = 1;
>> - }
>> - if (faccessat (dir_fd, "some-file", W_OK, AT_EACCESS))
>> - {
>> - printf ("faccessat W_OK: %m\n");
>> - result = 1;
>> - }
>> + TEST_VERIFY (faccessat (dir_fd, "some-file", F_OK, AT_EACCESS) == 0);
>> + TEST_VERIFY (faccessat (dir_fd, "some-file", W_OK, AT_EACCESS) == 0);
>>
>> errno = 0;
>> - if (faccessat (dir_fd, "some-file", X_OK, AT_EACCESS) == 0
>> - || errno != EACCES)
>> - {
>> - printf ("faccessat X_OK on nonexecutable: %m\n");
>> - result = 1;
>> - }
>> + TEST_VERIFY (faccessat (dir_fd, "some-file", X_OK, AT_EACCESS) != 0
>> + && errno == EACCES);
>
> Maybe move the errno to a different TEST_VERIFY, so on a possibly failure
> it would be easier to sort out what has failed.
OK.
>>
>> if (fchmodat (dir_fd, "some-file", 0400, 0) != 0)
>> - {
>> - printf ("fchownat failed: %m\n");
>> - return 1;
>> - }
>> + FAIL_EXIT1 ("fchownat failed: %m\n");
>>
>> - if (faccessat (dir_fd, "some-file", R_OK, AT_EACCESS))
>> - {
>> - printf ("faccessat R_OK: %m\n");
>> - result = 1;
>> - }
>> + TEST_VERIFY (faccessat (dir_fd, "some-file", R_OK, AT_EACCESS) == 0);
>>
>> + /* Write would succeed only for EUID root, otherwise this test should
>> + fail. */
>> errno = 0;
>> - if (faccessat (dir_fd, "some-file", W_OK, AT_EACCESS) == 0
>> - ? (geteuid () != 0) : (errno != EACCES))
>> - {
>> - printf ("faccessat W_OK on unwritable file: %m\n");
>> - result = 1;
>> - }
>> + TEST_VERIFY (faccessat (dir_fd, "some-file", W_OK, AT_EACCESS) == 0
>> + ? (geteuid () == 0) : (errno == EACCES));
>>
>> /* Create a file descriptor which is closed again right away. */
>> - int dir_fd2 = dup (dir_fd);
>> - if (dir_fd2 == -1)
>> - {
>> - puts ("dup failed");
>> - return 1;
>> - }
>> + int dir_fd2 = xdup (dir_fd);
>> close (dir_fd2);
>>
>> /* With the file descriptor closed the next call must fail. */
>> - if (faccessat (dir_fd2, "some-file", F_OK, AT_EACCESS) != -1)
>> - {
>> - puts ("faccessat using closed descriptor succeeded");
>> - return 1;
>> - }
>> - if (errno != EBADF)
>> - {
>> - puts ("faccessat using closed descriptor did not set EBADF");
>> - return 1;
>> - }
>> + TEST_VERIFY_EXIT (faccessat (dir_fd2, "some-file", F_OK, AT_EACCESS)
>> + == -1);
>> + TEST_VERIFY_EXIT (errno == EBADF);
>>
>> /* Same with a non-existing file. */
>> - if (faccessat (dir_fd2, "non-existing-file", F_OK, AT_EACCESS) != -1)
>> - {
>> - puts ("2nd faccessat using closed descriptor succeeded");
>> - return 1;
>> - }
>> - if (errno != EBADF)
>> - {
>> - puts ("2nd faccessat using closed descriptor did not set EBADF");
>> - return 1;
>> - }
>> + TEST_VERIFY_EXIT (faccessat (dir_fd2, "non-existing-file", F_OK, AT_EACCESS)
>> + == -1);
>> + TEST_VERIFY_EXIT (errno == EBADF);
>>
>> - if (unlinkat (dir_fd, "some-file", 0) != 0)
>> - {
>> - puts ("unlinkat failed");
>> - result = 1;
>> - }
>> + TEST_VERIFY (unlinkat (dir_fd, "some-file", 0) == 0);
>>
>> - close (dir_fd);
>> + xclose (dir_fd);
>>
>> - fd = faccessat (-1, "some-file", F_OK, AT_EACCESS);
>> - if (fd != -1)
>> - {
>> - puts ("faccessat using -1 descriptor succeeded");
>> - return 1;
>> - }
>> - if (errno != EBADF)
>> - {
>> - puts ("faccessat using -1 descriptor did not set EBADF");
>> - return 1;
>> - }
>> + TEST_VERIFY_EXIT (faccessat (-1, "some-file", F_OK, AT_EACCESS) == -1);
>> + TEST_VERIFY_EXIT (errno == EBADF);
>>
>> - return result;
>> + return 0;
>> }
>> +#define PREPARE prepare
>> +#include <support/test-driver.c>
>> diff --git a/support/Makefile b/support/Makefile
>> index 84e2419775..099f5ebb9c 100644
>> --- a/support/Makefile
>> +++ b/support/Makefile
>> @@ -128,6 +128,7 @@ libsupport-routines = \
>> xcopy_file_range \
>> xdlfcn \
>> xdlmopen \
>> + xdup \
>> xdup2 \
>> xfchmod \
>> xfclose \
>> diff --git a/support/xdup.c b/support/xdup.c
>> new file mode 100644
>> index 0000000000..1eab317354
>> --- /dev/null
>> +++ b/support/xdup.c
>> @@ -0,0 +1,30 @@
>> +/* dup with error checking.
>> + Copyright The GNU Toolchain Authors.
>> + This file is part of the GNU C Library.
>> +
>> + The GNU C Library is free software; you can redistribute it and/or
>> + modify it under the terms of the GNU Lesser General Public
>> + License as published by the Free Software Foundation; either
>> + version 2.1 of the License, or (at your option) any later version.
>> +
>> + The GNU C Library 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
>> + Lesser General Public License for more details.
>> +
>> + You should have received a copy of the GNU Lesser General Public
>> + License along with the GNU C Library; if not, see
>> + <https://www.gnu.org/licenses/>. */
>> +
>> +#include <support/xunistd.h>
>> +#include <support/check.h>
>> +
>> +int
>> +xdup (int from)
>> +{
>> + int ret = dup (from);
>> + if (ret < 0)
>> + FAIL_EXIT1 ("dup (%d): %m", from);
>> +
>> + return ret;
>> +}
>> diff --git a/support/xunistd.h b/support/xunistd.h
>> index 204951bce7..0c6d837ac0 100644
>> --- a/support/xunistd.h
>> +++ b/support/xunistd.h
>> @@ -35,6 +35,7 @@ pid_t xfork (void);
>> pid_t xwaitpid (pid_t, int *status, int flags);
>> void xpipe (int[2]);
>> void xdup2 (int, int);
>> +int xdup (int);
>> int xopen (const char *path, int flags, mode_t);
>> void support_check_stat_fd (const char *name, int fd, int result);
>> void support_check_stat_path (const char *name, const char *path, int result);
>
> I think the usual way is to add libsupport additions in a different
> patch, so backports would be easier.
>
Ack, I'll split this up.
Thanks,
Sid
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 2/2] io: Add setuid tests for faccessat
2024-11-06 15:09 ` Adhemerval Zanella Netto
@ 2024-11-06 15:13 ` Siddhesh Poyarekar
2024-11-06 17:26 ` Adhemerval Zanella Netto
0 siblings, 1 reply; 16+ messages in thread
From: Siddhesh Poyarekar @ 2024-11-06 15:13 UTC (permalink / raw)
To: Adhemerval Zanella Netto, libc-alpha; +Cc: carlos
On 2024-11-06 10:09, Adhemerval Zanella Netto wrote:
>
>
> On 16/10/24 16:21, Siddhesh Poyarekar wrote:
>> Add a new test tst-faccessat-setuid that iterates through real and
>> effective UID/GID combination and tests the faccessat() interface for
>> default and AT_EACCESS flags.
>>
>> Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
>> ---
>> io/Makefile | 4 +
>> io/tst-faccessat-setuid.c | 163 ++++++++++++++++++++++++++++++++++++++
>> 2 files changed, 167 insertions(+)
>> create mode 100644 io/tst-faccessat-setuid.c
>>
>> diff --git a/io/Makefile b/io/Makefile
>> index a8d575e9ce..3ae26a5aa3 100644
>> --- a/io/Makefile
>> +++ b/io/Makefile
>> @@ -232,6 +232,10 @@ tests := \
>> tst-utimes \
>> # tests
>>
>> +xtests := \
>> + tst-faccessat-setuid \
>> + #xtests
>> +
>
> Can't we use support_become_root and make it a container test? It became
> moot to add a new xtests, since it is not usually tested on make check
> and not everyone knows about the make xcheck.
>
The test needs multiple user and group combinations, which doesn't seem
to be something tests-container can provide. Does it make sense instead
to add this as a `test` and bail out as UNSUPPORTED if it's not run as
root? That way users know that the test is being skipped over, similar
to how we do setuid tests.
Thanks,
Sid
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 2/2] io: Add setuid tests for faccessat
2024-11-06 15:13 ` Siddhesh Poyarekar
@ 2024-11-06 17:26 ` Adhemerval Zanella Netto
0 siblings, 0 replies; 16+ messages in thread
From: Adhemerval Zanella Netto @ 2024-11-06 17:26 UTC (permalink / raw)
To: Siddhesh Poyarekar, libc-alpha; +Cc: carlos
On 06/11/24 12:13, Siddhesh Poyarekar wrote:
> On 2024-11-06 10:09, Adhemerval Zanella Netto wrote:
>>
>>
>> On 16/10/24 16:21, Siddhesh Poyarekar wrote:
>>> Add a new test tst-faccessat-setuid that iterates through real and
>>> effective UID/GID combination and tests the faccessat() interface for
>>> default and AT_EACCESS flags.
>>>
>>> Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
>>> ---
>>> io/Makefile | 4 +
>>> io/tst-faccessat-setuid.c | 163 ++++++++++++++++++++++++++++++++++++++
>>> 2 files changed, 167 insertions(+)
>>> create mode 100644 io/tst-faccessat-setuid.c
>>>
>>> diff --git a/io/Makefile b/io/Makefile
>>> index a8d575e9ce..3ae26a5aa3 100644
>>> --- a/io/Makefile
>>> +++ b/io/Makefile
>>> @@ -232,6 +232,10 @@ tests := \
>>> tst-utimes \
>>> # tests
>>> +xtests := \
>>> + tst-faccessat-setuid \
>>> + #xtests
>>> +
>>
>> Can't we use support_become_root and make it a container test? It became
>> moot to add a new xtests, since it is not usually tested on make check
>> and not everyone knows about the make xcheck.
>>
>
> The test needs multiple user and group combinations, which doesn't seem to be something tests-container can provide. Does it make sense instead to add this as a `test` and bail out as UNSUPPORTED if it's not run as root? That way users know that the test is being skipped over, similar to how we do setuid tests.
Right, I was hoping that it would be easier but it seems that we will
need to add some support on test-container for extra uid/gid mapping.
Bailing as unsupported in this case is fine.
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v2 0/3] faccessat test improvements
2024-10-16 19:21 [PATCH 0/2] faccessat test improvements Siddhesh Poyarekar
` (2 preceding siblings ...)
2024-11-06 13:14 ` [ping1][PATCH 0/2] faccessat test improvements Siddhesh Poyarekar
@ 2024-11-08 17:45 ` Siddhesh Poyarekar
2024-11-08 17:45 ` [PATCH v2 1/3] support: Add xdup Siddhesh Poyarekar
` (2 subsequent siblings)
6 siblings, 0 replies; 16+ messages in thread
From: Siddhesh Poyarekar @ 2024-11-08 17:45 UTC (permalink / raw)
To: libc-alpha; +Cc: adhemerval.zanella
Cleaned up current test for faccessat and added a test to verify
behaviour with different real and effective user/group combinations.
Changes from v2:
- Separated out the return check and errno check in tst-faccessat
- Separated out the libsupport addition into a separate patch to ease
backports
- Made the new setuid test a regular one instead of xtest, bailing out
as UNSUPPORTED if it isn't run as root.
Siddhesh Poyarekar (3):
support: Add xdup
tst-faccessat.c: Port to libsupport
io: Add setuid tests for faccessat
io/Makefile | 1 +
io/tst-faccessat-setuid.c | 163 ++++++++++++++++++++++++++++
io/tst-faccessat.c | 221 +++++++++++---------------------------
support/Makefile | 1 +
support/xdup.c | 30 ++++++
support/xunistd.h | 1 +
6 files changed, 261 insertions(+), 156 deletions(-)
create mode 100644 io/tst-faccessat-setuid.c
create mode 100644 support/xdup.c
--
2.46.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v2 1/3] support: Add xdup
2024-10-16 19:21 [PATCH 0/2] faccessat test improvements Siddhesh Poyarekar
` (3 preceding siblings ...)
2024-11-08 17:45 ` [PATCH v2 0/3] " Siddhesh Poyarekar
@ 2024-11-08 17:45 ` Siddhesh Poyarekar
2024-11-11 14:05 ` Adhemerval Zanella Netto
2024-11-08 17:45 ` [PATCH v2 2/3] tst-faccessat.c: Port to libsupport Siddhesh Poyarekar
2024-11-08 17:45 ` [PATCH v2 3/3] io: Add setuid tests for faccessat Siddhesh Poyarekar
6 siblings, 1 reply; 16+ messages in thread
From: Siddhesh Poyarekar @ 2024-11-08 17:45 UTC (permalink / raw)
To: libc-alpha; +Cc: adhemerval.zanella
Add xdup as the error-checking version of dup for test cases.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
---
support/Makefile | 1 +
support/xdup.c | 30 ++++++++++++++++++++++++++++++
support/xunistd.h | 1 +
3 files changed, 32 insertions(+)
create mode 100644 support/xdup.c
diff --git a/support/Makefile b/support/Makefile
index 84e2419775..099f5ebb9c 100644
--- a/support/Makefile
+++ b/support/Makefile
@@ -128,6 +128,7 @@ libsupport-routines = \
xcopy_file_range \
xdlfcn \
xdlmopen \
+ xdup \
xdup2 \
xfchmod \
xfclose \
diff --git a/support/xdup.c b/support/xdup.c
new file mode 100644
index 0000000000..1eab317354
--- /dev/null
+++ b/support/xdup.c
@@ -0,0 +1,30 @@
+/* dup with error checking.
+ Copyright The GNU Toolchain Authors.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <support/xunistd.h>
+#include <support/check.h>
+
+int
+xdup (int from)
+{
+ int ret = dup (from);
+ if (ret < 0)
+ FAIL_EXIT1 ("dup (%d): %m", from);
+
+ return ret;
+}
diff --git a/support/xunistd.h b/support/xunistd.h
index 204951bce7..0c6d837ac0 100644
--- a/support/xunistd.h
+++ b/support/xunistd.h
@@ -35,6 +35,7 @@ pid_t xfork (void);
pid_t xwaitpid (pid_t, int *status, int flags);
void xpipe (int[2]);
void xdup2 (int, int);
+int xdup (int);
int xopen (const char *path, int flags, mode_t);
void support_check_stat_fd (const char *name, int fd, int result);
void support_check_stat_path (const char *name, const char *path, int result);
--
2.46.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v2 2/3] tst-faccessat.c: Port to libsupport
2024-10-16 19:21 [PATCH 0/2] faccessat test improvements Siddhesh Poyarekar
` (4 preceding siblings ...)
2024-11-08 17:45 ` [PATCH v2 1/3] support: Add xdup Siddhesh Poyarekar
@ 2024-11-08 17:45 ` Siddhesh Poyarekar
2024-11-11 14:08 ` Adhemerval Zanella Netto
2024-11-08 17:45 ` [PATCH v2 3/3] io: Add setuid tests for faccessat Siddhesh Poyarekar
6 siblings, 1 reply; 16+ messages in thread
From: Siddhesh Poyarekar @ 2024-11-08 17:45 UTC (permalink / raw)
To: libc-alpha; +Cc: adhemerval.zanella
Use libsupport convenience functions and macros instead of the old
test-skeleton. Also add a new xdup() convenience wrapper function.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
---
io/tst-faccessat.c | 221 +++++++++++++--------------------------------
1 file changed, 65 insertions(+), 156 deletions(-)
diff --git a/io/tst-faccessat.c b/io/tst-faccessat.c
index b90954e318..b980ca3fa2 100644
--- a/io/tst-faccessat.c
+++ b/io/tst-faccessat.c
@@ -1,6 +1,23 @@
-/* Test for faccessat function. */
-
-#include <dirent.h>
+/* Test for faccessat function.
+ Copyright (C) 2006-2024 Free Software Foundation, Inc.
+ Copyright The GNU Toolchain Authors.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
@@ -8,47 +25,19 @@
#include <unistd.h>
#include <sys/stat.h>
+#include <support/check.h>
+#include <support/temp_file.h>
+#include <support/test-driver.h>
+#include <support/xdirent.h>
#include <support/xunistd.h>
-static void prepare (void);
-#define PREPARE(argc, argv) prepare ()
-
-static int do_test (void);
-#define TEST_FUNCTION do_test ()
-
-#include "../test-skeleton.c"
-
static int dir_fd;
static void
-prepare (void)
+prepare (int argc, char **argv)
{
- size_t test_dir_len = strlen (test_dir);
- static const char dir_name[] = "/tst-faccessat.XXXXXX";
-
- size_t dirbuflen = test_dir_len + sizeof (dir_name);
- char *dirbuf = malloc (dirbuflen);
- if (dirbuf == NULL)
- {
- puts ("out of memory");
- exit (1);
- }
-
- snprintf (dirbuf, dirbuflen, "%s%s", test_dir, dir_name);
- if (mkdtemp (dirbuf) == NULL)
- {
- puts ("cannot create temporary directory");
- exit (1);
- }
-
- add_temp_file (dirbuf);
-
- dir_fd = open (dirbuf, O_RDONLY | O_DIRECTORY);
- if (dir_fd == -1)
- {
- puts ("cannot open directory");
- exit (1);
- }
+ dir_fd = xopen (support_create_temp_directory ("tst-faccessat."),
+ O_RDONLY | O_DIRECTORY, 0);
}
@@ -56,159 +45,79 @@ static int
do_test (void)
{
/* fdopendir takes over the descriptor, make a copy. */
- int dupfd = dup (dir_fd);
- if (dupfd == -1)
- {
- puts ("dup failed");
- return 1;
- }
- if (lseek (dupfd, 0, SEEK_SET) != 0)
- {
- puts ("1st lseek failed");
- return 1;
- }
+ int dupfd = xdup (dir_fd);
+ xlseek (dupfd, 0, SEEK_SET);
/* The directory should be empty save the . and .. files. */
- DIR *dir = fdopendir (dupfd);
- if (dir == NULL)
- {
- puts ("fdopendir failed");
- return 1;
- }
+ DIR *dir = xfdopendir (dupfd);
+
struct dirent64 *d;
- while ((d = readdir64 (dir)) != NULL)
+ while ((d = xreaddir64 (dir)) != NULL)
if (strcmp (d->d_name, ".") != 0 && strcmp (d->d_name, "..") != 0)
- {
- printf ("temp directory contains file \"%s\"\n", d->d_name);
- return 1;
- }
- closedir (dir);
+ FAIL_EXIT1 ("temp directory contains file \"%s\"\n", d->d_name);
+ xclosedir (dir);
/* Try to create a file. */
int fd = openat (dir_fd, "some-file", O_CREAT|O_RDWR|O_EXCL, 0666);
if (fd == -1)
{
if (errno == ENOSYS)
- {
- puts ("*at functions not supported");
- return 0;
- }
+ FAIL_UNSUPPORTED ("*at functions not supported");
- puts ("file creation failed");
- return 1;
+ FAIL_EXIT1 ("file creation failed");
}
xwrite (fd, "hello", 5);
puts ("file created");
/* Before closing the file, try using this file descriptor to open
another file. This must fail. */
- if (faccessat (fd, "should-not-work", F_OK, AT_EACCESS) != -1)
- {
- puts ("faccessat using descriptor for normal file worked");
- return 1;
- }
- if (errno != ENOTDIR)
- {
- puts ("\
-error for faccessat using descriptor for normal file not ENOTDIR ");
- return 1;
- }
-
- close (fd);
+ TEST_VERIFY_EXIT (faccessat (fd, "should-not-work", F_OK, AT_EACCESS) == -1);
+ TEST_VERIFY_EXIT (errno == ENOTDIR);
- int result = 0;
+ xclose (fd);
- if (faccessat (dir_fd, "some-file", F_OK, AT_EACCESS))
- {
- printf ("faccessat F_OK: %m\n");
- result = 1;
- }
- if (faccessat (dir_fd, "some-file", W_OK, AT_EACCESS))
- {
- printf ("faccessat W_OK: %m\n");
- result = 1;
- }
+ TEST_VERIFY (faccessat (dir_fd, "some-file", F_OK, AT_EACCESS) == 0);
+ TEST_VERIFY (faccessat (dir_fd, "some-file", W_OK, AT_EACCESS) == 0);
errno = 0;
- if (faccessat (dir_fd, "some-file", X_OK, AT_EACCESS) == 0
- || errno != EACCES)
- {
- printf ("faccessat X_OK on nonexecutable: %m\n");
- result = 1;
- }
+ if (faccessat (dir_fd, "some-file", X_OK, AT_EACCESS) != 0)
+ TEST_COMPARE (errno, EACCES);
+ else
+ FAIL ("faccessat unexpectedly succeeded\n");
if (fchmodat (dir_fd, "some-file", 0400, 0) != 0)
- {
- printf ("fchownat failed: %m\n");
- return 1;
- }
+ FAIL_EXIT1 ("fchownat failed: %m\n");
- if (faccessat (dir_fd, "some-file", R_OK, AT_EACCESS))
- {
- printf ("faccessat R_OK: %m\n");
- result = 1;
- }
+ TEST_VERIFY (faccessat (dir_fd, "some-file", R_OK, AT_EACCESS) == 0);
+ /* Write would succeed only for EUID root, otherwise this test should
+ fail. */
errno = 0;
- if (faccessat (dir_fd, "some-file", W_OK, AT_EACCESS) == 0
- ? (geteuid () != 0) : (errno != EACCES))
- {
- printf ("faccessat W_OK on unwritable file: %m\n");
- result = 1;
- }
+ TEST_VERIFY (faccessat (dir_fd, "some-file", W_OK, AT_EACCESS) == 0
+ ? (geteuid () == 0) : (errno == EACCES));
/* Create a file descriptor which is closed again right away. */
- int dir_fd2 = dup (dir_fd);
- if (dir_fd2 == -1)
- {
- puts ("dup failed");
- return 1;
- }
+ int dir_fd2 = xdup (dir_fd);
close (dir_fd2);
/* With the file descriptor closed the next call must fail. */
- if (faccessat (dir_fd2, "some-file", F_OK, AT_EACCESS) != -1)
- {
- puts ("faccessat using closed descriptor succeeded");
- return 1;
- }
- if (errno != EBADF)
- {
- puts ("faccessat using closed descriptor did not set EBADF");
- return 1;
- }
+ TEST_VERIFY_EXIT (faccessat (dir_fd2, "some-file", F_OK, AT_EACCESS)
+ == -1);
+ TEST_VERIFY_EXIT (errno == EBADF);
/* Same with a non-existing file. */
- if (faccessat (dir_fd2, "non-existing-file", F_OK, AT_EACCESS) != -1)
- {
- puts ("2nd faccessat using closed descriptor succeeded");
- return 1;
- }
- if (errno != EBADF)
- {
- puts ("2nd faccessat using closed descriptor did not set EBADF");
- return 1;
- }
+ TEST_VERIFY_EXIT (faccessat (dir_fd2, "non-existing-file", F_OK, AT_EACCESS)
+ == -1);
+ TEST_VERIFY_EXIT (errno == EBADF);
- if (unlinkat (dir_fd, "some-file", 0) != 0)
- {
- puts ("unlinkat failed");
- result = 1;
- }
+ TEST_VERIFY (unlinkat (dir_fd, "some-file", 0) == 0);
- close (dir_fd);
+ xclose (dir_fd);
- fd = faccessat (-1, "some-file", F_OK, AT_EACCESS);
- if (fd != -1)
- {
- puts ("faccessat using -1 descriptor succeeded");
- return 1;
- }
- if (errno != EBADF)
- {
- puts ("faccessat using -1 descriptor did not set EBADF");
- return 1;
- }
+ TEST_VERIFY_EXIT (faccessat (-1, "some-file", F_OK, AT_EACCESS) == -1);
+ TEST_VERIFY_EXIT (errno == EBADF);
- return result;
+ return 0;
}
+#define PREPARE prepare
+#include <support/test-driver.c>
--
2.46.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v2 3/3] io: Add setuid tests for faccessat
2024-10-16 19:21 [PATCH 0/2] faccessat test improvements Siddhesh Poyarekar
` (5 preceding siblings ...)
2024-11-08 17:45 ` [PATCH v2 2/3] tst-faccessat.c: Port to libsupport Siddhesh Poyarekar
@ 2024-11-08 17:45 ` Siddhesh Poyarekar
2024-11-11 16:05 ` Adhemerval Zanella Netto
6 siblings, 1 reply; 16+ messages in thread
From: Siddhesh Poyarekar @ 2024-11-08 17:45 UTC (permalink / raw)
To: libc-alpha; +Cc: adhemerval.zanella
Add a new test tst-faccessat-setuid that iterates through real and
effective UID/GID combination and tests the faccessat() interface for
default and AT_EACCESS flags.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
---
io/Makefile | 1 +
io/tst-faccessat-setuid.c | 163 ++++++++++++++++++++++++++++++++++++++
2 files changed, 164 insertions(+)
create mode 100644 io/tst-faccessat-setuid.c
diff --git a/io/Makefile b/io/Makefile
index a8d575e9ce..f5813a81c7 100644
--- a/io/Makefile
+++ b/io/Makefile
@@ -188,6 +188,7 @@ tests := \
tst-closefrom \
tst-copy_file_range \
tst-faccessat \
+ tst-faccessat-setuid \
tst-fchmod-errors \
tst-fchmod-fuse \
tst-fchmodat \
diff --git a/io/tst-faccessat-setuid.c b/io/tst-faccessat-setuid.c
new file mode 100644
index 0000000000..aab0261914
--- /dev/null
+++ b/io/tst-faccessat-setuid.c
@@ -0,0 +1,163 @@
+/* Smoke test for faccessat with different UID/GID combinations. Needs root
+ access.
+ Copyright The GNU Toolchain Authors.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <pwd.h>
+
+#include <support/check.h>
+#include <support/namespace.h>
+#include <support/support.h>
+#include <support/temp_file.h>
+#include <support/test-driver.h>
+#include <support/xdirent.h>
+#include <support/xunistd.h>
+
+#define SOMEFILE "some-file"
+
+static int dir_fd;
+uid_t users[3];
+gid_t groups[3];
+
+struct test_case
+{
+ int mode;
+ uid_t uid;
+ uid_t euid;
+ gid_t gid;
+ gid_t egid;
+ int flags;
+ bool succeeds;
+};
+
+static void
+run_one_test_child (void *in)
+{
+ struct test_case *t = (struct test_case *) in;
+
+ printf ("TEST: MODE=%s, UID=%d, EUID=%d, GID=%d, EGID=%d, FLAGS=%s: ",
+ t->mode == R_OK ? "R_OK" : "W_OK", t->uid, t->euid, t->gid, t->egid,
+ t->flags ? "AT_EACCESS" : "0");
+
+ if (setregid (t->gid, t->egid) != 0)
+ FAIL_EXIT1 ("Could not change group: %m\n");
+ if (setreuid (t->uid, t->euid) != 0)
+ FAIL_EXIT1 ("Could not change user: %m\n");
+
+ if (faccessat (dir_fd, SOMEFILE, t->mode, t->flags) != 0 && t->succeeds)
+ FAIL_EXIT1 ("faccessat failed: %m\n");
+
+ if (!t->succeeds && errno != EACCES)
+ FAIL_EXIT1 ("Unexpected faccessat failure: %m\n");
+
+ printf ("OK%s\n", !t->succeeds ? " (FAILED with EACCES)" : "");
+}
+
+static void
+run_one_test (int mode, int u, int eu, int g, int eg, int flags, bool succeeds)
+{
+ struct test_case t =
+ {mode, users[u], users[eu], groups[g], groups[eg], flags, succeeds};
+ support_isolate_in_subprocess (run_one_test_child, &t);
+}
+
+static int
+do_test (void)
+{
+
+ /* We need to start as root. */
+ if (getuid () != 0)
+ FAIL_UNSUPPORTED ("Test needs to be run as root (UID 0)\n");
+
+ /* Collect 3 distinct users and groups to test with. */
+ struct passwd *ent = NULL;
+ int count = 0;
+ while ((ent = getpwent ()) != NULL && count < 3)
+ {
+ if (ent->pw_uid == 0 || ent->pw_gid == 0)
+ continue;
+
+ int i = count;
+ bool skip = false;
+ while (i > 0)
+ if (groups[--i] == ent->pw_gid)
+ skip = true;
+
+ if (skip)
+ continue;
+
+ users[count] = ent->pw_uid;
+ groups[count++] = ent->pw_gid;
+ }
+
+ if (count < 3)
+ FAIL_UNSUPPORTED ("Not enough users in the system to do this test\n");
+
+ printf ("Testing with UID/GID:\n");
+ while (--count >= 0)
+ printf (" UID: %d, GID: %d\n", users[count], groups[count]);
+ printf ("\n");
+
+ char *tempdir = support_create_temp_directory ("tst-faccessat-setuid.");
+ dir_fd = xopen (tempdir, O_RDONLY | O_DIRECTORY, 0);
+
+ xfchmod (dir_fd, 0777);
+
+ /* Now, create a file in it, which will be our test case. */
+
+ int fd = openat (dir_fd, SOMEFILE, O_CREAT|O_RDWR|O_EXCL, 0640);
+ if (fd == -1)
+ {
+ if (errno == ENOSYS)
+ FAIL_UNSUPPORTED ("*at functions not supported");
+
+ FAIL_EXIT1 ("file creation failed");
+ }
+ xwrite (fd, "hello", 5);
+
+ if (fchown (fd, users[0], groups[1]) == -1)
+ FAIL_EXIT1 ("fchown failed: %m\n");
+ xclose (fd);
+
+ char *somefile = xasprintf ("%s/" SOMEFILE, tempdir);
+ add_temp_file (somefile);
+
+ /* Finally, run through the combinations. */
+ for (int u = 0; u < 3; u++)
+ for (int eu = 0; eu < 3; eu++)
+ for (int g = 0; g < 3; g++)
+ for (int eg = 0; eg < 3; eg++)
+ {
+ run_one_test (R_OK, u, eu, g, eg, 0, u == 0 || g == 1);
+ run_one_test (W_OK, u, eu, g, eg, 0, u == 0);
+ run_one_test (R_OK, u, eu, g, eg, AT_EACCESS, eu == 0 || eg == 1);
+ run_one_test (W_OK, u, eu, g, eg, AT_EACCESS, eu == 0);
+ }
+
+ xclose (dir_fd);
+ free (tempdir);
+ free (somefile);
+
+ return 0;
+}
+#include <support/test-driver.c>
--
2.46.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2 1/3] support: Add xdup
2024-11-08 17:45 ` [PATCH v2 1/3] support: Add xdup Siddhesh Poyarekar
@ 2024-11-11 14:05 ` Adhemerval Zanella Netto
0 siblings, 0 replies; 16+ messages in thread
From: Adhemerval Zanella Netto @ 2024-11-11 14:05 UTC (permalink / raw)
To: Siddhesh Poyarekar, libc-alpha
On 08/11/24 14:45, Siddhesh Poyarekar wrote:
> Add xdup as the error-checking version of dup for test cases.
>
> Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
LGTM, thanks.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
> ---
> support/Makefile | 1 +
> support/xdup.c | 30 ++++++++++++++++++++++++++++++
> support/xunistd.h | 1 +
> 3 files changed, 32 insertions(+)
> create mode 100644 support/xdup.c
>
> diff --git a/support/Makefile b/support/Makefile
> index 84e2419775..099f5ebb9c 100644
> --- a/support/Makefile
> +++ b/support/Makefile
> @@ -128,6 +128,7 @@ libsupport-routines = \
> xcopy_file_range \
> xdlfcn \
> xdlmopen \
> + xdup \
> xdup2 \
> xfchmod \
> xfclose \
> diff --git a/support/xdup.c b/support/xdup.c
> new file mode 100644
> index 0000000000..1eab317354
> --- /dev/null
> +++ b/support/xdup.c
> @@ -0,0 +1,30 @@
> +/* dup with error checking.
> + Copyright The GNU Toolchain Authors.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library 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
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, see
> + <https://www.gnu.org/licenses/>. */
> +
> +#include <support/xunistd.h>
> +#include <support/check.h>
> +
> +int
> +xdup (int from)
> +{
> + int ret = dup (from);
> + if (ret < 0)
> + FAIL_EXIT1 ("dup (%d): %m", from);
> +
> + return ret;
> +}
> diff --git a/support/xunistd.h b/support/xunistd.h
> index 204951bce7..0c6d837ac0 100644
> --- a/support/xunistd.h
> +++ b/support/xunistd.h
> @@ -35,6 +35,7 @@ pid_t xfork (void);
> pid_t xwaitpid (pid_t, int *status, int flags);
> void xpipe (int[2]);
> void xdup2 (int, int);
> +int xdup (int);
> int xopen (const char *path, int flags, mode_t);
> void support_check_stat_fd (const char *name, int fd, int result);
> void support_check_stat_path (const char *name, const char *path, int result);
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2 2/3] tst-faccessat.c: Port to libsupport
2024-11-08 17:45 ` [PATCH v2 2/3] tst-faccessat.c: Port to libsupport Siddhesh Poyarekar
@ 2024-11-11 14:08 ` Adhemerval Zanella Netto
0 siblings, 0 replies; 16+ messages in thread
From: Adhemerval Zanella Netto @ 2024-11-11 14:08 UTC (permalink / raw)
To: Siddhesh Poyarekar, libc-alpha
On 08/11/24 14:45, Siddhesh Poyarekar wrote:
> Use libsupport convenience functions and macros instead of the old
> test-skeleton. Also add a new xdup() convenience wrapper function.
>
> Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
LGTM, thanks.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
> ---
> io/tst-faccessat.c | 221 +++++++++++++--------------------------------
> 1 file changed, 65 insertions(+), 156 deletions(-)
>
> diff --git a/io/tst-faccessat.c b/io/tst-faccessat.c
> index b90954e318..b980ca3fa2 100644
> --- a/io/tst-faccessat.c
> +++ b/io/tst-faccessat.c
> @@ -1,6 +1,23 @@
> -/* Test for faccessat function. */
> -
> -#include <dirent.h>
> +/* Test for faccessat function.
> + Copyright (C) 2006-2024 Free Software Foundation, Inc.
> + Copyright The GNU Toolchain Authors.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library 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
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, see
> + <https://www.gnu.org/licenses/>. */
> +
> +#include <errno.h>
> #include <fcntl.h>
> #include <stdio.h>
> #include <stdlib.h>
> @@ -8,47 +25,19 @@
> #include <unistd.h>
> #include <sys/stat.h>
>
> +#include <support/check.h>
> +#include <support/temp_file.h>
> +#include <support/test-driver.h>
> +#include <support/xdirent.h>
> #include <support/xunistd.h>
>
> -static void prepare (void);
> -#define PREPARE(argc, argv) prepare ()
> -
> -static int do_test (void);
> -#define TEST_FUNCTION do_test ()
> -
> -#include "../test-skeleton.c"
> -
> static int dir_fd;
>
> static void
> -prepare (void)
> +prepare (int argc, char **argv)
> {
> - size_t test_dir_len = strlen (test_dir);
> - static const char dir_name[] = "/tst-faccessat.XXXXXX";
> -
> - size_t dirbuflen = test_dir_len + sizeof (dir_name);
> - char *dirbuf = malloc (dirbuflen);
> - if (dirbuf == NULL)
> - {
> - puts ("out of memory");
> - exit (1);
> - }
> -
> - snprintf (dirbuf, dirbuflen, "%s%s", test_dir, dir_name);
> - if (mkdtemp (dirbuf) == NULL)
> - {
> - puts ("cannot create temporary directory");
> - exit (1);
> - }
> -
> - add_temp_file (dirbuf);
> -
> - dir_fd = open (dirbuf, O_RDONLY | O_DIRECTORY);
> - if (dir_fd == -1)
> - {
> - puts ("cannot open directory");
> - exit (1);
> - }
> + dir_fd = xopen (support_create_temp_directory ("tst-faccessat."),
> + O_RDONLY | O_DIRECTORY, 0);
> }
>
>
> @@ -56,159 +45,79 @@ static int
> do_test (void)
> {
> /* fdopendir takes over the descriptor, make a copy. */
> - int dupfd = dup (dir_fd);
> - if (dupfd == -1)
> - {
> - puts ("dup failed");
> - return 1;
> - }
> - if (lseek (dupfd, 0, SEEK_SET) != 0)
> - {
> - puts ("1st lseek failed");
> - return 1;
> - }
> + int dupfd = xdup (dir_fd);
> + xlseek (dupfd, 0, SEEK_SET);
>
> /* The directory should be empty save the . and .. files. */
> - DIR *dir = fdopendir (dupfd);
> - if (dir == NULL)
> - {
> - puts ("fdopendir failed");
> - return 1;
> - }
> + DIR *dir = xfdopendir (dupfd);
> +
> struct dirent64 *d;
> - while ((d = readdir64 (dir)) != NULL)
> + while ((d = xreaddir64 (dir)) != NULL)
> if (strcmp (d->d_name, ".") != 0 && strcmp (d->d_name, "..") != 0)
> - {
> - printf ("temp directory contains file \"%s\"\n", d->d_name);
> - return 1;
> - }
> - closedir (dir);
> + FAIL_EXIT1 ("temp directory contains file \"%s\"\n", d->d_name);
> + xclosedir (dir);
>
> /* Try to create a file. */
> int fd = openat (dir_fd, "some-file", O_CREAT|O_RDWR|O_EXCL, 0666);
> if (fd == -1)
> {
> if (errno == ENOSYS)
> - {
> - puts ("*at functions not supported");
> - return 0;
> - }
> + FAIL_UNSUPPORTED ("*at functions not supported");
>
> - puts ("file creation failed");
> - return 1;
> + FAIL_EXIT1 ("file creation failed");
> }
> xwrite (fd, "hello", 5);
> puts ("file created");
>
> /* Before closing the file, try using this file descriptor to open
> another file. This must fail. */
> - if (faccessat (fd, "should-not-work", F_OK, AT_EACCESS) != -1)
> - {
> - puts ("faccessat using descriptor for normal file worked");
> - return 1;
> - }
> - if (errno != ENOTDIR)
> - {
> - puts ("\
> -error for faccessat using descriptor for normal file not ENOTDIR ");
> - return 1;
> - }
> -
> - close (fd);
> + TEST_VERIFY_EXIT (faccessat (fd, "should-not-work", F_OK, AT_EACCESS) == -1);
> + TEST_VERIFY_EXIT (errno == ENOTDIR);
>
> - int result = 0;
> + xclose (fd);
>
> - if (faccessat (dir_fd, "some-file", F_OK, AT_EACCESS))
> - {
> - printf ("faccessat F_OK: %m\n");
> - result = 1;
> - }
> - if (faccessat (dir_fd, "some-file", W_OK, AT_EACCESS))
> - {
> - printf ("faccessat W_OK: %m\n");
> - result = 1;
> - }
> + TEST_VERIFY (faccessat (dir_fd, "some-file", F_OK, AT_EACCESS) == 0);
> + TEST_VERIFY (faccessat (dir_fd, "some-file", W_OK, AT_EACCESS) == 0);
>
> errno = 0;
> - if (faccessat (dir_fd, "some-file", X_OK, AT_EACCESS) == 0
> - || errno != EACCES)
> - {
> - printf ("faccessat X_OK on nonexecutable: %m\n");
> - result = 1;
> - }
> + if (faccessat (dir_fd, "some-file", X_OK, AT_EACCESS) != 0)
> + TEST_COMPARE (errno, EACCES);
> + else
> + FAIL ("faccessat unexpectedly succeeded\n");
>
> if (fchmodat (dir_fd, "some-file", 0400, 0) != 0)
> - {
> - printf ("fchownat failed: %m\n");
> - return 1;
> - }
> + FAIL_EXIT1 ("fchownat failed: %m\n");
>
> - if (faccessat (dir_fd, "some-file", R_OK, AT_EACCESS))
> - {
> - printf ("faccessat R_OK: %m\n");
> - result = 1;
> - }
> + TEST_VERIFY (faccessat (dir_fd, "some-file", R_OK, AT_EACCESS) == 0);
>
> + /* Write would succeed only for EUID root, otherwise this test should
> + fail. */
> errno = 0;
> - if (faccessat (dir_fd, "some-file", W_OK, AT_EACCESS) == 0
> - ? (geteuid () != 0) : (errno != EACCES))
> - {
> - printf ("faccessat W_OK on unwritable file: %m\n");
> - result = 1;
> - }
> + TEST_VERIFY (faccessat (dir_fd, "some-file", W_OK, AT_EACCESS) == 0
> + ? (geteuid () == 0) : (errno == EACCES));
>
> /* Create a file descriptor which is closed again right away. */
> - int dir_fd2 = dup (dir_fd);
> - if (dir_fd2 == -1)
> - {
> - puts ("dup failed");
> - return 1;
> - }
> + int dir_fd2 = xdup (dir_fd);
> close (dir_fd2);
>
> /* With the file descriptor closed the next call must fail. */
> - if (faccessat (dir_fd2, "some-file", F_OK, AT_EACCESS) != -1)
> - {
> - puts ("faccessat using closed descriptor succeeded");
> - return 1;
> - }
> - if (errno != EBADF)
> - {
> - puts ("faccessat using closed descriptor did not set EBADF");
> - return 1;
> - }
> + TEST_VERIFY_EXIT (faccessat (dir_fd2, "some-file", F_OK, AT_EACCESS)
> + == -1);
> + TEST_VERIFY_EXIT (errno == EBADF);
>
> /* Same with a non-existing file. */
> - if (faccessat (dir_fd2, "non-existing-file", F_OK, AT_EACCESS) != -1)
> - {
> - puts ("2nd faccessat using closed descriptor succeeded");
> - return 1;
> - }
> - if (errno != EBADF)
> - {
> - puts ("2nd faccessat using closed descriptor did not set EBADF");
> - return 1;
> - }
> + TEST_VERIFY_EXIT (faccessat (dir_fd2, "non-existing-file", F_OK, AT_EACCESS)
> + == -1);
> + TEST_VERIFY_EXIT (errno == EBADF);
>
> - if (unlinkat (dir_fd, "some-file", 0) != 0)
> - {
> - puts ("unlinkat failed");
> - result = 1;
> - }
> + TEST_VERIFY (unlinkat (dir_fd, "some-file", 0) == 0);
>
> - close (dir_fd);
> + xclose (dir_fd);
>
> - fd = faccessat (-1, "some-file", F_OK, AT_EACCESS);
> - if (fd != -1)
> - {
> - puts ("faccessat using -1 descriptor succeeded");
> - return 1;
> - }
> - if (errno != EBADF)
> - {
> - puts ("faccessat using -1 descriptor did not set EBADF");
> - return 1;
> - }
> + TEST_VERIFY_EXIT (faccessat (-1, "some-file", F_OK, AT_EACCESS) == -1);
> + TEST_VERIFY_EXIT (errno == EBADF);
>
> - return result;
> + return 0;
> }
> +#define PREPARE prepare
> +#include <support/test-driver.c>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2 3/3] io: Add setuid tests for faccessat
2024-11-08 17:45 ` [PATCH v2 3/3] io: Add setuid tests for faccessat Siddhesh Poyarekar
@ 2024-11-11 16:05 ` Adhemerval Zanella Netto
0 siblings, 0 replies; 16+ messages in thread
From: Adhemerval Zanella Netto @ 2024-11-11 16:05 UTC (permalink / raw)
To: Siddhesh Poyarekar, libc-alpha
On 08/11/24 14:45, Siddhesh Poyarekar wrote:
> Add a new test tst-faccessat-setuid that iterates through real and
> effective UID/GID combination and tests the faccessat() interface for
> default and AT_EACCESS flags.
>
> Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
LGTM, thanks.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
> ---
> io/Makefile | 1 +
> io/tst-faccessat-setuid.c | 163 ++++++++++++++++++++++++++++++++++++++
> 2 files changed, 164 insertions(+)
> create mode 100644 io/tst-faccessat-setuid.c
>
> diff --git a/io/Makefile b/io/Makefile
> index a8d575e9ce..f5813a81c7 100644
> --- a/io/Makefile
> +++ b/io/Makefile
> @@ -188,6 +188,7 @@ tests := \
> tst-closefrom \
> tst-copy_file_range \
> tst-faccessat \
> + tst-faccessat-setuid \
> tst-fchmod-errors \
> tst-fchmod-fuse \
> tst-fchmodat \
> diff --git a/io/tst-faccessat-setuid.c b/io/tst-faccessat-setuid.c
> new file mode 100644
> index 0000000000..aab0261914
> --- /dev/null
> +++ b/io/tst-faccessat-setuid.c
> @@ -0,0 +1,163 @@
> +/* Smoke test for faccessat with different UID/GID combinations. Needs root
> + access.
> + Copyright The GNU Toolchain Authors.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library 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
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, see
> + <https://www.gnu.org/licenses/>. */
> +
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <sys/types.h>
> +#include <pwd.h>
> +
> +#include <support/check.h>
> +#include <support/namespace.h>
> +#include <support/support.h>
> +#include <support/temp_file.h>
> +#include <support/test-driver.h>
> +#include <support/xdirent.h>
> +#include <support/xunistd.h>
> +
> +#define SOMEFILE "some-file"
> +
> +static int dir_fd;
> +uid_t users[3];
> +gid_t groups[3];
> +
> +struct test_case
> +{
> + int mode;
> + uid_t uid;
> + uid_t euid;
> + gid_t gid;
> + gid_t egid;
> + int flags;
> + bool succeeds;
> +};
> +
> +static void
> +run_one_test_child (void *in)
> +{
> + struct test_case *t = (struct test_case *) in;
> +
> + printf ("TEST: MODE=%s, UID=%d, EUID=%d, GID=%d, EGID=%d, FLAGS=%s: ",
> + t->mode == R_OK ? "R_OK" : "W_OK", t->uid, t->euid, t->gid, t->egid,
> + t->flags ? "AT_EACCESS" : "0");
> +
> + if (setregid (t->gid, t->egid) != 0)
> + FAIL_EXIT1 ("Could not change group: %m\n");
> + if (setreuid (t->uid, t->euid) != 0)
> + FAIL_EXIT1 ("Could not change user: %m\n");
> +
> + if (faccessat (dir_fd, SOMEFILE, t->mode, t->flags) != 0 && t->succeeds)
> + FAIL_EXIT1 ("faccessat failed: %m\n");
> +
> + if (!t->succeeds && errno != EACCES)
> + FAIL_EXIT1 ("Unexpected faccessat failure: %m\n");
> +
> + printf ("OK%s\n", !t->succeeds ? " (FAILED with EACCES)" : "");
> +}
> +
> +static void
> +run_one_test (int mode, int u, int eu, int g, int eg, int flags, bool succeeds)
> +{
> + struct test_case t =
> + {mode, users[u], users[eu], groups[g], groups[eg], flags, succeeds};
> + support_isolate_in_subprocess (run_one_test_child, &t);
> +}
> +
> +static int
> +do_test (void)
> +{
> +
> + /* We need to start as root. */
> + if (getuid () != 0)
> + FAIL_UNSUPPORTED ("Test needs to be run as root (UID 0)\n");
> +
> + /* Collect 3 distinct users and groups to test with. */
> + struct passwd *ent = NULL;
> + int count = 0;
> + while ((ent = getpwent ()) != NULL && count < 3)
> + {
> + if (ent->pw_uid == 0 || ent->pw_gid == 0)
> + continue;
> +
> + int i = count;
> + bool skip = false;
> + while (i > 0)
> + if (groups[--i] == ent->pw_gid)
> + skip = true;
> +
> + if (skip)
> + continue;
> +
> + users[count] = ent->pw_uid;
> + groups[count++] = ent->pw_gid;
> + }
> +
> + if (count < 3)
> + FAIL_UNSUPPORTED ("Not enough users in the system to do this test\n");
> +
> + printf ("Testing with UID/GID:\n");
> + while (--count >= 0)
> + printf (" UID: %d, GID: %d\n", users[count], groups[count]);
> + printf ("\n");
> +
> + char *tempdir = support_create_temp_directory ("tst-faccessat-setuid.");
> + dir_fd = xopen (tempdir, O_RDONLY | O_DIRECTORY, 0);
> +
> + xfchmod (dir_fd, 0777);
> +
> + /* Now, create a file in it, which will be our test case. */
> +
> + int fd = openat (dir_fd, SOMEFILE, O_CREAT|O_RDWR|O_EXCL, 0640);
> + if (fd == -1)
> + {
> + if (errno == ENOSYS)
> + FAIL_UNSUPPORTED ("*at functions not supported");
> +
> + FAIL_EXIT1 ("file creation failed");
> + }
> + xwrite (fd, "hello", 5);
> +
> + if (fchown (fd, users[0], groups[1]) == -1)
> + FAIL_EXIT1 ("fchown failed: %m\n");
> + xclose (fd);
> +
> + char *somefile = xasprintf ("%s/" SOMEFILE, tempdir);
> + add_temp_file (somefile);
> +
> + /* Finally, run through the combinations. */
> + for (int u = 0; u < 3; u++)
> + for (int eu = 0; eu < 3; eu++)
> + for (int g = 0; g < 3; g++)
> + for (int eg = 0; eg < 3; eg++)
> + {
> + run_one_test (R_OK, u, eu, g, eg, 0, u == 0 || g == 1);
> + run_one_test (W_OK, u, eu, g, eg, 0, u == 0);
> + run_one_test (R_OK, u, eu, g, eg, AT_EACCESS, eu == 0 || eg == 1);
> + run_one_test (W_OK, u, eu, g, eg, AT_EACCESS, eu == 0);
> + }
> +
> + xclose (dir_fd);
> + free (tempdir);
> + free (somefile);
> +
> + return 0;
> +}
> +#include <support/test-driver.c>
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2024-11-11 16:05 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-10-16 19:21 [PATCH 0/2] faccessat test improvements Siddhesh Poyarekar
2024-10-16 19:21 ` [PATCH 1/2] tst-faccessat.c: Port to libsupport Siddhesh Poyarekar
2024-11-06 15:08 ` Adhemerval Zanella Netto
2024-11-06 15:11 ` Siddhesh Poyarekar
2024-10-16 19:21 ` [PATCH 2/2] io: Add setuid tests for faccessat Siddhesh Poyarekar
2024-11-06 15:09 ` Adhemerval Zanella Netto
2024-11-06 15:13 ` Siddhesh Poyarekar
2024-11-06 17:26 ` Adhemerval Zanella Netto
2024-11-06 13:14 ` [ping1][PATCH 0/2] faccessat test improvements Siddhesh Poyarekar
2024-11-08 17:45 ` [PATCH v2 0/3] " Siddhesh Poyarekar
2024-11-08 17:45 ` [PATCH v2 1/3] support: Add xdup Siddhesh Poyarekar
2024-11-11 14:05 ` Adhemerval Zanella Netto
2024-11-08 17:45 ` [PATCH v2 2/3] tst-faccessat.c: Port to libsupport Siddhesh Poyarekar
2024-11-11 14:08 ` Adhemerval Zanella Netto
2024-11-08 17:45 ` [PATCH v2 3/3] io: Add setuid tests for faccessat Siddhesh Poyarekar
2024-11-11 16:05 ` Adhemerval Zanella Netto
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).