[PATCH] nplt: Fix MADV_GUARD_INSTALL logic for thread without guard page (BZ 33356)
Florian Weimer
fweimer@redhat.com
Mon Sep 8 14:15:17 GMT 2025
* Adhemerval Zanella:
> The main issue is that setup_stack_prot fails to account for cases where
> the cached thread stack lacks a guard page, which can cause madvise to
> fail. Update the logic to also handle whether MADV_GUARD_INSTALL is
> supported when resizing the guard page.
>
> Checked on x86_64-linux-gnu with 6.8.0 and 6.15 kernels.
(nptl typo, as mentioned)
> ---
> nptl/allocatestack.c | 22 +++++++++++++++++-----
> nptl/tst-guard1.c | 31 +++++++++++++++++++------------
> 2 files changed, 36 insertions(+), 17 deletions(-)
>
> diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c
> index 4c2aacdd10..61838eed8a 100644
> --- a/nptl/allocatestack.c
> +++ b/nptl/allocatestack.c
> @@ -234,7 +234,7 @@ setup_stack_prot (char *mem, size_t size, struct pthread *pd,
> /* Update the guard area of the thread stack MEM of size SIZE with the new
> GUARDISZE. It uses the method defined by PD stack_mode. */
> static inline bool
> -adjust_stack_prot (char *mem, size_t size, const struct pthread *pd,
> +adjust_stack_prot (char *mem, size_t size, struct pthread *pd,
> size_t guardsize, size_t pagesize_m1)
> {
> /* The required guard area is larger than the current one. For
> @@ -252,11 +252,23 @@ adjust_stack_prot (char *mem, size_t size, const struct pthread *pd,
> so use the new guard placement with the new size. */
> if (guardsize > pd->guardsize)
> {
> + /* There was no need to previously setup a guard parge, so we need
typo: pa[]ge
> + check whether the kernel supports guard advise. */
typo: need [to] check
> char *guard = guard_position (mem, size, guardsize, pd, pagesize_m1);
> - if (pd->stack_mode == ALLOCATE_GUARD_MADV_GUARD)
> - return __madvise (guard, guardsize, MADV_GUARD_INSTALL) == 0;
> - else if (pd->stack_mode == ALLOCATE_GUARD_PROT_NONE)
> - return __mprotect (guard, guardsize, PROT_NONE) == 0;
> + if (atomic_load_relaxed (&allocate_stack_mode)
> + == ALLOCATE_GUARD_MADV_GUARD)
> + {
> + if (__madvise (guard, guardsize, MADV_GUARD_INSTALL) == 0)
> + {
> + pd->stack_mode = ALLOCATE_GUARD_MADV_GUARD;
> + return true;
> + }
> + atomic_store_relaxed (&allocate_stack_mode,
> + ALLOCATE_GUARD_PROT_NONE);
> + }
> +
> + pd->stack_mode = ALLOCATE_GUARD_PROT_NONE;
> + return __mprotect (guard, guardsize, PROT_NONE) == 0;
> }
> /* The current guard area is larger than the required one. For
> _STACK_GROWS_DOWN is means change the guard as:
> diff --git a/nptl/tst-guard1.c b/nptl/tst-guard1.c
> index e3e06df0fc..2c597a6a34 100644
> --- a/nptl/tst-guard1.c
> +++ b/nptl/tst-guard1.c
> @@ -250,18 +250,9 @@ do_test2 (void)
> xmunmap (stack, stacksize);
> }
I'd suggest to run each test after fork, in separate processes, and then
once in the same process, for better test coverage.
> @@ -350,8 +350,15 @@ do_test (void)
> } tests[] = {
> { "user provided stack without guard", do_test1 },
> { "user provided stack with guard", do_test2 },
> - { "default attribute", do_test3 },
> - { "default attribute without guard", do_test4 },
> + /* N.B: do_test3 should be before do_test4 to check if a new thread
> + that uses the thread stack previously allocated without a guard
> + page correctly setup the guard pages even on kernel without
> + MADV_GUARD_INSTALL support (BZ 33356). */
typos: set[s ]up, on [a] kernel
Thanks,
Florian
More information about the Libc-alpha
mailing list