Module Name:    src
Committed By:   christos
Date:           Sun Sep 15 20:23:50 UTC 2019

Modified Files:
        src/sys/kern: kern_exec.c

Log Message:
- Add support for fexecve
        - get the vnode from the fd passed instead of calling namei() on the
          path
        - try to reverse resolve the vnode to extract the pathname
        - deal with not having a resolved path available
- rename variable that was not a pathbuf


To generate a diff of this commit:
cvs rdiff -u -r1.479 -r1.480 src/sys/kern/kern_exec.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/kern/kern_exec.c
diff -u src/sys/kern/kern_exec.c:1.479 src/sys/kern/kern_exec.c:1.480
--- src/sys/kern/kern_exec.c:1.479	Sat Sep  7 11:34:44 2019
+++ src/sys/kern/kern_exec.c	Sun Sep 15 16:23:50 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: kern_exec.c,v 1.479 2019/09/07 15:34:44 christos Exp $	*/
+/*	$NetBSD: kern_exec.c,v 1.480 2019/09/15 20:23:50 christos Exp $	*/
 
 /*-
  * Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -59,7 +59,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_exec.c,v 1.479 2019/09/07 15:34:44 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_exec.c,v 1.480 2019/09/15 20:23:50 christos Exp $");
 
 #include "opt_exec.h"
 #include "opt_execfmt.h"
@@ -257,7 +257,7 @@ struct execve_data {
 	struct ps_strings	ed_arginfo;
 	char			*ed_argp;
 	const char		*ed_pathstring;
-	char			*ed_resolvedpathbuf;
+	char			*ed_resolvedname;
 	size_t			ed_ps_strings_sz;
 	int			ed_szsigcode;
 	size_t			ed_argslen;
@@ -309,9 +309,32 @@ exec_path_free(struct execve_data *data)
 {              
 	pathbuf_stringcopy_put(data->ed_pathbuf, data->ed_pathstring);
 	pathbuf_destroy(data->ed_pathbuf);
-	PNBUF_PUT(data->ed_resolvedpathbuf);
+	if (data->ed_resolvedname)
+		PNBUF_PUT(data->ed_resolvedname);
 }
 
+static void
+exec_resolvename(struct lwp *l, struct exec_package *epp, struct vnode *vp,
+    char **rpath)
+{
+	int error;
+	char *p;
+
+	KASSERT(rpath != NULL);
+
+	*rpath = PNBUF_GET();
+	error = vnode_to_path(*rpath, MAXPATHLEN, vp, l, l->l_proc);
+	if (error) {
+		PNBUF_PUT(*rpath);
+		*rpath = NULL;
+		return;
+	}
+	epp->ep_resolvedname = *rpath;
+	if ((p = strrchr(*rpath, '/')) != NULL)
+		epp->ep_kname = p + 1;
+}
+
+
 /*
  * check exec:
  * given an "executable" described in the exec package's namei info,
@@ -339,26 +362,40 @@ exec_path_free(struct execve_data *data)
  */
 int
 /*ARGSUSED*/
-check_exec(struct lwp *l, struct exec_package *epp, struct pathbuf *pb)
+check_exec(struct lwp *l, struct exec_package *epp, struct pathbuf *pb,
+    char **rpath)
 {
 	int		error, i;
 	struct vnode	*vp;
-	struct nameidata nd;
 	size_t		resid;
 
-	// grab the absolute pathbuf here before namei() trashes it.
-	pathbuf_copystring(pb, epp->ep_resolvedname, PATH_MAX);
-	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, pb);
+	if (epp->ep_resolvedname) {
+		struct nameidata nd;
 
-	/* first get the vnode */
-	if ((error = namei(&nd)) != 0)
-		return error;
-	epp->ep_vp = vp = nd.ni_vp;
+		// grab the absolute pathbuf here before namei() trashes it.
+		pathbuf_copystring(pb, epp->ep_resolvedname, PATH_MAX);
+		NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, pb);
 
