The Linux Kernel Mailing List
 help / color / mirror / Atom feed
* [PATCH] prctl: fix PR_SET_MM_AUXV losing the forced AT_NULL terminator
@ 2026-08-09  0:29 Bradley Morgan
  2026-08-10  4:50 ` Alexey Dobriyan
  0 siblings, 1 reply; 2+ messages in thread
From: Bradley Morgan @ 2026-08-09  0:29 UTC (permalink / raw)
  To: akpm; +Cc: adobriyan, gorcunov, linux-kernel, include

prctl_set_auxv() copies the user vector into a stack buffer, forces
AT_NULL on the last two entries there, and then copies only len bytes
into mm->saved_auxv. Which is fine until the vector is shorter than
the buffer, because then the forced terminator sits past the end of
the copy and never lands in saved_auxv at all.

The code even says

	/* Make sure the last entry is always AT_NULL */

and it does, just not in the part that gets copied.

So mm->saved_auxv keeps the stale tail from exec. Reproducing it is
easy: from a process with CAP_SYS_RESOURCE (just run it as root),
call prctl(PR_SET_MM, PR_SET_MM_AUXV, ...) with a vector that has a
couple of entries and no AT_NULL inside len (32 bytes on arm64), and
then hexdump /proc/self/auxv, or gcore the process and look at the
AUXV note with readelf -n. This is arm64, the new vector was just
{ AT_UID, 0x1111, AT_GID, 0x2222 }:

    idx  before (from exec)               after the prctl
    [0]  AT_SYSINFO_EHDR   0x7ed1d6e000   AT_UID    0x1111    <- new
    [1]  AT_MINSIGSTKSZ    0x1270         AT_GID    0x2222    <- new
    [2]  AT_HWCAP          0x119fff       AT_HWCAP  0x119fff  <- stale
    [3]  AT_PAGESZ         0x1000         AT_PAGESZ 0x1000    <- stale
    ...  16 more entries                  ...                 <- stale
    [20] AT_NULL           0x0            AT_NULL   0x0

21 entries before the prctl, still 21 after: the two new ones plus
all 19 left over from exec.

Every consumer walks the vector until AT_NULL, so what they get now
is a vector that never existed at exec, the head from the prctl
glued onto the tail of the old binary. gdb and crash pull the AUXV
note out of coredumps to find AT_PHDR, AT_ENTRY, AT_SYSINFO_EHDR and
friends, and a mixed vector points them at the wrong layout.
/proc/<pid>/auxv and PR_GET_AUXV hand the same mess out to live
processes too. Nothing crashes, everything just quietly reads a
frankenstein auxv.

And callers that terminate their own vector hide the whole thing,
which is likely why nobody noticed since PR_SET_MM_AUXV landed in
2012. Nothing exciting security wise either, I mean it needs
CAP_SYS_RESOURCE to begin with.

prctl_set_mm_map() right above already copies the whole buffer for
exactly this reason, so just do the same here. user_auxv is zero
initialized and only partially filled from userspace, so the rest is
zeros and nothing leaks.

Fixes: fe8c7f5cbf91 ("c/r: prctl: extend PR_SET_MM to set up more mm_struct entries")
Signed-off-by: Bradley Morgan <include@grrlz.net>
---
 kernel/sys.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/kernel/sys.c b/kernel/sys.c
index df69bd71de03..35b538ba843c 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -2189,7 +2189,7 @@ static int prctl_set_auxv(struct mm_struct *mm, unsigned long addr,
 	BUILD_BUG_ON(sizeof(user_auxv) != sizeof(mm->saved_auxv));
 
 	task_lock(current);
-	memcpy(mm->saved_auxv, user_auxv, len);
+	memcpy(mm->saved_auxv, user_auxv, sizeof(user_auxv));
 	task_unlock(current);
 
 	return 0;
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH] prctl: fix PR_SET_MM_AUXV losing the forced AT_NULL terminator
  2026-08-09  0:29 [PATCH] prctl: fix PR_SET_MM_AUXV losing the forced AT_NULL terminator Bradley Morgan
@ 2026-08-10  4:50 ` Alexey Dobriyan
  0 siblings, 0 replies; 2+ messages in thread
From: Alexey Dobriyan @ 2026-08-10  4:50 UTC (permalink / raw)
  To: Bradley Morgan; +Cc: akpm, gorcunov, linux-kernel

On Sun, Aug 09, 2026 at 12:29:01AM +0000, Bradley Morgan wrote:
> prctl_set_auxv() copies the user vector into a stack buffer, forces
> AT_NULL on the last two entries there, and then copies only len bytes
> into mm->saved_auxv. Which is fine until the vector is shorter than
> the buffer, because then the forced terminator sits past the end of
> the copy and never lands in saved_auxv at all.

> --- a/kernel/sys.c
> +++ b/kernel/sys.c
> @@ -2189,7 +2189,7 @@ static int prctl_set_auxv(struct mm_struct *mm, unsigned long addr,
>  	BUILD_BUG_ON(sizeof(user_auxv) != sizeof(mm->saved_auxv));
>  
>  	task_lock(current);
> -	memcpy(mm->saved_auxv, user_auxv, len);
> +	memcpy(mm->saved_auxv, user_auxv, sizeof(user_auxv));
>  	task_unlock(current);

You're supposed to use prctl(PR_SET_MM_AUXV) with correct "len", yes.

This is userspace visible, warning could be added for another 14 years
and then line changed.

	PR_ALEXEY

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-08-10  4:46 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-09  0:29 [PATCH] prctl: fix PR_SET_MM_AUXV losing the forced AT_NULL terminator Bradley Morgan
2026-08-10  4:50 ` Alexey Dobriyan

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox