aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKonstantin Belousov <kib@FreeBSD.org>2021-10-29 01:42:59 +0000
committerKonstantin Belousov <kib@FreeBSD.org>2021-11-06 02:12:32 +0000
commit0303cc4be8538ae16c577cdeda30823ada76f802 (patch)
treec0cc1725b252d505d74791d51e4e3317da718f4b
parent52e2887d1dcb1e214eeacf09b9af401194053754 (diff)
downloadsrc-0303cc4be8538ae16c577cdeda30823ada76f802.tar.gz
src-0303cc4be8538ae16c577cdeda30823ada76f802.zip
Extract proc_get_binpath() from sysctl_kern_proc_pathname()
(cherry picked from commit f34fc6ba06a10e0f2a505ec0dd2f2fab2a79e53d)
-rw-r--r--sys/kern/kern_proc.c89
-rw-r--r--sys/sys/proc.h2
2 files changed, 58 insertions, 33 deletions
diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c
index c4c01da1faea..2156c5c465ba 100644
--- a/sys/kern/kern_proc.c
+++ b/sys/kern/kern_proc.c
@@ -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);
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
index a09a006b836b..96bd2cc8a6ce 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -1115,6 +1115,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);