From: Konstantin Khorenko <khorenko@virtuozzo.com>
To: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>,
Pavel Tikhomirov <ptikhomirov@virtuozzo.com>,
Vasileios Almpanis <vasileios.almpanis@virtuozzo.com>
Cc: devel@openvz.org
Subject: [Devel] [PATCH hci-8.1 v2 9/9] selftests/mm: do not lose doexec failures
Date: Wed, 21 Oct 2026 18:57:22 +0200 [thread overview]
Message-ID: <20261021-b4-prep-khorenko-vstor-149847-5-doexec-selftests-v2-9-97dbb5c6e0ab@virtuozzo.com> (raw)
In-Reply-To: <20261021-b4-prep-khorenko-vstor-149847-5-doexec-selftests-v2-0-97dbb5c6e0ab@virtuozzo.com>
Some doexec failures can go unreported:
- write() results are ignored. The clone race reports a failure by
writing to a pipe, so a failed write turns it into a pass, and a
failed wake-up write leaves a shared-mm child blocked forever. glibc
warns about these with _FORTIFY_SOURCE.
- The allocation failure sweep prints the failing exec and calls
_exit() without flushing stdout, so under a pipe the message is lost.
- The writes that disarm fail-nth are not checked, so injection could
still hit the checks that follow a failed disarm.
Check every write(), abort when a race failure cannot be reported, and
flush stdout before that _exit().
https://virtuozzo.atlassian.net/browse/VSTOR-150234
Feature: oracle/mm: MADV_DOEXEC madvise() flag
Assisted-by: LLM
Signed-off-by: Konstantin Khorenko <khorenko@virtuozzo.com>
---
tools/testing/selftests/mm/doexec.c | 30 ++++++++++++++++++++++--------
1 file changed, 22 insertions(+), 8 deletions(-)
diff --git a/tools/testing/selftests/mm/doexec.c b/tools/testing/selftests/mm/doexec.c
index 7e73a98e4ec2a..561e07b4444f0 100644
--- a/tools/testing/selftests/mm/doexec.c
+++ b/tools/testing/selftests/mm/doexec.c
@@ -441,7 +441,8 @@ static int shared_mm_exec(bool own_thread)
if (pthread_create(&thread, NULL, blocked_thread, &pipe_fd[0]))
return fail("pthread_create failed");
check_exec(ram, size, 1, false);
- write(pipe_fd[1], "x", 1);
+ if (write(pipe_fd[1], "x", 1) != 1)
+ return fail_errno("write");
pthread_join(thread, NULL);
return KSFT_FAIL;
}
@@ -460,7 +461,10 @@ static int shared_mm_exec(bool own_thread)
} else {
ret = check_bytes(ram, size, 0x31) ? fail("contents lost") : KSFT_PASS;
}
- write(pipe_fd[1], "x", 1);
+ if (write(pipe_fd[1], "x", 1) != 1) {
+ ret = fail_errno("write");
+ kill(pid, SIGKILL);
+ }
if (wait_child(pid))
ret = KSFT_FAIL;
if (ret)
@@ -966,6 +970,13 @@ struct clone_race {
atomic_uint rounds;
};
+/* A failure that cannot reach the supervisor must still fail the test. */
+static void report_failure(struct clone_race *race)
+{
+ if (write(race->report, "x", 1) != 1)
+ abort();
+}
+
static int clone_race_child(void *arg)
{
struct clone_race *race = arg;
@@ -973,7 +984,7 @@ static int clone_race_child(void *arg)
for (i = 0; i < 8; i++) {
if (__atomic_load_n(race->ram, __ATOMIC_RELAXED) != 0x31) {
- write(race->report, "x", 1);
+ report_failure(race);
return KSFT_FAIL;
}
usleep(1000);
@@ -989,7 +1000,7 @@ static void *clone_race_thread(void *arg)
pid_t pid;
if (stack == MAP_FAILED) {
- write(race->report, "x", 1);
+ report_failure(race);
atomic_store(&race->rounds, 4);
return NULL;
}
@@ -998,9 +1009,9 @@ static void *clone_race_thread(void *arg)
CLONE_VM | SIGCHLD, race);
if (pid >= 0) {
if (wait_child(pid))
- write(race->report, "x", 1);
+ report_failure(race);
} else if (errno != EBUSY && errno != EINTR) {
- write(race->report, "x", 1);
+ report_failure(race);
}
atomic_fetch_add(&race->rounds, 1);
usleep(1000);
@@ -1122,7 +1133,8 @@ static int allocation_failures(void)
_exit(fail_errno("fail-nth setup"));
err = check_exec_fd(exe, ram, size, stride);
/* Disarm before checking mappings or exiting. */
- pwrite(fd, "0", 1, 0);
+ if (pwrite(fd, "0", 1, 0) != 1)
+ _exit(fail_errno("fail-nth disarm"));
for (i = 0; i < size; i += stride)
if (ram[i] != 0x31)
_exit(fail("contents lost by a failed exec"));
@@ -1135,6 +1147,7 @@ static int allocation_failures(void)
err == E2BIG || err == ELIBBAD || err == EIO)
_exit(10);
ksft_print_msg("fail-nth %u: exec: %s\n", nth, strerror(err));
+ fflush(stdout);
_exit(KSFT_FAIL);
}
do {
@@ -2395,7 +2408,8 @@ int main(int argc, char **argv)
int fd = open("/proc/self/fail-nth", O_WRONLY);
if (fd >= 0) {
- write(fd, "0", 1);
+ if (write(fd, "0", 1) != 1)
+ return fail_errno("fail-nth disarm");
close(fd);
}
if (!range_mapped(ram, size))
--
2.43.0
_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel
next prev parent reply other threads:[~2026-10-21 16:59 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-21 16:57 [Devel] [PATCH hci-8.1 v2 0/9] selftests/mm: broader MADV_DOEXEC coverage Konstantin Khorenko
2026-10-21 16:57 ` [Devel] [PATCH hci-8.1 v2 1/9] selftests/mm: cover the MADV_DOEXEC interface and VMA attributes Konstantin Khorenko
2026-10-21 16:57 ` [Devel] [PATCH hci-8.1 v2 2/9] selftests/mm: cover the MADV_DOEXEC opt-in note and the new stack Konstantin Khorenko
2026-10-21 16:57 ` [Devel] [PATCH hci-8.1 v2 3/9] selftests/mm: cover large, swapped and partly marked THP ranges Konstantin Khorenko
2026-10-21 16:57 ` [Devel] [PATCH hci-8.1 v2 4/9] selftests/mm: check that MADV_DOEXEC refuses an exec from a vfork() child Konstantin Khorenko
2026-10-21 16:57 ` [Devel] [PATCH hci-8.1 v2 5/9] selftests/mm: check VM_MAYEXEC of MADV_DOEXEC ranges in smaps Konstantin Khorenko
2026-10-21 16:57 ` [Devel] [PATCH hci-8.1 v2 6/9] selftests/mm: check who can still reach the old mm of a preserving exec Konstantin Khorenko
2026-10-21 16:57 ` [Devel] [PATCH hci-8.1 v2 7/9] selftests/mm: say why a doexec case fails Konstantin Khorenko
2026-10-21 16:57 ` [Devel] [PATCH hci-8.1 v2 8/9] selftests/mm: run repeated live updates through MADV_DOEXEC Konstantin Khorenko
2026-10-21 16:57 ` Konstantin Khorenko [this message]
2026-11-04 19:22 ` [Devel] [PATCH hci-8.1 v2 0/9] selftests/mm: broader MADV_DOEXEC coverage Konstantin Khorenko
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=20261021-b4-prep-khorenko-vstor-149847-5-doexec-selftests-v2-9-97dbb5c6e0ab@virtuozzo.com \
--to=khorenko@virtuozzo.com \
--cc=andrey.drobyshev@virtuozzo.com \
--cc=devel@openvz.org \
--cc=ptikhomirov@virtuozzo.com \
--cc=vasileios.almpanis@virtuozzo.com \
/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.