Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250321211201.GJ1827@brightrain.aerifal.cx>
Date: Fri, 21 Mar 2025 17:12:01 -0400
From: Rich Felker <dalias@...c.org>
To: MouriNaruto <mourinaruto@...il.com>
Cc: musl@...ts.openwall.com, MouriNaruto <Kenji.Mouri@...look.com>
Subject: Re: [PATCH] workaround the issue that pthread_getattr_np
 won't return in FreeBSD Linuxulator

On Sat, Mar 22, 2025 at 01:04:16AM +0800, MouriNaruto wrote:
> Some notes from Kenji Mouri (MouriNaruto) about this workaround:
> 
> I tried to use musl-based userspace in FreeBSD's Linuxulator, I found some
> Node.js based app will hung at startup. I did some investigations and finally
> found that caused by the mremap loop in the musl's pthread_getattr_np. I read
> the FreeBSD's Linuxulator source code, it seems mremap in FreeBSD's Linuxulator
> in won't support expand the size.
> 
> With Edward Tomasz Napierala (https://wiki.freebsd.org/EdwardTomaszNapierala)'s
> suggestion, choose to use RLIMIT_STACK _in addition_ to the current measurement
> can workaround the issue without doing much modifications.
> 
> Consider that getrlimit may failed, so I think we should use __default_stacksize
> when getrlimit failed.
> 
> I have tested this commit in my FreeBSD environment with Visual Studio Code
> Remote SSH server which requires the FreeBSD's Linuxulator.
> ---
>  src/thread/pthread_getattr_np.c | 11 ++++++++++-
>  1 file changed, 10 insertions(+), 1 deletion(-)
> 
> diff --git a/src/thread/pthread_getattr_np.c b/src/thread/pthread_getattr_np.c
> index 2881831f..54b1ba34 100644
> --- a/src/thread/pthread_getattr_np.c
> +++ b/src/thread/pthread_getattr_np.c
> @@ -2,6 +2,7 @@
>  #include "pthread_impl.h"
>  #include "libc.h"
>  #include <sys/mman.h>
> +#include <sys/resource.h>
>  
>  int pthread_getattr_np(pthread_t t, pthread_attr_t *a)
>  {
> @@ -12,11 +13,19 @@ int pthread_getattr_np(pthread_t t, pthread_attr_t *a)
>  		a->_a_stackaddr = (uintptr_t)t->stack;
>  		a->_a_stacksize = t->stack_size;
>  	} else {
> +		struct rlimit rl_stack = {0};
> +		/* get the current stack limit to workaround the issue */
> +		/* that mremap loop won't stop in FreeBSD Linuxulator */
> +		if (getrlimit(RLIMIT_STACK, &rl_stack) != 0) {
> +			/* use default stack size if getrlimit fails */
> +			rl_stack.rlim_cur = __default_stacksize;
> +			rl_stack.rlim_max = __default_stacksize;
> +		}
>  		char *p = (void *)libc.auxv;
>  		size_t l = PAGE_SIZE;
>  		p += -(uintptr_t)p & PAGE_SIZE-1;
>  		a->_a_stackaddr = (uintptr_t)p;
> -		while (mremap(p-l-PAGE_SIZE, PAGE_SIZE, 2*PAGE_SIZE, 0)==MAP_FAILED && errno==ENOMEM)
> +		while (l <= rl_stack.rlim_cur && mremap(p-l-PAGE_SIZE, PAGE_SIZE, 2*PAGE_SIZE, 0)==MAP_FAILED && errno==ENOMEM)
>  			l += PAGE_SIZE;
>  		a->_a_stacksize = l;
>  	}
> -- 
> 2.47.2

This change isn't acceptable upstream - it will necessarily return a
size that can be smaller than the actual stack, if the rlimit has been
lowered, by stopping the scan early. In fact, if you reach the rlimit
without the loop ending, you know either one of two things is true:
either the FreeBSD Linux emulation bug is present, or the stack is
already larger than the current rlimit.

If you have ideas for other ways to scan for the actual limit, I'm
open to hearing them, but I think it would make sense first to see if
FreeBSD could just fix the error code to reflect whether there's a
mapping present. I looked at the old mincore interface but it seems to
only tell if it's currently paged in, not if it's mapped. There's
procfs which could be used if mounted, but that's more of a pain to
work with and not always present, and I'm not sure it would help on
FreeBSD anyway.

Rich

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.