[LTP] [PATCH 2/5] fanotify21: Stop relying on exited child for pidfd error
Jan Kara
jack@suse.cz
Tue Jun 16 09:48:33 CEST 2026
On Tue 16-06-26 02:06:26, AnonymeMeow wrote:
> fanotify21 used to verify the pidfd error case by generating an event
> from a child process and reading the event after the child had exited.
> This is no longer a stable way to trigger a pidfd error, because newer
> kernels can report pidfds for exited event processes.
>
> Read the event from a child process in a descendant PID namespace
> instead. The reader cannot get the pidfd in the parent PID namespace
> from fanotify, so pidfd creation will fail and the test can verify
> FAN_NOPIDFD, or -ESRCH with FAN_REPORT_FD_ERROR.
>
> Signed-off-by: AnonymeMeow <anonymemeow@gmail.com>
Looks good. Feel free to add:
Reviewed-by: Jan Kara <jack@suse.cz>
Honza
> ---
> .../kernel/syscalls/fanotify/fanotify21.c | 55 ++++++++-----------
> 1 file changed, 24 insertions(+), 31 deletions(-)
>
> diff --git a/testcases/kernel/syscalls/fanotify/fanotify21.c b/testcases/kernel/syscalls/fanotify/fanotify21.c
> index 4d2115469..bd1a43513 100644
> --- a/testcases/kernel/syscalls/fanotify/fanotify21.c
> +++ b/testcases/kernel/syscalls/fanotify/fanotify21.c
> @@ -42,7 +42,6 @@ struct pidfd_fdinfo_t {
>
> static struct test_case_t {
> char *name;
> - int fork;
> int want_pidfd_err;
> int remount_ro;
> } test_cases[] = {
> @@ -50,18 +49,15 @@ static struct test_case_t {
> "return a valid pidfd for event created by self",
> 0,
> 0,
> - 0,
> },
> {
> - "return invalid pidfd for event created by terminated child",
> - 1,
> + "return invalid pidfd for reader in descendant PID namespace",
> 1,
> 0,
> },
> {
> "fail to open rw fd for event created on read-only mount",
> 0,
> - 0,
> 1,
> },
> };
> @@ -72,6 +68,11 @@ static struct pidfd_fdinfo_t *self_pidfd_fdinfo;
>
> static int fd_error_unsupported;
>
> +static struct tst_clone_args clone_args = {
> + .flags = CLONE_NEWPID,
> + .exit_signal = SIGCHLD,
> +};
> +
> static struct pidfd_fdinfo_t *read_pidfd_fdinfo(int pidfd)
> {
> char *fdinfo_path;
> @@ -100,24 +101,6 @@ static void generate_event(void)
> SAFE_CLOSE(fd);
> }
>
> -static void do_fork(void)
> -{
> - int status;
> - pid_t child;
> -
> - child = SAFE_FORK();
> - if (child == 0) {
> - SAFE_CLOSE(fanotify_fd);
> - generate_event();
> - exit(EXIT_SUCCESS);
> - }
> -
> - SAFE_WAITPID(child, &status, 0);
> - if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
> - tst_brk(TBROK,
> - "child process terminated incorrectly");
> -}
> -
> static void do_setup(void)
> {
> int pidfd;
> @@ -165,6 +148,8 @@ static void do_test(unsigned int num)
> int nopidfd_err = tc->want_pidfd_err ?
> (tst_variant ? -ESRCH : FAN_NOPIDFD) : 0;
> int fd_err = (tc->remount_ro && tst_variant) ? -EROFS : 0;
> + pid_t reader_pid;
> + int reader_exit_status;
>
> tst_res(TINFO, "Test #%d.%d: %s %s", num, tst_variant, tc->name,
> tst_variant ? "(FAN_REPORT_FD_ERROR)" : "");
> @@ -178,15 +163,20 @@ static void do_test(unsigned int num)
> SAFE_MOUNT("none", MOUNT_PATH, "none", MS_BIND | MS_REMOUNT |
> (tc->remount_ro ? MS_RDONLY : 0), NULL);
>
> + generate_event();
> +
> /*
> - * Generate the event in either self or a child process. Event
> - * generation in a child process is done so that the FAN_NOPIDFD case
> - * can be verified.
> + * Read the event in either self or a child process in a descendant
> + * PID namespace. A reader in a descendant PID namespace cannot obtain
> + * the pidfd of the event process in the parent PID namespace so that
> + * the FAN_NOPIDFD case can be verified.
> */
> - if (tc->fork)
> - do_fork();
> - else
> - generate_event();
> + if (tc->want_pidfd_err && (reader_pid = SAFE_CLONE(&clone_args))) {
> + SAFE_WAITPID(reader_pid, &reader_exit_status, 0);
> + if (!WIFEXITED(reader_exit_status) || WEXITSTATUS(reader_exit_status))
> + tst_brk(TBROK, "reader process exited incorrectly");
> + return;
> + }
>
> /*
> * Read all of the queued events into the provided event
> @@ -274,7 +264,7 @@ static void do_test(unsigned int num)
> goto next_event;
> } else if (tc->want_pidfd_err && info->pidfd == nopidfd_err) {
> tst_res(TPASS,
> - "pid: %u terminated before pidfd was created, "
> + "pid: %u is invisible in reader PID namespace, "
> "pidfd set to the value of: %d, as expected",
> (unsigned int)event->pid,
> nopidfd_err);
> @@ -343,6 +333,9 @@ next_event:
> if (event_pidfd_fdinfo)
> free(event_pidfd_fdinfo);
> }
> +
> + if (tc->want_pidfd_err)
> + exit(0);
> }
>
> static void do_cleanup(void)
> --
> 2.54.0
>
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
More information about the ltp
mailing list