[Bug 277382] Wrong stack growth for amd64 pthread stacks

From: <bugzilla-noreply_at_freebsd.org>
Date: Wed, 28 Feb 2024 20:46:52 UTC
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=277382

            Bug ID: 277382
           Summary: Wrong stack growth for amd64 pthread stacks
           Product: Base System
           Version: 14.0-RELEASE
          Hardware: Any
                OS: Any
            Status: New
          Severity: Affects Only Me
          Priority: ---
         Component: kern
          Assignee: bugs@FreeBSD.org
          Reporter: pjfloyd@wanadoo.fr

I've been trying to diagnose a Valgrind regression test failure since I moved
to using FreeBSD 14.0.

The test deliberately exceeds the thread's stack:

static void bad_things_till_guard_page(void)
{
   char j = 0;
   char *p = &j;

   for (;;) {
      j = j + *p;
      p = p - 400;
      lowest_j = p;
   }
}

Then it tries to describe where the eventual segfault happens. Prior to 14.0 it
correctly worked out that it was in the guard page below the stack. Not it just
say below the stack. Not the end of the world.

Here's what I see is happening.

When the stack is allocated, there is an mmap for 2M+4k. The bottom 4k is then
mprotect'd  to have PROT_NONE

mmap(0x1ffedfe000,2101248,PROT_READ|PROT_WRITE,MAP_FIXED|MAP_STACK,-1,0x0) =
137420070912 (0x1ffedfe000)
mprotect(0x1ffedfe000,4096,PROT_NONE)            = 0 (0x0)


Now that 2M above the guard page gets subdivided. The bottom 128k (controlled
by kern.sgrowsiz) is marked as the RW grow down stack and the remaining 2M-128k
is the growth guard area. As the thread uses more an more of its stack the
kernel will use up the free space 128k at a time.

Apart from the last chunk. That will be 128k - 4k (the 4k is controlled by
security.bsd.stack_guard_page which is in pages, default of 1). So at the end
there are, by default, two 4k guard pages left.

That looks like a bug to me. 

Back to Valgrind. All of those changes to the kern.sgrowsiz blocks of the stack
are invisible to Valgrind. It sees the 2M+4k mmap and the 4k mprotect so it
thinks that there is 2M of RW stack and then a 4k guard page. But the segfault
doesn't happen in the lowest guard page, it happens in the second one that is
above that. Valgrind doesn't see that as PROT_NONE so it fails to figure out
that it is a kind of guard page.

-- 
You are receiving this mail because:
You are the assignee for the bug.