diff options
author | Alan Somers <asomers@FreeBSD.org> | 2022-05-04 23:36:17 +0000 |
---|---|---|
committer | Alan Somers <asomers@FreeBSD.org> | 2022-05-12 20:32:26 +0000 |
commit | 0bef4927ea858bb18b6f679bc0a36cff264dc842 (patch) | |
tree | cfec5e4bcaab80a4c7a629d44777d125ea9cea0e /sys/fs/fuse/fuse_vnops.c | |
parent | 8b582b16402102df10a715c626e212bbbc8e9d7c (diff) | |
download | src-0bef4927ea858bb18b6f679bc0a36cff264dc842.tar.gz src-0bef4927ea858bb18b6f679bc0a36cff264dc842.zip |
fusefs: handle evil servers that return illegal inode numbers
* If during FUSE_CREATE, FUSE_MKDIR, etc the server returns the same
inode number for the new file as for its parent directory, reject it.
Previously this would triggers a recurse-on-non-recursive lock panic.
* If during FUSE_LINK the server returns a different inode number for
the new name as for the old one, reject it. Obviously, that can't be
a hard link.
* If during FUSE_LOOKUP the server returns the same inode number for the
new file as for its parent directory, reject it. Nothing good can
come of this.
PR: 263662
Reported by: Robert Morris <rtm@lcs.mit.edu>
MFC after: 2 weeks
Reviewed by: pfg
Differential Revision: https://reviews.freebsd.org/D35128
Diffstat (limited to 'sys/fs/fuse/fuse_vnops.c')
-rw-r--r-- | sys/fs/fuse/fuse_vnops.c | 27 |
1 files changed, 24 insertions, 3 deletions
diff --git a/sys/fs/fuse/fuse_vnops.c b/sys/fs/fuse/fuse_vnops.c index 9ffc8f32c048..845ea04eca93 100644 --- a/sys/fs/fuse/fuse_vnops.c +++ b/sys/fs/fuse/fuse_vnops.c @@ -1327,6 +1327,16 @@ fuse_vnop_link(struct vop_link_args *ap) } feo = fdi.answ; + if (fli.oldnodeid != feo->nodeid) { + struct fuse_data *data = fuse_get_mpdata(vnode_mount(vp)); + fuse_warn(data, FSESS_WARN_ILLEGAL_INODE, + "Assigned wrong inode for a hard link."); + fuse_vnode_clear_attr_cache(vp); + fuse_vnode_clear_attr_cache(tdvp); + err = EIO; + goto out; + } + err = fuse_internal_checkentry(feo, vnode_vtype(vp)); if (!err) { /* @@ -1386,6 +1396,7 @@ fuse_vnop_lookup(struct vop_lookup_args *ap) struct mount *mp = vnode_mount(dvp); struct fuse_data *data = fuse_get_mpdata(mp); int default_permissions = data->dataflags & FSESS_DEFAULT_PERMISSIONS; + bool is_dot; int err = 0; int lookup_err = 0; @@ -1413,6 +1424,7 @@ fuse_vnop_lookup(struct vop_lookup_args *ap) else if ((err = fuse_internal_access(dvp, VEXEC, td, cred))) return err; + is_dot = cnp->cn_namelen == 1 && *(cnp->cn_nameptr) == '.'; if ((flags & ISDOTDOT) && !(data->dataflags & FSESS_EXPORT_SUPPORT)) { if (!(VTOFUD(dvp)->flag & FN_PARENT_NID)) { @@ -1427,7 +1439,7 @@ fuse_vnop_lookup(struct vop_lookup_args *ap) return ENOENT; /* .. is obviously a directory */ vtyp = VDIR; - } else if (cnp->cn_namelen == 1 && *(cnp->cn_nameptr) == '.') { + } else if (is_dot) { nid = VTOI(dvp); /* . is obviously a directory */ vtyp = VDIR; @@ -1546,8 +1558,17 @@ fuse_vnop_lookup(struct vop_lookup_args *ap) &vp); *vpp = vp; } else if (nid == VTOI(dvp)) { - vref(dvp); - *vpp = dvp; + if (is_dot) { + vref(dvp); + *vpp = dvp; + } else { + fuse_warn(fuse_get_mpdata(mp), + FSESS_WARN_ILLEGAL_INODE, + "Assigned same inode to both parent and " + "child."); + err = EIO; + } + } else { struct fuse_vnode_data *fvdat; |