git: 51b8ffb95c4f - main - fdesc_allocvp(): fix potential use after free
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 24 Mar 2023 17:47:41 UTC
The branch main has been updated by kib:
URL: https://cgit.FreeBSD.org/src/commit/?id=51b8ffb95c4fe45f6825d551bd093889820a8115
commit 51b8ffb95c4fe45f6825d551bd093889820a8115
Author: Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2023-03-21 21:24:06 +0000
Commit: Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2023-03-24 17:46:53 +0000
fdesc_allocvp(): fix potential use after free
Just owning the interlock is not enough for vget() to operate on the
vnode race-free with vgone(), the vnode should be held. Use
vget_prep()/vget_finish() to avoid vholding the vnode explicitly, and
drop LK_INTERLOCK.
Reviewed by: markj
Tested by: pho
Sponsored by: The FreeBSD Foundation
MFC after: 1 week
Differential revision: https://reviews.freebsd.org/D39207
---
sys/fs/fdescfs/fdesc_vnops.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/sys/fs/fdescfs/fdesc_vnops.c b/sys/fs/fdescfs/fdesc_vnops.c
index d3c7951672cf..afefaff8acf4 100644
--- a/sys/fs/fdescfs/fdesc_vnops.c
+++ b/sys/fs/fdescfs/fdesc_vnops.c
@@ -147,6 +147,7 @@ fdesc_allocvp(fdntype ftype, unsigned fd_fd, int ix, struct mount *mp,
struct fdhashhead *fc;
struct fdescnode *fd, *fd2;
struct vnode *vp, *vp2;
+ enum vgetstate vgs;
int error;
fc = FD_NHASH(ix);
@@ -166,9 +167,9 @@ loop:
if (fd->fd_ix == ix && fd->fd_vnode->v_mount == mp) {
/* Get reference to vnode in case it's being free'd */
vp = fd->fd_vnode;
- VI_LOCK(vp);
+ vgs = vget_prep(vp);
mtx_unlock(&fdesc_hashmtx);
- if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK))
+ if (vget_finish(vp, LK_EXCLUSIVE, vgs) != 0)
goto loop;
*vpp = vp;
return (0);
@@ -218,9 +219,9 @@ loop:
if (fd2->fd_ix == ix && fd2->fd_vnode->v_mount == mp) {
/* Get reference to vnode in case it's being free'd */
vp2 = fd2->fd_vnode;
- VI_LOCK(vp2);
+ vgs = vget_prep(vp2);
mtx_unlock(&fdesc_hashmtx);
- error = vget(vp2, LK_EXCLUSIVE | LK_INTERLOCK);
+ error = vget_finish(vp2, LK_EXCLUSIVE, vgs);
/* Someone beat us, dec use count and wait for reclaim */
vgone(vp);
vput(vp);