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
This commit is contained in:
Konstantin Belousov 2021-10-23 22:01:37 +03:00
parent 351d5f7fc5
commit ee92c8a842

View File

@ -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);