Copy out aux args after the argument and environment vectors.

Partially revert r354741 and r354754 and go back to allocating a
fixed-size chunk of stack space for the auxiliary vector.  Keep
sv_copyout_auxargs but change it to accept the address at the end of
the environment vector as an input stack address and no longer
allocate room on the stack.  It is now called at the end of
copyout_strings after the argv and environment vectors have been
copied out.

This should fix a regression in r354754 that broke the stack alignment
for newer Linux amd64 binaries (and probably broke Linux arm64 as
well).

Reviewed by:	kib
Tested on:	amd64 (native, linux64 (only linux-base-c7), and i386)
Sponsored by:	DARPA
Differential Revision:	https://reviews.freebsd.org/D22695
This commit is contained in:
John Baldwin 2019-12-09 19:17:28 +00:00
parent 168bde45c2
commit d8010b1175
9 changed files with 106 additions and 52 deletions

View File

@ -224,11 +224,10 @@ linux_set_syscall_retval(struct thread *td, int error)
} }
static int static int
linux_copyout_auxargs(struct image_params *imgp, uintptr_t *base) linux_copyout_auxargs(struct image_params *imgp, uintptr_t base)
{ {
Elf_Auxargs *args; Elf_Auxargs *args;
Elf_Auxinfo *argarray, *pos; Elf_Auxinfo *argarray, *pos;
u_long auxlen;
struct proc *p; struct proc *p;
int error, issetugid; int error, issetugid;
@ -266,9 +265,8 @@ linux_copyout_auxargs(struct image_params *imgp, uintptr_t *base)
imgp->auxargs = NULL; imgp->auxargs = NULL;
KASSERT(pos - argarray <= LINUX_AT_COUNT, ("Too many auxargs")); KASSERT(pos - argarray <= LINUX_AT_COUNT, ("Too many auxargs"));
auxlen = sizeof(*argarray) * (pos - argarray); error = copyout(argarray, (void *)base,
*base -= auxlen; sizeof(*argarray) * LINUX_AT_COUNT);
error = copyout(argarray, (void *)*base, auxlen);
free(argarray, M_TEMP); free(argarray, M_TEMP);
return (error); return (error);
} }
@ -336,17 +334,13 @@ linux_copyout_strings(struct image_params *imgp, uintptr_t *stack_base)
destp = rounddown2(destp, sizeof(void *)); destp = rounddown2(destp, sizeof(void *));
ustringp = destp; ustringp = destp;
/*
* Starting with 2.24, glibc depends on a 16-byte stack alignment.
* One "long argc" will be prepended later.
*/
if (destp % 16 == 0)
destp -= 8;
if (imgp->auxargs) { if (imgp->auxargs) {
error = imgp->sysent->sv_copyout_auxargs(imgp, &destp); /*
if (error != 0) * Allocate room on the stack for the ELF auxargs
return (error); * array. It has LINUX_AT_COUNT entries.
*/
destp -= LINUX_AT_COUNT * sizeof(Elf64_Auxinfo);
destp = rounddown2(destp, sizeof(void *));
} }
vectp = (char **)destp; vectp = (char **)destp;
@ -357,6 +351,12 @@ linux_copyout_strings(struct image_params *imgp, uintptr_t *stack_base)
*/ */
vectp -= imgp->args->argc + 1 + imgp->args->envc + 1; vectp -= imgp->args->argc + 1 + imgp->args->envc + 1;
/*
* Starting with 2.24, glibc depends on a 16-byte stack alignment.
* One "long argc" will be prepended later.
*/
vectp = (char **)((((uintptr_t)vectp + 8) & ~0xF) - 8);
/* vectp also becomes our initial stack base. */ /* vectp also becomes our initial stack base. */
*stack_base = (uintptr_t)vectp; *stack_base = (uintptr_t)vectp;
@ -405,6 +405,14 @@ linux_copyout_strings(struct image_params *imgp, uintptr_t *stack_base)
if (suword(vectp, 0) != 0) if (suword(vectp, 0) != 0)
return (EFAULT); return (EFAULT);
if (imgp->auxargs) {
vectp++;
error = imgp->sysent->sv_copyout_auxargs(imgp,
(uintptr_t)vectp);
if (error != 0)
return (error);
}
return (0); return (0);
} }

View File

