Avoid two suword() calls per auxarg entry.

Instead, construct an auxargs array and copy it out all at once.

Use an array of Elf_Auxinfo rather than pairs of Elf_Addr * to represent
the array. This is the correct type where pairs of words just happend
to work. To reduce the size of the diff, AUXARGS_ENTRY is altered to act
on this array rather than introducing a new macro.

Return errors on copyout() and suword() failures and handle them in the
caller.

Incidentally fixes AT_RANDOM and AT_EXECFN in 32-bit linux on amd64
which incorrectly used AUXARG_ENTRY instead of AUXARGS_ENTRY_32
(now removed due to the use of proper types).

Reviewed by:	kib
Comments from:	emaste, jhb
Obtained from:	CheriBSD
Sponsored by:	DARPA, AFRL
Differential Revision:	https://reviews.freebsd.org/D15485
This commit is contained in:
Brooks Davis 2018-05-24 16:25:18 +00:00
parent b50b5555ef
commit 5f77b8a88b
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=334165
6 changed files with 86 additions and 47 deletions

View File

@ -240,11 +240,11 @@ static int
linux_fixup_elf(register_t **stack_base, struct image_params *imgp)
{
Elf_Auxargs *args;
Elf_Addr *base;
Elf_Addr *pos;
Elf_Auxinfo *argarray, *pos;
Elf_Addr *auxbase, *base;
struct ps_strings *arginfo;
struct proc *p;
int issetugid;
int error, issetugid;
p = imgp->proc;
arginfo = (struct ps_strings *)p->p_sysent->sv_psstrings;
@ -253,7 +253,9 @@ linux_fixup_elf(register_t **stack_base, struct image_params *imgp)
("unsafe linux_fixup_elf(), should be curproc"));
base = (Elf64_Addr *)*stack_base;
args = (Elf64_Auxargs *)imgp->auxargs;
pos = base + (imgp->args->argc + imgp->args->envc + 2);
auxbase = base + imgp->args->argc + 1 + imgp->args->envc + 1;
argarray = pos = malloc(LINUX_AT_COUNT * sizeof(*pos), M_TEMP,
M_WAITOK | M_ZERO);
issetugid = p->p_flag & P_SUGID ? 1 : 0;
AUXARGS_ENTRY(pos, LINUX_AT_SYSINFO_EHDR,
@ -281,9 +283,17 @@ linux_fixup_elf(register_t **stack_base, struct image_params *imgp)
AUXARGS_ENTRY(pos, AT_NULL, 0);
free(imgp->auxargs, M_TEMP);
imgp->auxargs = NULL;
KASSERT((pos - argarray) / sizeof(*pos) <= LINUX_AT_COUNT,
("Too many auxargs"));
error = copyout(argarray, auxbase, sizeof(*argarray) * LINUX_AT_COUNT);
free(argarray, M_TEMP);
if (error != 0)
return (error);
base--;
suword(base, (uint64_t)imgp->args->argc);
if (suword(base, (uint64_t)imgp->args->argc) == -1)
return (EFAULT);
*stack_base = (register_t *)base;
return (0);

View File

@ -89,12 +89,6 @@ __FBSDID("$FreeBSD$");
MODULE_VERSION(linux, 1);
#define AUXARGS_ENTRY_32(pos, id, val) \
do { \
suword32(pos++, id); \
suword32(pos++, val); \
} while (0)
/*
* Allow the sendsig functions to use the ldebug() facility even though they
* are not syscalls themselves. Map them to syscall 0. This is slightly less
@ -202,10 +196,10 @@ static int
linux_fixup_elf(register_t **stack_base, struct image_params *imgp)
{
Elf32_Auxargs *args;
Elf32_Addr *base;
Elf32_Addr *pos;
Elf32_Auxinfo *argarray, *pos;
Elf32_Addr *auxbase, *base;
struct linux32_ps_strings *arginfo;
int issetugid;
int error, issetugid;
arginfo = (struct linux32_ps_strings *)LINUX32_PS_STRINGS;
@ -213,13 +207,15 @@ linux_fixup_elf(register_t **stack_base, struct image_params *imgp)
("unsafe linux_fixup_elf(), should be curproc"));
base = (Elf32_Addr *)*stack_base;
args = (Elf32_Auxargs *)imgp->auxargs;
pos = base + (imgp->args->argc + imgp->args->envc + 2);
auxbase = base + (imgp->args->argc + 1 + imgp->args->envc + 1);
argarray = pos = malloc(LINUX_AT_COUNT * sizeof(*pos), M_TEMP,
M_WAITOK | M_ZERO);
issetugid = imgp->proc->p_flag & P_SUGID ? 1 : 0;
AUXARGS_ENTRY_32(pos, LINUX_AT_SYSINFO_EHDR,
AUXARGS_ENTRY(pos, LINUX_AT_SYSINFO_EHDR,
imgp->proc->p_sysent->sv_shared_page_base);
AUXARGS_ENTRY_32(pos, LINUX_AT_SYSINFO, linux32_vsyscall);
AUXARGS_ENTRY_32(pos, LINUX_AT_HWCAP, cpu_feature);
AUXARGS_ENTRY(pos, LINUX_AT_SYSINFO, linux32_vsyscall);
AUXARGS_ENTRY(pos, LINUX_AT_HWCAP, cpu_feature);
/*
* Do not export AT_CLKTCK when emulating Linux kernel prior to 2.4.0,
@ -230,32 +226,40 @@ linux_fixup_elf(register_t **stack_base, struct image_params *imgp)
* Also see linux_times() implementation.
*/
if (linux_kernver(curthread) >= LINUX_KERNVER_2004000)
AUXARGS_ENTRY_32(pos, LINUX_AT_CLKTCK, stclohz);
AUXARGS_ENTRY_32(pos, AT_PHDR, args->phdr);
AUXARGS_ENTRY_32(pos, AT_PHENT, args->phent);
AUXARGS_ENTRY_32(pos, AT_PHNUM, args->phnum);
AUXARGS_ENTRY_32(pos, AT_PAGESZ, args->pagesz);
AUXARGS_ENTRY_32(pos, AT_FLAGS, args->flags);
AUXARGS_ENTRY_32(pos, AT_ENTRY, args->entry);
AUXARGS_ENTRY_32(pos, AT_BASE, args->base);
AUXARGS_ENTRY_32(pos, LINUX_AT_SECURE, issetugid);
AUXARGS_ENTRY_32(pos, AT_UID, imgp->proc->p_ucred->cr_ruid);
AUXARGS_ENTRY_32(pos, AT_EUID, imgp->proc->p_ucred->cr_svuid);
AUXARGS_ENTRY_32(pos, AT_GID, imgp->proc->p_ucred->cr_rgid);
AUXARGS_ENTRY_32(pos, AT_EGID, imgp->proc->p_ucred->cr_svgid);
AUXARGS_ENTRY_32(pos, LINUX_AT_PLATFORM, PTROUT(linux_platform));
AUXARGS_ENTRY(pos, LINUX_AT_CLKTCK, stclohz);
AUXARGS_ENTRY(pos, AT_PHDR, args->phdr);
AUXARGS_ENTRY(pos, AT_PHENT, args->phent);
AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum);
AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz);
AUXARGS_ENTRY(pos, AT_FLAGS, args->flags);
AUXARGS_ENTRY(pos, AT_ENTRY, args->entry);
AUXARGS_ENTRY(pos, AT_BASE, args->base);
AUXARGS_ENTRY(pos, LINUX_AT_SECURE, issetugid);
AUXARGS_ENTRY(pos, AT_UID, imgp->proc->p_ucred->cr_ruid);
AUXARGS_ENTRY(pos, AT_EUID, imgp->proc->p_ucred->cr_svuid);
AUXARGS_ENTRY(pos, AT_GID, imgp->proc->p_ucred->cr_rgid);
AUXARGS_ENTRY(pos, AT_EGID, imgp->proc->p_ucred->cr_svgid);
AUXARGS_ENTRY(pos, LINUX_AT_PLATFORM, PTROUT(linux_platform));
AUXARGS_ENTRY(pos, LINUX_AT_RANDOM, PTROUT(imgp->canary));
if (imgp->execpathp != 0)
AUXARGS_ENTRY(pos, LINUX_AT_EXECFN, PTROUT(imgp->execpathp));
if (args->execfd != -1)
AUXARGS_ENTRY_32(pos, AT_EXECFD, args->execfd);
AUXARGS_ENTRY_32(pos, AT_NULL, 0);
AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd);
AUXARGS_ENTRY(pos, AT_NULL, 0);
free(imgp->auxargs, M_TEMP);
imgp->auxargs = NULL;
KASSERT((pos - argarray) / sizeof(*pos) <= AT_COUNT,
("Too many auxargs"));
error = copyout(&argarray[0], auxbase, sizeof(*argarray) * AT_COUNT);
free(argarray, M_TEMP);
if (error != 0)
return (error);
base--;
suword32(base, (uint32_t)imgp->args->argc);
if (suword32(base, (uint32_t)imgp->args->argc) == -1)
return (EFAULT);
*stack_base = (register_t *)base;
return (0);
}

