Extract proc_get_binpath() from sysctl_kern_proc_pathname()

Reviewed by:	emaste, markj
Sponsored by:	The FreeBSD Foundation
MFC after:	1 week
Differential revision:	https://reviews.freebsd.org/D32738
This commit is contained in:
Konstantin Belousov 2021-10-29 04:42:59 +03:00
parent b4c7d45c84
commit f34fc6ba06
2 changed files with 58 additions and 33 deletions

View File

@ -2226,41 +2226,34 @@ sysctl_kern_proc_auxv(SYSCTL_HANDLER_ARGS)
}
/*
* This sysctl allows a process to retrieve the path of the executable for
* itself or another process.
* Look up the canonical executable path running in the specified process.
* It tries to return the same hardlink name as was used for execve(2).
* This allows the programs that modify their behavior based on their progname,
* to operate correctly.
*
* Result is returned in retbuf, it must not be freed, similar to vn_fullpath()
* calling conventions.
* binname is a pointer to temporary string buffer of length MAXPATHLEN,
* allocated and freed by caller.
* freebuf should be freed by caller, from the M_TEMP malloc type.
*/
static int
sysctl_kern_proc_pathname(SYSCTL_HANDLER_ARGS)
int
proc_get_binpath(struct proc *p, char *binname, char **retbuf,
char **freebuf)
{
pid_t *pidp = (pid_t *)arg1;
unsigned int arglen = arg2;
struct proc *p;
struct vnode *vp, *dvp;
char *retbuf, *freebuf, *binname;
struct nameidata nd;
struct vnode *vp, *dvp;
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) {
free(binname, M_TEMP);
return (error);
}
}
PROC_LOCK_ASSERT(p, MA_OWNED);
vp = p->p_textvp;
if (vp == NULL) {
if (*pidp != -1)
PROC_UNLOCK(p);
free(binname, M_TEMP);
PROC_UNLOCK(p);
*retbuf = NULL;
*freebuf = NULL;
return (0);
}
vref(vp);
@ -2269,20 +2262,20 @@ sysctl_kern_proc_pathname(SYSCTL_HANDLER_ARGS)
vref(dvp);
if (p->p_binname != NULL)
strlcpy(binname, p->p_binname, MAXPATHLEN);
if (*pidp != -1)
PROC_UNLOCK(p);
PROC_UNLOCK(p);
do_fullpath = true;
freebuf = NULL;
*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) {
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,
NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, *retbuf,
req->td);
error = namei(&nd);
if (error == 0) {
@ -2294,13 +2287,43 @@ sysctl_kern_proc_pathname(SYSCTL_HANDLER_ARGS)
}
}
if (do_fullpath) {
free(freebuf, M_TEMP);
freebuf = NULL;
error = vn_fullpath(vp, &retbuf, &freebuf);
free(*freebuf, M_TEMP);
*freebuf = NULL;
error = vn_fullpath(vp, retbuf, freebuf);
}
vrele(vp);
if (dvp != NULL)
vrele(dvp);
return (error);
}
/*
* This sysctl allows a process to retrieve the path of the executable for
* itself or another process.
*/
static int
sysctl_kern_proc_pathname(SYSCTL_HANDLER_ARGS)
{
pid_t *pidp = (pid_t *)arg1;
unsigned int arglen = arg2;
struct proc *p;
char *retbuf, *freebuf, *binname;
int error;
if (arglen != 1)
return (EINVAL);
binname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
binname[0] = '\0';
if (*pidp == -1) { /* -1 means this process */
error = 0;
p = req->td->td_proc;
PROC_LOCK(p);
} else {
error = pget(*pidp, PGET_CANSEE, &p);
}
if (error == 0)
error = proc_get_binpath(p, binname, &retbuf, &freebuf);
free(binname, M_TEMP);
if (error != 0)
return (error);

View File

@ -1128,6 +1128,8 @@ struct pargs *pargs_alloc(int len);
void pargs_drop(struct pargs *pa);
void pargs_hold(struct pargs *pa);
void proc_add_orphan(struct proc *child, struct proc *parent);
int proc_get_binpath(struct proc *p, char *binname, char **fullpath,
char **freepath);
int proc_getargv(struct thread *td, struct proc *p, struct sbuf *sb);
int proc_getauxv(struct thread *td, struct proc *p, struct sbuf *sb);
int proc_getenvv(struct thread *td, struct proc *p, struct sbuf *sb);