@ -187,11 +187,10 @@ linux_translate_traps(int signal, int trap_code)
} }
static int static int
linux_copyout_auxargs(struct image_params *imgp, u_long *base) linux_copyout_auxargs(struct image_params *imgp, uintptr_t base)
{ {
Elf32_Auxargs *args; Elf32_Auxargs *args;
Elf32_Auxinfo *argarray, *pos; Elf32_Auxinfo *argarray, *pos;
u_long auxlen;
int error, issetugid; int error, issetugid;
args = (Elf32_Auxargs *)imgp->auxargs; args = (Elf32_Auxargs *)imgp->auxargs;
@ -238,9 +237,8 @@ linux_copyout_auxargs(struct image_params *imgp, u_long *base)
imgp->auxargs = NULL; imgp->auxargs = NULL;
KASSERT(pos - argarray <= LINUX_AT_COUNT, ("Too many auxargs")); KASSERT(pos - argarray <= LINUX_AT_COUNT, ("Too many auxargs"));
auxlen = sizeof(*argarray) * (pos - argarray); error = copyout(argarray, (void *)base,
*base -= auxlen; sizeof(*argarray) * LINUX_AT_COUNT);
error = copyout(argarray, (void *)*base, auxlen);
free(argarray, M_TEMP); free(argarray, M_TEMP);
return (error); return (error);
} }
@ -764,9 +762,12 @@ linux_copyout_strings(struct image_params *imgp, uintptr_t *stack_base)
ustringp = destp; ustringp = destp;
if (imgp->auxargs) { if (imgp->auxargs) {
error = imgp->sysent->sv_copyout_auxargs(imgp, &destp); /*
if (error != 0) * Allocate room on the stack for the ELF auxargs
return (error); * array. It has LINUX_AT_COUNT entries.
*/
destp -= LINUX_AT_COUNT * sizeof(Elf32_Auxinfo);
destp = rounddown2(destp, sizeof(void *));
} }
vectp = (uint32_t *)destp; vectp = (uint32_t *)destp;
@ -825,6 +826,14 @@ linux_copyout_strings(struct image_params *imgp, uintptr_t *stack_base)
if (suword32(vectp, 0) != 0) if (suword32(vectp, 0) != 0)
return (EFAULT); return (EFAULT);
if (imgp->auxargs) {
vectp++;
error = imgp->sysent->sv_copyout_auxargs(imgp,
(uintptr_t)vectp);
if (error != 0)
return (error);
}
return (0); return (0);
} }

View File

@ -143,11 +143,10 @@ linux_set_syscall_retval(struct thread *td, int error)
} }
static int static int
linux_copyout_auxargs(struct image_params *imgp, uintptr_t *base) linux_copyout_auxargs(struct image_params *imgp, uintptr_t base)
{ {
Elf_Auxargs *args; Elf_Auxargs *args;
Elf_Auxinfo *argarray, *pos; Elf_Auxinfo *argarray, *pos;
u_long auxlen;
struct proc *p; struct proc *p;
int error, issetugid; int error, issetugid;
@ -190,9 +189,8 @@ linux_copyout_auxargs(struct image_params *imgp, uintptr_t *base)
imgp->auxargs = NULL; imgp->auxargs = NULL;
KASSERT(pos - argarray <= LINUX_AT_COUNT, ("Too many auxargs")); KASSERT(pos - argarray <= LINUX_AT_COUNT, ("Too many auxargs"));
auxlen = sizeof(*argarray) * (pos - argarray); error = copyout(argarray, (void *)base,
*base -= auxlen; sizeof(*argarray) * LINUX_AT_COUNT);
error = copyout(argarray, (void *)*base, auxlen);
free(argarray, M_TEMP); free(argarray, M_TEMP);
return (error); return (error);
} }
@ -257,9 +255,12 @@ linux_copyout_strings(struct image_params *imgp, uintptr_t *stack_base)
ustringp = destp; ustringp = destp;
if (imgp->auxargs) { if (imgp->auxargs) {
error = imgp->sysent->sv_copyout_auxargs(imgp, &destp); /*
if (error != 0) * Allocate room on the stack for the ELF auxargs
return (error); * array. It has up to LINUX_AT_COUNT entries.
*/
destp -= LINUX_AT_COUNT * sizeof(Elf64_Auxinfo);
destp = rounddown2(destp, sizeof(void *));
} }
vectp = (char **)destp; vectp = (char **)destp;
@ -322,6 +323,14 @@ linux_copyout_strings(struct image_params *imgp, uintptr_t *stack_base)
if (suword(vectp, 0) != 0) if (suword(vectp, 0) != 0)
return (EFAULT); return (EFAULT);
if (imgp->auxargs) {
vectp++;
error = imgp->sysent->sv_copyout_auxargs(imgp,
(uintptr_t)vectp);
if (error != 0)
return (error);
}
return (0); return (0);
} }

