Index: kern/kern_exec.c =================================================================== RCS file: /cvsroot/src/sys/kern/kern_exec.c,v retrieving revision 1.413 diff -u -u -r1.413 kern_exec.c --- kern/kern_exec.c 31 Jul 2015 07:37:17 -0000 1.413 +++ kern/kern_exec.c 10 Sep 2015 16:23:55 -0000 @@ -79,6 +79,7 @@ #include #include #include +#include #include #include #include @@ -131,6 +132,8 @@ static int copyinargstrs(struct execve_data * restrict, char * const *, execve_fetch_element_t, char **, size_t *, void (*)(const void *, size_t)); static int exec_sigcode_map(struct proc *, const struct emul *); +static void absolutepath(struct lwp *, struct exec_package *, + struct nameidata *); #ifdef DEBUG_EXEC #define DPRINTF(a) printf a @@ -331,15 +334,13 @@ struct nameidata nd; size_t resid; - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, pb); + NDINIT(&nd, LOOKUP, LOCKPARENT | FOLLOW | LOCKLEAF | TRYEMULROOT, pb); /* first get the vnode */ if ((error = namei(&nd)) != 0) return error; + absolutepath(l, epp, &nd); epp->ep_vp = vp = nd.ni_vp; - /* normally this can't fail */ - error = copystr(nd.ni_pnbuf, epp->ep_resolvedname, PATH_MAX, NULL); - KASSERT(error == 0); #ifdef DIAGNOSTIC /* paranoia (take this out once namei stuff stabilizes) */ @@ -863,11 +864,71 @@ } static void -pathexec(struct exec_package *epp, struct proc *p, const char *pathstring) +absolutepath(struct lwp *l, struct exec_package *epp, struct nameidata *nd) { - const char *commandname; - size_t commandlen; - char *path; + int error; + struct proc *p; + char *bp; + size_t len; + + /* normally this can't fail */ + error = copystr(nd->ni_pnbuf, epp->ep_resolvedname, PATH_MAX, NULL); + KASSERT(error == 0); + epp->ep_path = PNBUF_GET(); + + /* + * If the path starts with /, we don't need to do any work. + * This handles the majority of the cases. + * In the future perhaps we could canonicalize it? + */ + if (epp->ep_resolvedname[0] == '/') { + (void)strlcpy(epp->ep_path, epp->ep_resolvedname, MAXPATHLEN); + vput(nd->ni_dvp); + return; + } + + len = strlen(epp->ep_resolvedname) + 1; + KASSERT(len < MAXPATHLEN); + bp = epp->ep_path + MAXPATHLEN - len; + memcpy(bp, epp->ep_resolvedname, len); + *(--bp) = '/'; + + error = getcwd_common(nd->ni_dvp, NULL, &bp, epp->ep_path, + MAXPATHLEN / 2, GETCWD_LOCKED | GETCWD_CHECK_ACCESS, l); + if (error) { +#ifdef DIAGNOSTIC + printf("getcwd failed for %s error=%d\n", epp->ep_resolvedname, + error); +#endif + PNBUF_PUT(epp->ep_path); + epp->ep_path = NULL; + return; + } + + /* + * Strip off emulation path for emulated processes looking at + * the maps file of a process of the same emulation. (Won't + * work if /emul/xxx is a symlink..) + */ + p = l->l_proc; + if (p->p_emul->e_path != NULL) { + len = strlen(p->p_emul->e_path); + if (!strncmp(bp, p->p_emul->e_path, len)) + bp = &bp[len]; + } + + len = epp->ep_path + MAXPATHLEN - bp; + + memcpy(epp->ep_path, bp, len); + epp->ep_path[len] = '\0'; + +} + +static void +pathexec(struct proc *p, struct exec_package *epp) +{ + const char *commandname; + size_t commandlen; /* set command name & other accounting info */ commandname = strrchr(epp->ep_resolvedname, '/'); @@ -879,39 +940,6 @@ commandlen = min(strlen(commandname), MAXCOMLEN); (void)memcpy(p->p_comm, commandname, commandlen); p->p_comm[commandlen] = '\0'; - - path = PNBUF_GET(); - - /* - * If the path starts with /, we don't need to do any work. - * This handles the majority of the cases. - * In the future perhaps we could canonicalize it? - */ - if (pathstring[0] == '/') { - (void)strlcpy(path, pathstring, - MAXPATHLEN); - epp->ep_path = path; - } -#ifdef notyet - /* - * Although this works most of the time [since the entry was just - * entered in the cache] we don't use it because it will fail for - * entries that are not placed in the cache because their name is - * longer than NCHNAMLEN and it is not the cleanest interface, - * because there could be races. When the namei cache is re-written, - * this can be changed to use the appropriate function. - */ - else if (!(error = vnode_to_path(path, MAXPATHLEN, p->p_textvp, l, p))) - epp->ep_path = path; -#endif - else { -#ifdef notyet - printf("Cannot get path for pid %d [%s] (error %d)\n", - (int)p->p_pid, p->p_comm, error); -#endif - epp->ep_path = NULL; - PNBUF_PUT(path); - } } /* XXX elsewhere */ @@ -1131,7 +1159,7 @@ if (error != 0) goto exec_abort; - pathexec(epp, p, data->ed_pathstring); + pathexec(p, epp); char * const newstack = STACK_GROW(vm->vm_minsaddr, epp->ep_ssize); Index: kern/vfs_getcwd.c =================================================================== RCS file: /cvsroot/src/sys/kern/vfs_getcwd.c,v retrieving revision 1.50 diff -u -u -r1.50 vfs_getcwd.c --- kern/vfs_getcwd.c 7 Feb 2014 15:29:22 -0000 1.50 +++ kern/vfs_getcwd.c 10 Sep 2015 16:23:55 -0000 @@ -348,7 +348,8 @@ * uvp is either NULL, or locked and held. */ - vn_lock(lvp, LK_EXCLUSIVE | LK_RETRY); + if (!(flags & GETCWD_LOCKED)) + vn_lock(lvp, LK_EXCLUSIVE | LK_RETRY); if (bufp) bp = *bpp; Index: sys/filedesc.h =================================================================== RCS file: /cvsroot/src/sys/sys/filedesc.h,v retrieving revision 1.63 diff -u -u -r1.63 filedesc.h --- sys/filedesc.h 11 Feb 2012 23:16:18 -0000 1.63 +++ sys/filedesc.h 10 Sep 2015 16:23:55 -0000 @@ -220,6 +220,7 @@ void cwdexec(struct proc *); #define GETCWD_CHECK_ACCESS 0x0001 +#define GETCWD_LOCKED 0x0002 int getcwd_common(struct vnode *, struct vnode *, char **, char *, int, int, struct lwp *); int vnode_to_path(char *, size_t, struct vnode *, struct lwp *,