aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason A. Harmening <jah@FreeBSD.org>2021-12-21 23:51:51 +0000
committerEd Maste <emaste@FreeBSD.org>2023-01-09 02:31:15 +0000
commit04f8674aa7486ec2d73d60c2247fe5e33b5399c5 (patch)
treecb81cd117309769aad300926d9d6d6c730fca8b1
parentf61fca7409f67f7f8d3e68e8b6c15cf4ae976895 (diff)
downloadsrc-04f8674aa7486ec2d73d60c2247fe5e33b5399c5.tar.gz
src-04f8674aa7486ec2d73d60c2247fe5e33b5399c5.zip
unionfs: implement VOP_SET_TEXT/VOP_UNSET_TEXT
The implementation simply passes the text ref to the appropriate underlying vnode. Without this, the default [un]set_text implementation will only manage the text ref on the unionfs vnode, causing it to be out of sync with the underlying filesystems and potentially allowing corruption of executable file contents. On INVARIANTS kernels, it also readily produces a panic on process termination because the VM object representing the executable mapping is backed by the underlying vnode, not the unionfs vnode. PR: 251342 Reviewed by: kib Differential Revision: https://reviews.freebsd.org/D33611 (cherry picked from commit 9e891d43f586e91541bd61fb12550de296d76fd9)
-rw-r--r--sys/fs/unionfs/union_vnops.c34
1 files changed, 34 insertions, 0 deletions
diff --git a/sys/fs/unionfs/union_vnops.c b/sys/fs/unionfs/union_vnops.c
index 09fbccb3d7ff..331235ab93d5 100644
--- a/sys/fs/unionfs/union_vnops.c
+++ b/sys/fs/unionfs/union_vnops.c
@@ -2503,6 +2503,38 @@ unionfs_add_writecount(struct vop_add_writecount_args *ap)
return (error);
}
+static int
+unionfs_set_text(struct vop_set_text_args *ap)
+{
+ struct vnode *tvp;
+ struct unionfs_node *unp;
+ int error;
+
+ /*
+ * We assume text refs are managed against lvp/uvp through the
+ * executable mapping backed by its VM object. We therefore don't
+ * need to track leased text refs in the case of a forcible unmount.
+ */
+ unp = VTOUNIONFS(ap->a_vp);
+ ASSERT_VOP_LOCKED(ap->a_vp, __func__);
+ tvp = unp->un_uppervp != NULL ? unp->un_uppervp : unp->un_lowervp;
+ error = VOP_SET_TEXT(tvp);
+ return (error);
+}
+
+static int
+unionfs_unset_text(struct vop_unset_text_args *ap)
+{
+ struct vnode *tvp;
+ struct unionfs_node *unp;
+
+ ASSERT_VOP_LOCKED(ap->a_vp, __func__);
+ unp = VTOUNIONFS(ap->a_vp);
+ tvp = unp->un_uppervp != NULL ? unp->un_uppervp : unp->un_lowervp;
+ VOP_UNSET_TEXT_CHECKED(tvp);
+ return (0);
+}
+
struct vop_vector unionfs_vnodeops = {
.vop_default = &default_vnodeops,
@@ -2553,5 +2585,7 @@ struct vop_vector unionfs_vnodeops = {
.vop_write = unionfs_write,
.vop_vptofh = unionfs_vptofh,
.vop_add_writecount = unionfs_add_writecount,
+ .vop_set_text = unionfs_set_text,
+ .vop_unset_text = unionfs_unset_text,
};
VFS_VOP_VECTOR_REGISTER(unionfs_vnodeops);