Remove a needlessly clever hack to start init with sys_exec().

Construct a struct image_args with the help of new exec_args_*() helper
functions and call kern_execve().

The previous code mapped a page in userspace, copied arguments out
to it one at a time, and then constructed a struct execve_args all so
that sys_execve() can call exec_copyin_args() to copy the data back in
to a struct image_args.

Opencode the part of pre_execve()/post_execve() that releases a
reference to the initial vmspace. We don't need to stop threads like
they do.

Reviewed by:	kib, jhb (prior version)
Obtained from:	CheriBSD
Sponsored by:	DARPA, AFRL
Differential Revision:	https://reviews.freebsd.org/D15469
This commit is contained in:
brooks 2018-12-04 00:15:47 +00:00
parent fec90e1e9c
commit ff1fac3cb1

View File

@ -56,6 +56,7 @@ __FBSDID("$FreeBSD$");
#include <sys/exec.h> #include <sys/exec.h>
#include <sys/file.h> #include <sys/file.h>
#include <sys/filedesc.h> #include <sys/filedesc.h>
#include <sys/imgact.h>
#include <sys/jail.h> #include <sys/jail.h>
#include <sys/ktr.h> #include <sys/ktr.h>
#include <sys/lock.h> #include <sys/lock.h>
@ -716,15 +717,15 @@ SYSCTL_INT(_kern, OID_AUTO, init_shutdown_timeout,
static void static void
start_init(void *dummy) start_init(void *dummy)
{ {
vm_offset_t addr; struct image_args args;
struct execve_args args;
int options, error; int options, error;
size_t pathlen; size_t pathlen;
char flags[8], *flagp;
char *var, *path; char *var, *path;
char *free_init_path, *tmp_init_path; char *free_init_path, *tmp_init_path;
char *ucp, **uap, *arg0, *arg1;
struct thread *td; struct thread *td;
struct proc *p; struct proc *p;
struct vmspace *oldvmspace;
TSENTER(); /* Here so we don't overlap with mi_startup. */ TSENTER(); /* Here so we don't overlap with mi_startup. */
@ -736,16 +737,6 @@ start_init(void *dummy)
/* Wipe GELI passphrase from the environment. */ /* Wipe GELI passphrase from the environment. */
kern_unsetenv("kern.geom.eli.passphrase"); kern_unsetenv("kern.geom.eli.passphrase");
/*
* Need just enough stack to hold the faked-up "execve()" arguments.
*/
addr = p->p_sysent->sv_usrstack - PAGE_SIZE;
if (vm_map_find(&p->p_vmspace->vm_map, NULL, 0, &addr, PAGE_SIZE, 0,
VMFS_NO_SPACE, VM_PROT_ALL, VM_PROT_ALL, 0) != 0)
panic("init: couldn't allocate argument space");
p->p_vmspace->vm_maxsaddr = (caddr_t)addr;
p->p_vmspace->vm_ssize = 1;
if ((var = kern_getenv("init_path")) != NULL) { if ((var = kern_getenv("init_path")) != NULL) {
strlcpy(init_path, var, sizeof(init_path)); strlcpy(init_path, var, sizeof(init_path));
freeenv(var); freeenv(var);
@ -757,54 +748,44 @@ start_init(void *dummy)
if (bootverbose) if (bootverbose)
printf("start_init: trying %s\n", path); printf("start_init: trying %s\n", path);
/* memset(&args, 0, sizeof(args));
* Move out the boot flag argument. error = exec_alloc_args(&args);
*/ if (error != 0)
panic("%s: Can't allocate space for init arguments %d",
__func__, error);
error = exec_args_add_fname(&args, path, UIO_SYSSPACE);
if (error != 0)
panic("%s: Can't add fname %d", __func__, error);
error = exec_args_add_arg(&args, path, UIO_SYSSPACE);
if (error != 0)
panic("%s: Can't add argv[0] %d", __func__, error);
options = 0; options = 0;
ucp = (char *)p->p_sysent->sv_usrstack; flagp = &flags[0];
(void)subyte(--ucp, 0); /* trailing zero */ *flagp++ = '-';
if (boothowto & RB_SINGLE) { if (boothowto & RB_SINGLE) {
(void)subyte(--ucp, 's'); *flagp++ = 's';
options = 1; options++;
} }
#ifdef notyet #ifdef notyet
if (boothowto & RB_FASTBOOT) { if (boothowto & RB_FASTBOOT) {
(void)subyte(--ucp, 'f'); *flagp++ = 'f';
options = 1; options++;
} }
#endif #endif
#ifdef BOOTCDROM #ifdef BOOTCDROM
(void)subyte(--ucp, 'C'); *flagp++ = 'C';
options = 1; options++;
#endif #endif
if (options == 0) if (options == 0)
(void)subyte(--ucp, '-'); *flagp++ = '-';
(void)subyte(--ucp, '-'); /* leading hyphen */ *flagp++ = 0;
arg1 = ucp; KASSERT(flagp <= &flags[0] + sizeof(flags), ("Overran flags"));
error = exec_args_add_arg(&args, flags, UIO_SYSSPACE);
/* if (error != 0)
* Move out the file name (also arg 0). panic("%s: Can't add argv[0] %d", __func__, error);
*/
ucp -= pathlen;
copyout(path, ucp, pathlen);
arg0 = ucp;
/*
* Move out the arg pointers.
*/
uap = (char **)rounddown2((intptr_t)ucp, sizeof(intptr_t));
(void)suword((caddr_t)--uap, (long)0); /* terminator */
(void)suword((caddr_t)--uap, (long)(intptr_t)arg1);
(void)suword((caddr_t)--uap, (long)(intptr_t)arg0);
/*
* Point at the arguments.
*/
args.fname = arg0;
args.argv = uap;
args.envv = NULL;
/* /*
* Now try to exec the program. If can't for any reason * Now try to exec the program. If can't for any reason
@ -813,7 +794,19 @@ start_init(void *dummy)
* Otherwise, return via fork_trampoline() all the way * Otherwise, return via fork_trampoline() all the way
* to user mode as init! * to user mode as init!
*/ */
if ((error = sys_execve(td, &args)) == EJUSTRETURN) { KASSERT((td->td_pflags & TDP_EXECVMSPC) == 0,
("nested execve"));
oldvmspace = td->td_proc->p_vmspace;
error = kern_execve(td, &args, NULL);
KASSERT(error != 0,
("kern_execve returned success, not EJUSTRETURN"));
if (error == EJUSTRETURN) {
if ((td->td_pflags & TDP_EXECVMSPC) != 0) {
KASSERT(p->p_vmspace != oldvmspace,
("oldvmspace still used"));
vmspace_free(oldvmspace);
td->td_pflags &= ~TDP_EXECVMSPC;
}
free(free_init_path, M_TEMP); free(free_init_path, M_TEMP);
TSEXIT(); TSEXIT();
return; return;