View File

@ -3206,9 +3206,12 @@ freebsd32_copyout_strings(struct image_params *imgp, uintptr_t *stack_base)
imgp->sysent->sv_stackgap(imgp, &destp); imgp->sysent->sv_stackgap(imgp, &destp);
if (imgp->auxargs) { if (imgp->auxargs) {
error = imgp->sysent->sv_copyout_auxargs(imgp, &destp); /*
if (error != 0) * Allocate room on the stack for the ELF auxargs
return (error); * array. It has up to AT_COUNT entries.
*/
destp -= AT_COUNT * sizeof(Elf32_Auxinfo);
destp = rounddown2(destp, sizeof(uint32_t));
} }
vectp = (uint32_t *)destp; vectp = (uint32_t *)destp;
@ -3276,6 +3279,14 @@ freebsd32_copyout_strings(struct image_params *imgp, uintptr_t *stack_base)
if (suword32(vectp, 0) != 0) if (suword32(vectp, 0) != 0)
return (EFAULT); return (EFAULT);
if (imgp->auxargs) {
vectp++;
error = imgp->sysent->sv_copyout_auxargs(imgp,
(uintptr_t)vectp);
if (error != 0)
return (error);
}
return (0); return (0);
} }

View File

@ -192,14 +192,13 @@ linux_fixup(uintptr_t *stack_base, struct image_params *imgp)
} }
static int static int
linux_copyout_auxargs(struct image_params *imgp, uintptr_t *base) linux_copyout_auxargs(struct image_params *imgp, uintptr_t base)
{ {
struct proc *p; struct proc *p;
Elf32_Auxargs *args; Elf32_Auxargs *args;
Elf32_Auxinfo *argarray, *pos; Elf32_Auxinfo *argarray, *pos;
Elf32_Addr *uplatform; Elf32_Addr *uplatform;
struct ps_strings *arginfo; struct ps_strings *arginfo;
u_long auxlen;
int error, issetugid; int error, issetugid;
p = imgp->proc; p = imgp->proc;
@ -249,9 +248,8 @@ linux_copyout_auxargs(struct image_params *imgp, uintptr_t *base)
imgp->auxargs = NULL; imgp->auxargs = NULL;
KASSERT(pos - argarray <= LINUX_AT_COUNT, ("Too many auxargs")); KASSERT(pos - argarray <= LINUX_AT_COUNT, ("Too many auxargs"));
auxlen = sizeof(*argarray) * (pos - argarray); error = copyout(argarray, (void *)base,
*base -= auxlen; sizeof(*argarray) * LINUX_AT_COUNT);
error = copyout(argarray, (void *)*base, auxlen);
free(argarray, M_TEMP); free(argarray, M_TEMP);
return (error); return (error);
} }
@ -323,9 +321,12 @@ linux_copyout_strings(struct image_params *imgp, uintptr_t *stack_base)
ustringp = destp; ustringp = destp;
if (imgp->auxargs) { if (imgp->auxargs) {
error = imgp->sysent->sv_copyout_auxargs(imgp, &destp); /*
if (error != 0) * Allocate room on the stack for the ELF auxargs
return (error); * array. It has LINUX_AT_COUNT entries.
*/
destp -= LINUX_AT_COUNT * sizeof(Elf32_Auxinfo);
destp = rounddown2(destp, sizeof(void *));
} }
vectp = (char **)destp; vectp = (char **)destp;
@ -384,6 +385,14 @@ linux_copyout_strings(struct image_params *imgp, uintptr_t *stack_base)
if (suword(vectp, 0) != 0) if (suword(vectp, 0) != 0)
return (EFAULT); return (EFAULT);
if (imgp->auxargs) {
vectp++;
error = imgp->sysent->sv_copyout_auxargs(imgp,
(uintptr_t)vectp);
if (error != 0)
return (error);
}
return (0); return (0);
} }

View File

