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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox