git: ee92c8a842d6 - main - sysctl kern.proc.procname: report right hardlink name

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Thu, 28 Oct 2021 17:50:43 UTC
The branch main has been updated by kib:

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

commit ee92c8a842d61ffda8d111e1b0e398085c5bfb3a
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2021-10-23 19:01:37 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2021-10-28 17:50:02 +0000

    sysctl kern.proc.procname: report right hardlink name
    
    PR:     248184
    Reviewed by:    markj
    Tested by:      pho
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D32611
---
 sys/kern/kern_proc.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 49 insertions(+), 5 deletions(-)

diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c
index 2649d1d3a58f..c4c01da1faea 100644
--- a/sys/kern/kern_proc.c
+++ b/sys/kern/kern_proc.c
@@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/elf.h>
 #include <sys/eventhandler.h>
 #include <sys/exec.h>
+#include <sys/fcntl.h>
 #include <sys/jail.h>
 #include <sys/kernel.h>
 #include <sys/limits.h>
@@ -54,6 +55,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/mman.h>
 #include <sys/mount.h>
 #include <sys/mutex.h>
+#include <sys/namei.h>
 #include <sys/proc.h>
 #include <sys/ptrace.h>
 #include <sys/refcount.h>
@@ -2233,32 +2235,74 @@ sysctl_kern_proc_pathname(SYSCTL_HANDLER_ARGS)
 	pid_t *pidp = (pid_t *)arg1;
 	unsigned int arglen = arg2;
 	struct proc *p;
-	struct vnode *vp;
-	char *retbuf, *freebuf;
+	struct vnode *vp, *dvp;
+	char *retbuf, *freebuf, *binname;
+	struct nameidata nd;
+	size_t freepath_size;
 	int error;
+	bool do_fullpath;
 
 	if (arglen != 1)
 		return (EINVAL);
+	binname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
+	binname[0] = '\0';
 	if (*pidp == -1) {	/* -1 means this process */
 		p = req->td->td_proc;
 	} else {
 		error = pget(*pidp, PGET_CANSEE, &p);
-		if (error != 0)
+		if (error != 0) {
+			free(binname, M_TEMP);
 			return (error);
+		}
 	}
 
 	vp = p->p_textvp;
 	if (vp == NULL) {
 		if (*pidp != -1)
 			PROC_UNLOCK(p);
+		free(binname, M_TEMP);
 		return (0);
 	}
 	vref(vp);
+	dvp = p->p_textdvp;
+	if (dvp != NULL)
+		vref(dvp);
+	if (p->p_binname != NULL)
+		strlcpy(binname, p->p_binname, MAXPATHLEN);
 	if (*pidp != -1)
 		PROC_UNLOCK(p);
-	error = vn_fullpath(vp, &retbuf, &freebuf);
+	do_fullpath = true;
+	freebuf = NULL;
+	if (dvp != NULL && binname[0] != '\0') {
+		freepath_size = MAXPATHLEN;
+		if (vn_fullpath_hardlink(vp, dvp, binname, strlen(binname),
+		    &retbuf, &freebuf, &freepath_size) == 0) {
+			/*
+			 * Recheck the looked up path.  The binary
+			 * might have been renamed or replaced, in
+			 * which case we should not report old name.
+			 */
+			NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, retbuf,
+			    req->td);
+			error = namei(&nd);
+			if (error == 0) {
+				if (nd.ni_vp == vp)
+					do_fullpath = false;
+				vrele(nd.ni_vp);
+				NDFREE(&nd, NDF_ONLY_PNBUF);
+			}
+		}
+	}
+	if (do_fullpath) {
+		free(freebuf, M_TEMP);
+		freebuf = NULL;
+		error = vn_fullpath(vp, &retbuf, &freebuf);
+	}
 	vrele(vp);
-	if (error)
+	if (dvp != NULL)
+		vrele(dvp);
+	free(binname, M_TEMP);
+	if (error != 0)
 		return (error);
 	error = SYSCTL_OUT(req, retbuf, strlen(retbuf) + 1);
 	free(freebuf, M_TEMP);