@ -1324,11 +1324,10 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
#define suword __CONCAT(suword, __ELF_WORD_SIZE) #define suword __CONCAT(suword, __ELF_WORD_SIZE)
int int
__elfN(freebsd_copyout_auxargs)(struct image_params *imgp, uintptr_t *base) __elfN(freebsd_copyout_auxargs)(struct image_params *imgp, uintptr_t base)
{ {
Elf_Auxargs *args = (Elf_Auxargs *)imgp->auxargs; Elf_Auxargs *args = (Elf_Auxargs *)imgp->auxargs;
Elf_Auxinfo *argarray, *pos; Elf_Auxinfo *argarray, *pos;
u_long auxlen;
int error; int error;
argarray = pos = malloc(AT_COUNT * sizeof(*pos), M_TEMP, argarray = pos = malloc(AT_COUNT * sizeof(*pos), M_TEMP,
@ -1374,9 +1373,7 @@ __elfN(freebsd_copyout_auxargs)(struct image_params *imgp, uintptr_t *base)
imgp->auxargs = NULL; imgp->auxargs = NULL;
KASSERT(pos - argarray <= AT_COUNT, ("Too many auxargs")); KASSERT(pos - argarray <= AT_COUNT, ("Too many auxargs"));
auxlen = sizeof(*argarray) * (pos - argarray); error = copyout(argarray, (void *)base, sizeof(*argarray) * AT_COUNT);
*base -= auxlen;
error = copyout(argarray, (void *)*base, auxlen);
free(argarray, M_TEMP); free(argarray, M_TEMP);
return (error); return (error);
} }

View File

@ -1661,9 +1661,12 @@ exec_copyout_strings(struct image_params *imgp, uintptr_t *stack_base)
imgp->sysent->sv_stackgap(imgp, &destp); imgp->sysent->sv_stackgap(imgp, &destp);
if (imgp->auxargs) { if (imgp->auxargs) {
error = imgp->sysent->sv_copyout_auxargs(imgp, &destp); /*
if (error != 0) * Allocate room on the stack for the ELF auxargs
return (error); * array. It has up to AT_COUNT entries.
*/
destp -= AT_COUNT * sizeof(Elf_Auxinfo);
destp = rounddown2(destp, sizeof(void *));
} }
vectp = (char **)destp; vectp = (char **)destp;
@ -1732,6 +1735,14 @@ exec_copyout_strings(struct image_params *imgp, uintptr_t *stack_base)
if (suword(vectp, 0) != 0) if (suword(vectp, 0) != 0)
return (EFAULT); return (EFAULT);
if (imgp->auxargs) {
vectp++;
error = imgp->sysent->sv_copyout_auxargs(imgp,
(uintptr_t)vectp);
if (error != 0)
return (error);
}
return (0); return (0);
} }

View File

@ -99,7 +99,7 @@ int __elfN(freebsd_fixup)(uintptr_t *, struct image_params *);
int __elfN(coredump)(struct thread *, struct vnode *, off_t, int); int __elfN(coredump)(struct thread *, struct vnode *, off_t, int);
size_t __elfN(populate_note)(int, void *, void *, size_t, void **); size_t __elfN(populate_note)(int, void *, void *, size_t, void **);
void __elfN(stackgap)(struct image_params *, uintptr_t *); void __elfN(stackgap)(struct image_params *, uintptr_t *);
int __elfN(freebsd_copyout_auxargs)(struct image_params *, uintptr_t *); int __elfN(freebsd_copyout_auxargs)(struct image_params *, uintptr_t);
/* Machine specific function to dump per-thread information. */ /* Machine specific function to dump per-thread information. */
void __elfN(dump_thread)(struct thread *, void *, size_t *); void __elfN(dump_thread)(struct thread *, void *, size_t *);

View File

@ -111,7 +111,7 @@ struct sysentvec {
int (*sv_imgact_try)(struct image_params *); int (*sv_imgact_try)(struct image_params *);
void (*sv_stackgap)(struct image_params *, uintptr_t *); void (*sv_stackgap)(struct image_params *, uintptr_t *);
int (*sv_copyout_auxargs)(struct image_params *, int (*sv_copyout_auxargs)(struct image_params *,
uintptr_t *); uintptr_t);
int sv_minsigstksz; /* minimum signal stack size */ int sv_minsigstksz; /* minimum signal stack size */
vm_offset_t sv_minuser; /* VM_MIN_ADDRESS */ vm_offset_t sv_minuser; /* VM_MIN_ADDRESS */
vm_offset_t sv_maxuser; /* VM_MAXUSER_ADDRESS */ vm_offset_t sv_maxuser; /* VM_MAXUSER_ADDRESS */