From: Cyril Hrubis <chrubis@suse.cz>
To: Ricardo Branco <rbranco@suse.de>, et@yuki.lan
Cc: ltp@lists.linux.it
Subject: Re: [LTP] [PATCH v7] userfaultfd: Add test using UFFDIO_POISON
Date: Mon, 2 Mar 2026 11:24:11 +0100 [thread overview]
Message-ID: <aaVlS4eVHhDdSFOS@yuki.lan> (raw)
In-Reply-To: <20260226115427.58459-1-rbranco@suse.de>
Hi!
> +#ifndef HAVE_STRUCT_UFFDIO_POISON
> +#define UFFD_FEATURE_POISON (1<<14)
> +#define _UFFDIO_POISON (0x08)
> +#define UFFDIO_POISON _IOWR(UFFDIO, _UFFDIO_POISON, \
> + struct uffdio_poison)
> +struct uffdio_poison {
> + struct uffdio_range range;
> +#define UFFDIO_POISON_MODE_DONTWAKE ((__u64)1<<0)
> + __u64 mode;
> + __s64 updated;
> +};
> +#endif /* HAVE_STRUCT_UFFDIO_POISON */
> +
> #define SAFE_USERFAULTFD(flags, retry) \
> safe_userfaultfd(__FILE__, __LINE__, (flags), (retry))
>
> diff --git a/runtest/syscalls b/runtest/syscalls
> index 05bb3ceb1..b76c3890f 100644
> --- a/runtest/syscalls
> +++ b/runtest/syscalls
> @@ -1775,6 +1775,7 @@ userfaultfd02 userfaultfd02
> userfaultfd03 userfaultfd03
> userfaultfd04 userfaultfd04
> userfaultfd05 userfaultfd05
> +userfaultfd06 userfaultfd06
>
> ustat01 ustat01
> ustat02 ustat02
> diff --git a/testcases/kernel/syscalls/userfaultfd/.gitignore b/testcases/kernel/syscalls/userfaultfd/.gitignore
> index fb2ae243b..bc32fdf3b 100644
> --- a/testcases/kernel/syscalls/userfaultfd/.gitignore
> +++ b/testcases/kernel/syscalls/userfaultfd/.gitignore
> @@ -3,3 +3,4 @@
> /userfaultfd03
> /userfaultfd04
> /userfaultfd05
> +/userfaultfd06
> diff --git a/testcases/kernel/syscalls/userfaultfd/Makefile b/testcases/kernel/syscalls/userfaultfd/Makefile
> index 96650a65a..3252e47df 100644
> --- a/testcases/kernel/syscalls/userfaultfd/Makefile
> +++ b/testcases/kernel/syscalls/userfaultfd/Makefile
> @@ -16,3 +16,4 @@ userfaultfd02: CFLAGS += -pthread
> userfaultfd03: CFLAGS += -pthread
> userfaultfd04: CFLAGS += -pthread
> userfaultfd05: CFLAGS += -pthread
> +userfaultfd06: CFLAGS += -pthread
> diff --git a/testcases/kernel/syscalls/userfaultfd/userfaultfd06.c b/testcases/kernel/syscalls/userfaultfd/userfaultfd06.c
> new file mode 100644
> index 000000000..4803fa3d9
> --- /dev/null
> +++ b/testcases/kernel/syscalls/userfaultfd/userfaultfd06.c
> @@ -0,0 +1,142 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (c) 2026 SUSE LLC
> + * Author: Ricardo Branco <rbranco@suse.com>
> + */
> +
> +/*\
> + * Force a pagefault event and handle it using :manpage:`userfaultfd(2)`
> + * from a different thread testing UFFDIO_POISON.
> + */
> +
> +#include "config.h"
> +#include <poll.h>
> +#include <setjmp.h>
> +#include <signal.h>
> +#include <unistd.h>
> +#include "tst_test.h"
> +#include "tst_safe_macros.h"
> +#include "tst_safe_pthread.h"
> +#include "lapi/userfaultfd.h"
> +
> +static int page_size;
> +static char *page;
> +static int uffd;
> +static int poison_fault_seen;
> +static volatile int sigbus_seen;
> +static sigjmp_buf jmpbuf;
> +
> +static void sigbus_handler(int sig)
> +{
> + if (sig == SIGBUS) {
> + sigbus_seen = 1;
> + siglongjmp(jmpbuf, 1);
> + }
> +}
> +
> +static void setup(void)
> +{
> + struct sigaction sa = {};
> +
> + sa.sa_handler = sigbus_handler;
> + sigemptyset(&sa.sa_mask);
> + SAFE_SIGACTION(SIGBUS, &sa, NULL);
> +}
> +
> +static void set_pages(void)
> +{
> + page_size = sysconf(_SC_PAGE_SIZE);
> + page = SAFE_MMAP(NULL, page_size, PROT_READ | PROT_WRITE,
> + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
> +}
> +
> +static void reset_pages(void)
> +{
> + if (page) {
> + SAFE_MUNMAP(page, page_size);
> + page = NULL;
> + }
> +}
> +
> +static void *handle_thread(void)
> +{
> + static struct uffd_msg msg;
> + struct uffdio_poison uffdio_poison = {};
> + struct pollfd pollfd;
> + int nready;
> +
> + pollfd.fd = uffd;
> + pollfd.events = POLLIN;
> + nready = poll(&pollfd, 1, -1);
> + if (nready == -1)
> + tst_brk(TBROK | TERRNO, "Error on poll");
> +
> + SAFE_READ(1, uffd, &msg, sizeof(msg));
> +
> + if (msg.event != UFFD_EVENT_PAGEFAULT)
> + tst_brk(TFAIL, "Received unexpected UFFD_EVENT %d", msg.event);
> +
> + tst_atomic_store(1, &poison_fault_seen);
> +
> + /* Poison the page that triggered the fault */
> + uffdio_poison.range.start = msg.arg.pagefault.address & ~(page_size - 1);
> + uffdio_poison.range.len = page_size;
> +
> + SAFE_IOCTL(uffd, UFFDIO_POISON, &uffdio_poison);
> +
> + close(uffd);
> + return NULL;
> +}
> +
> +static void run(void)
> +{
> + pthread_t thr;
> + struct uffdio_api uffdio_api = {};
> + struct uffdio_register uffdio_register;
> + char dummy;
We still need to reset the poison_fault_seen and sigbus_seen flags here
for the case we run the test with -i 2
> + set_pages();
> +
> + uffd = SAFE_USERFAULTFD(O_CLOEXEC | O_NONBLOCK, false);
> +
> + uffdio_api.api = UFFD_API;
> + uffdio_api.features = UFFD_FEATURE_POISON;
> +
> + SAFE_IOCTL(uffd, UFFDIO_API, &uffdio_api);
> +
> + if (!(uffdio_api.features & UFFD_FEATURE_POISON))
> + tst_brk(TCONF, "UFFD_FEATURE_POISON not supported");
> +
> + uffdio_register.range.start = (unsigned long) page;
> + uffdio_register.range.len = page_size;
> + uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING;
> +
> + SAFE_IOCTL(uffd, UFFDIO_REGISTER, &uffdio_register);
> +
> + SAFE_PTHREAD_CREATE(&thr, NULL, (void *) handle_thread, NULL);
> +
> + /* Try to read from the page: should trigger fault, get poisoned, then SIGBUS */
> + if (sigsetjmp(jmpbuf, 1) == 0) {
> + LTP_VAR_USED(dummy) = page[0];
> + }
> +
> + SAFE_PTHREAD_JOIN(thr, NULL);
> + reset_pages();
> +
> + int poisoned = tst_atomic_load(&poison_fault_seen);
> +
> + if (poisoned && sigbus_seen)
> + tst_res(TPASS, "POISON successfully triggered SIGBUS");
> + else if (poison_fault_seen && !sigbus_seen)
^
poisoned?
> + tst_res(TFAIL, "POISON fault seen but no SIGBUS received");
> + else if (!poison_fault_seen && sigbus_seen)
^
poisoned
> + tst_res(TFAIL, "SIGBUS received but no poison fault seen");
> + else
> + tst_res(TFAIL, "No poison fault or SIGBUS observed");
> +}
> +
> +static struct tst_test test = {
> + .test_all = run,
> + .setup = setup,
> + .cleanup = reset_pages,
> +};
> --
> 2.53.0
>
>
> --
> Mailing list info: https://lists.linux.it/listinfo/ltp
--
Cyril Hrubis
chrubis@suse.cz
--
Mailing list info: https://lists.linux.it/listinfo/ltp
prev parent reply other threads:[~2026-03-02 10:24 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-02-26 11:54 [LTP] [PATCH v7] userfaultfd: Add test using UFFDIO_POISON Ricardo Branco
2026-03-02 10:24 ` Cyril Hrubis [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=aaVlS4eVHhDdSFOS@yuki.lan \
--to=chrubis@suse.cz \
--cc=et@yuki.lan \
--cc=ltp@lists.linux.it \
--cc=rbranco@suse.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.