aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKonstantin Belousov <kib@FreeBSD.org>2026-07-27 16:58:31 +0000
committerKonstantin Belousov <kib@FreeBSD.org>2026-07-30 02:56:30 +0000
commit930f2e4da96487f18a82f912275c6302c39b9bd2 (patch)
tree91cb3d02bbae7f8ebec911afeb96e096af851b99
parentbcb62ec0e3d592892f0f304269ed2722d1bae75a (diff)
kern_execve(): avoid storing non-VDIR into p_textdvp
Reported by: Nick Price Tested by: pho Reviewed by: jah, markj Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential revision: https://reviews.freebsd.org/D58506
-rw-r--r--sys/kern/kern_exec.c38
1 files changed, 36 insertions, 2 deletions
diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c
index 35eb22e03f48..352170d4f6f0 100644
--- a/sys/kern/kern_exec.c
+++ b/sys/kern/kern_exec.c
@@ -32,12 +32,12 @@
#include "opt_ktrace.h"
#include "opt_vm.h"
-#include <sys/param.h>
#include <sys/systm.h>
#include <sys/acct.h>
#include <sys/asan.h>
#include <sys/capsicum.h>
#include <sys/compressor.h>
+#include <sys/dirent.h>
#include <sys/eventhandler.h>
#include <sys/exec.h>
#include <sys/fcntl.h>
@@ -568,12 +568,46 @@ interpret:
newbinname[nd.ni_cnd.cn_namelen] = '\0';
imgp->vp = newtextvp;
+ if (atomic_load_8(&newtextdvp->v_type) != VDIR) {
+ struct vnode *dvp1;
+ char *buf1;
+ size_t buf1len;
+
+ /*
+ * The newtextdvp vnode might be not a
+ * directory when reclaimed or when the image
+ * is mounted over a regular file. In the
+ * latter case, try to resolve the containing
+ * directory.
+ *
+ * In any case, p_textdvp must be either a
+ * directory or reclaimed.
+ */
+ VOP_UNLOCK(imgp->vp);
+ dvp1 = newtextdvp;
+ buf1len = MAXNAMLEN + 1;
+ buf1 = malloc(buf1len, M_TEMP, M_WAITOK);
+ error = vn_vptocnp(&dvp1, buf1, &buf1len);
+ if (error == 0) {
+ if (atomic_load_8(&dvp1->v_type) == VDIR) {
+ newtextdvp = dvp1;
+ } else {
+ vrele(dvp1);
+ newtextdvp = NULL;
+ }
+ } else {
+ newtextdvp = NULL;
+ }
+ free(buf1, M_TEMP);
+ vn_lock(imgp->vp, LK_SHARED | LK_RETRY);
+ }
+
/*
* Do the best to calculate the full path to the image file.
*/
if (args->fname[0] == '/') {
imgp->execpath = args->fname;
- } else {
+ } else if (newtextdvp != NULL) {
VOP_UNLOCK(imgp->vp);
freepath_size = MAXPATHLEN;
if (vn_fullpath_hardlink(newtextvp, newtextdvp,