+		/* first get the vnode */
+		if ((error = namei(&nd)) != 0)
+			return error;
+
+		epp->ep_vp = vp = nd.ni_vp;
 #ifdef DIAGNOSTIC
-	/* paranoia (take this out once namei stuff stabilizes) */
-	memset(nd.ni_pnbuf, '~', PATH_MAX);
+		/* paranoia (take this out once namei stuff stabilizes) */
+		memset(nd.ni_pnbuf, '~', PATH_MAX);
 #endif
+	} else {
+		struct file *fp;
+
+		if ((error = fd_getvnode(epp->ep_xfd, &fp)) != 0)
+			return error;
+		epp->ep_vp = vp = fp->f_vnode;
+		vref(vp);
+		fd_putfile(epp->ep_xfd);
+		exec_resolvename(l, epp, vp, rpath);
+		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
+	}
 
 	/* check access and type */
 	if (vp->v_type != VREG) {
@@ -388,7 +425,8 @@ check_exec(struct lwp *l, struct exec_pa
 	VOP_UNLOCK(vp);
 
 #if NVERIEXEC > 0
-	error = veriexec_verify(l, vp, epp->ep_resolvedname,
+	error = veriexec_verify(l, vp,
+	    epp->ep_resolvedname ? epp->ep_resolvedname : epp->ep_kname,
 	    epp->ep_flags & EXEC_INDIR ? VERIEXEC_INDIRECT : VERIEXEC_DIRECT,
 	    NULL);
 	if (error)
@@ -545,7 +583,7 @@ sys_execve(struct lwp *l, const struct s
 		syscallarg(char * const *)	envp;
 	} */
 
-	return execve1(l, SCARG(uap, path), SCARG(uap, argp),
+	return execve1(l, SCARG(uap, path), -1, SCARG(uap, argp),
 	    SCARG(uap, envp), execve_fetch_element);
 }
 
@@ -559,7 +597,8 @@ sys_fexecve(struct lwp *l, const struct 
 		syscallarg(char * const *)	envp;
 	} */
 
-	return ENOSYS;
+	return execve1(l, NULL, SCARG(uap, fd), SCARG(uap, argp),
+	    SCARG(uap, envp), execve_fetch_element);
 }
 
 /*
@@ -680,7 +719,7 @@ exec_vm_minaddr(vaddr_t va_min)
 }
 
 static int
-execve_loadvm(struct lwp *l, const char *path, char * const *args,
+execve_loadvm(struct lwp *l, const char *path, int fd, char * const *args,
 	char * const *envs, execve_fetch_element_t fetch_element,
 	struct execve_data * restrict data)
 {
@@ -689,7 +728,6 @@ execve_loadvm(struct lwp *l, const char 
 	struct proc		*p;
 	char			*dp;
 	u_int			modgen;
-	size_t			offs;
 
 	KASSERT(data != NULL);
 
@@ -732,24 +770,36 @@ execve_loadvm(struct lwp *l, const char 
 	 */
 	rw_enter(&p->p_reflock, RW_WRITER);
 
-	/*
-	 * Init the namei data to point the file user's program name.
-	 * This is done here rather than in check_exec(), so that it's
-	 * possible to override this settings if any of makecmd/probe
-	 * functions call check_exec() recursively - for example,
-	 * see exec_script_makecmds().
-	 */
-	if ((error = exec_makepathbuf(l, path, UIO_USERSPACE,
-	    &data->ed_pathbuf, &offs)) != 0)
-		goto clrflg;
-	data->ed_pathstring = pathbuf_stringcopy_get(data->ed_pathbuf);
-	data->ed_resolvedpathbuf = PNBUF_GET();
+	if (path == NULL) {
+		data->ed_pathbuf = pathbuf_assimilate(strcpy(PNBUF_GET(), "/"));
+		data->ed_pathstring = pathbuf_stringcopy_get(data->ed_pathbuf);
+		epp->ep_kname = "*fexecve*";
+		data->ed_resolvedname = NULL;
+		epp->ep_resolvedname = NULL;
+		epp->ep_xfd = fd;
+	} else {
+		size_t	offs;
+		/*
+		 * Init the namei data to point the file user's program name.
+		 * This is done here rather than in check_exec(), so that it's
+		 * possible to override this settings if any of makecmd/probe
+		 * functions call check_exec() recursively - for example,
+		 * see exec_script_makecmds().
+		 */
+		if ((error = exec_makepathbuf(l, path, UIO_USERSPACE,
+		    &data->ed_pathbuf, &offs)) != 0)
+			goto clrflg;
+		data->ed_pathstring = pathbuf_stringcopy_get(data->ed_pathbuf);
+		epp->ep_kname = data->ed_pathstring + offs;
+		data->ed_resolvedname = PNBUF_GET();
+		epp->ep_resolvedname = data->ed_resolvedname;
+		epp->ep_xfd = -1;
+	}
+
 
 	/*
 	 * initialize the fields of the exec package.
 	 */
-	epp->ep_kname = data->ed_pathstring + offs;
-	epp->ep_resolvedname = data->ed_resolvedpathbuf;
 	epp->ep_hdr = kmem_alloc(exec_maxhdrsz, KM_SLEEP);
 	epp->ep_hdrlen = exec_maxhdrsz;
 	epp->ep_hdrvalid = 0;
@@ -768,7 +818,8 @@ execve_loadvm(struct lwp *l, const char 
 	rw_enter(&exec_lock, RW_READER);
 
 	/* see if we can run it. */
-	if ((error = check_exec(l, epp, data->ed_pathbuf)) != 0) {
+	if ((error = check_exec(l, epp, data->ed_pathbuf,
+	    &data->ed_resolvedname)) != 0) {
 		if (error != ENOENT && error != EACCES && error != ENOEXEC) {
 			DPRINTF(("%s: check exec failed for %s, error %d\n",
 			    __func__, epp->ep_kname, error));
@@ -942,10 +993,19 @@ execve_free_data(struct execve_data *dat
 static void
 pathexec(struct proc *p, const char *resolvedname)
 {
-	KASSERT(resolvedname[0] == '/');
-
 	/* set command name & other accounting info */
-	strlcpy(p->p_comm, strrchr(resolvedname, '/') + 1, sizeof(p->p_comm));
+	const char *cmdname;
+
+	if (resolvedname == NULL) {
+		cmdname = "*fexecve*";
+		resolvedname = "/";
+	} else {
+		cmdname = strrchr(resolvedname, '/') + 1;
+	}
+	KASSERTMSG(resolvedname[0] == '/', "bad resolvedname `%s'",
+	    resolvedname);
+
+	strlcpy(p->p_comm, cmdname, sizeof(p->p_comm));
 
 	kmem_strfree(p->p_path);
 	p->p_path = kmem_strdupsize(resolvedname, NULL, KM_SLEEP);
@@ -1346,13 +1406,13 @@ execve_runproc(struct lwp *l, struct exe
 }
 
 int
-execve1(struct lwp *l, const char *path, char * const *args,
+execve1(struct lwp *l, const char *path, int fd, char * const *args,
     char * const *envs, execve_fetch_element_t fetch_element)
 {
 	struct execve_data data;
 	int error;
 
-	error = execve_loadvm(l, path, args, envs, fetch_element, &data);
+	error = execve_loadvm(l, path, fd, args, envs, fetch_element, &data);
 	if (error)
 		return error;
 	error = execve_runproc(l, &data, false, false);
@@ -2376,7 +2436,7 @@ do_posix_spawn(struct lwp *l1, pid_t *pi
 	 * Do the first part of the exec now, collect state
 	 * in spawn_data.
 	 */
-	error = execve_loadvm(l1, path, argv,
+	error = execve_loadvm(l1, path, -1, argv,
 	    envp, fetch, &spawn_data->sed_exec);
 	if (error == EJUSTRETURN)
 		error = 0;

Reply via email to