From: Andrea Cervesato via ltp <ltp@lists.linux.it>
To: "Ricardo Branco" <rbranco@suse.de>, <ltp@lists.linux.it>
Subject: Re: [LTP] [PATCH v3] userfaultfd: Add test using UFFDIO_POISON
Date: Thu, 19 Feb 2026 10:54:42 +0100 [thread overview]
Message-ID: <DGIUIYEL9H07.TK6CF1O2WP7H@suse.com> (raw)
In-Reply-To: <20260218135026.159676-1-rbranco@suse.de>
Hi!
On Wed Feb 18, 2026 at 2:50 PM CET, Ricardo Branco wrote:
> Signed-off-by: Ricardo Branco <rbranco@suse.de>
> ---
> configure.ac | 1 +
> include/lapi/userfaultfd.h | 13 ++
> .../kernel/syscalls/userfaultfd/.gitignore | 1 +
> .../kernel/syscalls/userfaultfd/Makefile | 1 +
> .../syscalls/userfaultfd/userfaultfd06.c | 134 ++++++++++++++++++
> 5 files changed, 150 insertions(+)
> create mode 100644 testcases/kernel/syscalls/userfaultfd/userfaultfd06.c
>
> diff --git a/configure.ac b/configure.ac
> index 7fa614dcb..94bcbcc98 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -278,6 +278,7 @@ AC_CHECK_TYPES([struct sockaddr_vm],,,[
> ])
>
> AC_CHECK_TYPES([struct uffdio_move],,,[#include <linux/userfaultfd.h>])
> +AC_CHECK_TYPES([struct uffdio_poison],,,[#include <linux/userfaultfd.h>])
> AC_CHECK_TYPES([struct uffdio_writeprotect],,,[#include <linux/userfaultfd.h>])
>
> # Tools knobs
> diff --git a/include/lapi/userfaultfd.h b/include/lapi/userfaultfd.h
> index 0c9e34c84..aab3890b7 100644
> --- a/include/lapi/userfaultfd.h
> +++ b/include/lapi/userfaultfd.h
> @@ -233,6 +233,19 @@ struct uffdio_writeprotect {
> };
> #endif /* HAVE_STRUCT_UFFDIO_WRITEPROTECT */
>
> +#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/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..c4546acce
> --- /dev/null
> +++ b/testcases/kernel/syscalls/userfaultfd/userfaultfd06.c
> @@ -0,0 +1,134 @@
> +// 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 volatile 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 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);
> +
> + poison_fault_seen = 1;
> +
> + /* 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;
> + struct sigaction sa = {};
> + volatile char dummy;
> +
> + sa.sa_handler = sigbus_handler;
> + sigemptyset(&sa.sa_mask);
> + SAFE_SIGACTION(SIGBUS, &sa, NULL);
> +
> + 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);
> +
> + 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) {
> + dummy = page[0];
> + (void)dummy;
> + }
> +
> + SAFE_PTHREAD_JOIN(thr, NULL);
> + reset_pages();
This should also go into a cleanup(), otherwise if other syscalls will
fail (ioctl for instance), memory will be lost.
> +
> + if (poison_fault_seen && sigbus_seen) {
> + tst_res(TPASS, "POISON successfully triggered SIGBUS");
> + } else if (poison_fault_seen && !sigbus_seen) {
> + tst_res(TFAIL, "POISON fault seen but no SIGBUS received");
> + } else if (!poison_fault_seen && sigbus_seen) {
> + 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,
> + .min_kver = "6.6",
This is not needed, we should use UFFDIO_API instead, in order to verify
that UFFD_FEATURE_POISON is present and eventually TCONF.
Also, if I run checkpatch.pl on the code I get:
WARNING: Use of volatile is usually wrong: see Documentation/process/volatile-considered-harmful.rst
#25: FILE: userfaultfd06.c:25:
+static volatile int poison_fault_seen;
WARNING: Use of volatile is usually wrong: see Documentation/process/volatile-considered-harmful.rst
#26: FILE: userfaultfd06.c:26:
+static volatile int sigbus_seen;
WARNING: Use of volatile is usually wrong: see Documentation/process/volatile-considered-harmful.rst
#88: FILE: userfaultfd06.c:88:
+ volatile char dummy;
WARNING: braces {} are not necessary for any arm of this statement
#120: FILE: userfaultfd06.c:120:
+ if (poison_fault_seen && sigbus_seen) {
[...]
+ } else if (poison_fault_seen && !sigbus_seen) {
[...]
+ } else if (!poison_fault_seen && sigbus_seen) {
[...]
+ } else {
[...]
total: 0 errors, 4 warnings, 134 lines checked
NOTE: For some of the reported defects, checkpatch may be able to
mechanically convert to the typical style using --fix or --fix-inplace.
userfaultfd06.c has style problems, please review.
NOTE: If any of the errors are false positives, please report
them to the maintainer, see CHECKPATCH in MAINTAINERS.
If you have `b4`, please run `b4 prep --check` before sending the patch.
--
Andrea Cervesato
SUSE QE Automation Engineer Linux
andrea.cervesato@suse.com
--
Mailing list info: https://lists.linux.it/listinfo/ltp
next prev parent reply other threads:[~2026-02-19 9:55 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-02-18 13:50 [LTP] [PATCH v3] userfaultfd: Add test using UFFDIO_POISON Ricardo Branco
2026-02-19 9:54 ` Andrea Cervesato via ltp [this message]
2026-02-19 11:21 ` Ricardo Branco
2026-02-19 11:34 ` Andrea Cervesato via ltp
2026-02-19 11:24 ` Cyril Hrubis
2026-02-19 11:28 ` Andrea Cervesato via ltp
2026-02-19 13:15 ` Cyril Hrubis
2026-02-19 11:37 ` Andrea Cervesato via ltp
2026-02-19 13:26 ` Ricardo Branco
2026-02-19 15:52 ` Cyril Hrubis
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=DGIUIYEL9H07.TK6CF1O2WP7H@suse.com \
--to=ltp@lists.linux.it \
--cc=andrea.cervesato@suse.com \
--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.