git: a69fb7452ef9 - stable/13 - exec: provide right hardlink name in AT_EXECPATH

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Sat, 06 Nov 2021 02:25:20 UTC
The branch stable/13 has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=a69fb7452ef97b5690f1811d4fb3b7b9f8ad78f8

commit a69fb7452ef97b5690f1811d4fb3b7b9f8ad78f8
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2021-10-23 00:24:08 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2021-11-06 02:12:31 +0000

    exec: provide right hardlink name in AT_EXECPATH
    
    PR:     248184
    
    (cherry picked from commit 0c10648fbb758bb76fd29330b7fe1bc519252325)
---
 sys/kern/kern_exec.c | 38 ++++++++++++++++++++++++++++----------
 1 file changed, 28 insertions(+), 10 deletions(-)

diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c
index 9b8ee7025a94..a82eefca62b7 100644
--- a/sys/kern/kern_exec.c
+++ b/sys/kern/kern_exec.c
@@ -401,6 +401,7 @@ do_execve(struct thread *td, struct image_args *args, struct mac *mac_p,
 #endif
 	int error, i, orig_osrel;
 	uint32_t orig_fctl0;
+	size_t freepath_size;
 	static const char fexecv_proc_title[] = "(fexecv)";
 
 	imgp = &image_params;
@@ -447,7 +448,8 @@ do_execve(struct thread *td, struct image_args *args, struct mac *mac_p,
 	 */
 	if (args->fname != NULL) {
 		NDINIT(&nd, LOOKUP, ISOPEN | LOCKLEAF | LOCKSHARED | FOLLOW |
-		    SAVENAME | AUDITVNODE1, UIO_SYSSPACE, args->fname, td);
+		    SAVENAME | AUDITVNODE1 | WANTPARENT,
+		    UIO_SYSSPACE, args->fname, td);
 	}
 
 	SDT_PROBE1(proc, , , exec, args->fname);
@@ -592,9 +594,18 @@ interpret:
 	/*
 	 * Do the best to calculate the full path to the image file.
 	 */
-	if (args->fname != NULL && args->fname[0] == '/')
-		imgp->execpath = args->fname;
-	else {
+	if (args->fname != NULL) {
+		if (args->fname[0] == '/') {
+			imgp->execpath = args->fname;
+		} else {
+			VOP_UNLOCK(imgp->vp);
+			freepath_size = MAXPATHLEN;
+			if (vn_fullpath_hardlink(&nd, &imgp->execpath,
+			    &imgp->freepath, &freepath_size) != 0)
+				imgp->execpath = args->fname;
+			vn_lock(imgp->vp, LK_SHARED | LK_RETRY);
+		}
+	} else {
 		VOP_UNLOCK(imgp->vp);
 		if (vn_fullpath(imgp->vp, &imgp->execpath,
 		    &imgp->freepath) != 0)
@@ -647,8 +658,6 @@ interpret:
 		VOP_UNSET_TEXT_CHECKED(newtextvp);
 		imgp->textset = false;
 		/* free name buffer and old vnode */
-		if (args->fname != NULL)
-			NDFREE(&nd, NDF_ONLY_PNBUF);
 #ifdef MAC
 		mac_execve_interpreter_enter(newtextvp, &interpvplabel);
 #endif
@@ -657,6 +666,11 @@ interpret:
 			imgp->opened = false;
 		}
 		vput(newtextvp);
+		if (args->fname != NULL) {
+			if (nd.ni_dvp != NULL)
+				vrele(nd.ni_dvp);
+			NDFREE(&nd, NDF_ONLY_PNBUF);
+		}
 		vm_object_deallocate(imgp->object);
 		imgp->object = NULL;
 		execve_nosetid(imgp);
@@ -664,9 +678,10 @@ interpret:
 		free(imgp->freepath, M_TEMP);
 		imgp->freepath = NULL;
 		/* set new name to that of the interpreter */
-		NDINIT(&nd, LOOKUP, ISOPEN | LOCKLEAF | LOCKSHARED | FOLLOW |
-		    SAVENAME, UIO_SYSSPACE, imgp->interpreter_name, td);
 		args->fname = imgp->interpreter_name;
+		NDINIT(&nd, LOOKUP, ISOPEN | LOCKLEAF | LOCKSHARED | FOLLOW |
+		    SAVENAME | WANTPARENT,
+		    UIO_SYSSPACE, imgp->interpreter_name, td);
 		goto interpret;
 	}
 
@@ -907,8 +922,6 @@ exec_fail_dealloc:
 		exec_unmap_first_page(imgp);
 
 	if (imgp->vp != NULL) {
-		if (args->fname)
-			NDFREE(&nd, NDF_ONLY_PNBUF);
 		if (imgp->opened)
 			VOP_CLOSE(imgp->vp, FREAD, td->td_ucred, td);
 		if (imgp->textset)
@@ -917,6 +930,11 @@ exec_fail_dealloc:
 			vput(imgp->vp);
 		else
 			VOP_UNLOCK(imgp->vp);
+		if (args->fname != NULL) {
+			if (nd.ni_dvp != NULL)
+				vrele(nd.ni_dvp);
+			NDFREE(&nd, NDF_ONLY_PNBUF);
+		}
 	}
 
 	if (imgp->object != NULL)