View File

@ -207,10 +207,10 @@ linux_fixup_elf(register_t **stack_base, struct image_params *imgp)
{
struct proc *p;
Elf32_Auxargs *args;
Elf32_Addr *uplatform;
Elf32_Auxinfo *argarray, *pos;
Elf32_Addr *auxbase, *uplatform;
struct ps_strings *arginfo;
register_t *pos;
int issetugid;
int error, issetugid;
KASSERT(curthread->td_proc == imgp->proc,
("unsafe linux_fixup_elf(), should be curproc"));
@ -220,7 +220,9 @@ linux_fixup_elf(register_t **stack_base, struct image_params *imgp)
arginfo = (struct ps_strings *)p->p_sysent->sv_psstrings;
uplatform = (Elf32_Addr *)((caddr_t)arginfo - linux_szplatform);
args = (Elf32_Auxargs *)imgp->auxargs;
pos = *stack_base + (imgp->args->argc + imgp->args->envc + 2);
auxbase = *stack_base + imgp->args->argc + 1 + imgp->args->envc + 1;
argarray = pos = malloc(LINUX_AT_COUNT * sizeof(*pos), M_TEMP,
M_WAITOK | M_ZERO);
AUXARGS_ENTRY(pos, LINUX_AT_SYSINFO_EHDR,
imgp->proc->p_sysent->sv_shared_page_base);
@ -259,9 +261,17 @@ linux_fixup_elf(register_t **stack_base, struct image_params *imgp)
free(imgp->auxargs, M_TEMP);
imgp->auxargs = NULL;
KASSERT((pos - argarray) / sizeof(*pos) <= LINUX_AT_COUNT,
("Too many auxargs"));
error = copyout(argarray, auxbase, sizeof(*argarray) * LINUX_AT_COUNT);
free(argarray, M_TEMP);
if (error != 0)
return (error);
(*stack_base)--;
suword(*stack_base, (register_t)imgp->args->argc);
if (suword(*stack_base, (register_t)imgp->args->argc) == -1)
return (EFAULT);
return (0);
}

