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 Davis 2018-12-04 00:15:47 +00:00
parent a66732de4f
commit 3a325dec32

View File

@ -56,6 +56,7 @@ __FBSDID("$FreeBSD$");
#include <sys/exec.h>
#include <sys/file.h>
#include <sys/filedesc.h>
#include <sys/imgact.h>
#include <sys/jail.h>
#include <sys/ktr.h>
#include <sys/lock.h>
@ -716,15 +717,15 @@ SYSCTL_INT(_kern, OID_AUTO, init_shutdown_timeout,
static void
start_init(void *dummy)
{
vm_offset_t addr;
struct execve_args args;
struct image_args args;
int options, error;
size_t pathlen;
char flags[8], *flagp;
char *var, *path;
char *free_init_path, *tmp_init_path;
char *ucp, **uap, *arg0, *arg1;
struct thread *td;
struct proc *p;
struct vmspace *oldvmspace;
TSENTER(); /* Here so we don't overlap with mi_startup. */
@ -736,16 +737,6 @@ start_init(void *dummy)
/* Wipe GELI passphrase from the environment. */
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) {
strlcpy(init_path, var, sizeof(init_path));
freeenv(var);
@ -757,54 +748,44 @@ start_init(void *dummy)
if (bootverbose)
printf("start_init: trying %s\n", path);
/*
* Move out the boot flag argument.
*/
memset(&args, 0, sizeof(args));
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;
ucp = (char *)p->p_sysent->sv_usrstack;
(void)subyte(--ucp, 0); /* trailing zero */
flagp = &flags[0];
*flagp++ = '-';
if (boothowto & RB_SINGLE) {
(void)subyte(--ucp, 's');
options = 1;
*flagp++ = 's';
options++;
}
#ifdef notyet
if (boothowto & RB_FASTBOOT) {
(void)subyte(--ucp, 'f');
options = 1;
*flagp++ = 'f';
options++;
}
#endif
#ifdef BOOTCDROM
(void)subyte(--ucp, 'C');
options = 1;
*flagp++ = 'C';
options++;
#endif
if (options == 0)
(void)subyte(--ucp, '-');
(void)subyte(--ucp, '-'); /* leading hyphen */
arg1 = ucp;
/*
* Move out the file name (also arg 0).
*/
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;
*flagp++ = '-';
*flagp++ = 0;
KASSERT(flagp <= &flags[0] + sizeof(flags), ("Overran flags"));
error = exec_args_add_arg(&args, flags, UIO_SYSSPACE);
if (error != 0)
panic("%s: Can't add argv[0] %d", __func__, error);
/*
* 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
* 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);
TSEXIT();
return;