diff options
author | Jason A. Harmening <jah@FreeBSD.org> | 2021-12-21 23:51:51 +0000 |
---|---|---|
committer | Jason A. Harmening <jah@FreeBSD.org> | 2022-01-03 03:52:58 +0000 |
commit | 9e891d43f586e91541bd61fb12550de296d76fd9 (patch) | |
tree | eb713117305e96275ac904e192994245014fa188 | |
parent | d877dd5767bcbda5f3138facaceac6cab5820da3 (diff) | |
download | src-9e891d43f586e91541bd61fb12550de296d76fd9.tar.gz src-9e891d43f586e91541bd61fb12550de296d76fd9.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
-rw-r--r-- | sys/fs/unionfs/union_vnops.c | 34 |
1 files changed, 34 insertions, 0 deletions
diff --git a/sys/fs/unionfs/union_vnops.c b/sys/fs/unionfs/union_vnops.c index dc02e20f376f..43cf415ca755 100644 --- a/sys/fs/unionfs/union_vnops.c +++ b/sys/fs/unionfs/union_vnops.c @@ -2671,6 +2671,38 @@ unionfs_vput_pair(struct vop_vput_pair_args *ap) return (res); } +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, @@ -2722,5 +2754,7 @@ struct vop_vector unionfs_vnodeops = { .vop_vptofh = unionfs_vptofh, .vop_add_writecount = unionfs_add_writecount, .vop_vput_pair = unionfs_vput_pair, + .vop_set_text = unionfs_set_text, + .vop_unset_text = unionfs_unset_text, }; VFS_VOP_VECTOR_REGISTER(unionfs_vnodeops); |