View File

@ -1098,11 +1098,14 @@ int
__elfN(freebsd_fixup)(register_t **stack_base, struct image_params *imgp)
{
Elf_Auxargs *args = (Elf_Auxargs *)imgp->auxargs;
Elf_Addr *base;
Elf_Addr *pos;
Elf_Auxinfo *argarray, *pos;
Elf_Addr *base, *auxbase;
int error;
base = (Elf_Addr *)*stack_base;
pos = base + (imgp->args->argc + imgp->args->envc + 2);
auxbase = base + imgp->args->argc + 1 + imgp->args->envc + 1;
argarray = pos = malloc(AT_COUNT * sizeof(*pos), M_TEMP,
M_WAITOK | M_ZERO);
if (args->execfd != -1)
AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd);
@ -1142,9 +1145,17 @@ __elfN(freebsd_fixup)(register_t **stack_base, struct image_params *imgp)
free(imgp->auxargs, M_TEMP);
imgp->auxargs = NULL;
KASSERT((pos - argarray) / sizeof(*pos) <= AT_COUNT,
("Too many auxargs"));
error = copyout(argarray, auxbase, sizeof(*argarray) * AT_COUNT);
free(argarray, M_TEMP);
if (error != 0)
return (error);
base--;
suword(base, (long)imgp->args->argc);
if (suword(base, imgp->args->argc) == -1)
return (EFAULT);
*stack_base = (register_t *)base;
return (0);
}

View File

@ -691,9 +691,12 @@ do_execve(struct thread *td, struct image_args *args, struct mac *mac_p)
* Else stuff argument count as first item on stack
*/
if (p->p_sysent->sv_fixup != NULL)
(*p->p_sysent->sv_fixup)(&stack_base, imgp);
error = (*p->p_sysent->sv_fixup)(&stack_base, imgp);
else
suword(--stack_base, imgp->args->argc);
error = suword(--stack_base, imgp->args->argc) == 0 ?
0 : EFAULT;
if (error != 0)
goto exec_fail_dealloc;
if (args->fdp != NULL) {
/* Install a brand new file descriptor table. */

View File

@ -37,7 +37,8 @@
#ifdef _KERNEL
#define AUXARGS_ENTRY(pos, id, val) {suword(pos++, id); suword(pos++, val);}
#define AUXARGS_ENTRY(pos, id, val) \
{(pos)->a_type = (id); (pos)->a_un.a_val = (val); (pos)++;}
struct image_params;
struct thread;