rename(2): do not allow to rename root vnode of the mounted filesystem

Check for tdvp being vp_crossmp.  This cannot happen for the normal
rename cases, but could if the target path specified by the syscall
points to the nullfs mount over the regular file.  In this case namei()
cannot step over crossmp, and keep it in ni_dvp.

Since crossmp VOP_GETWRITEMOUNT() returns NULL mp, we retry the locking
dance since the belief is that NULL return is transient.

PR:	295826
Reviewed by:	markj
Tested by:	pho
Sponsored by:	The FreeBSD Foundation
MFC after:	1 week
Differential revision:	https://reviews.freebsd.org/D57453
This commit is contained in:
Konstantin Belousov
2026-06-04 22:56:36 +03:00
parent 5d0ebfe1d9
commit d53633bfcf
3 changed files with 11 additions and 1 deletions
+1 -1
View File
@@ -113,7 +113,7 @@ SDT_PROBE_DEFINE4(vfs, namei, lookup, return, "int", "struct vnode *", "bool",
uma_zone_t namei_zone;
/* Placeholder vnode for mp traversal. */
static struct vnode *vp_crossmp;
struct vnode *vp_crossmp;
static int
crossmp_vop_islocked(struct vop_islocked_args *ap)
+9
View File
@@ -3823,6 +3823,15 @@ kern_renameat(struct thread *td, int oldfd, const char *old, int newfd,
}
tdvp = tond.ni_dvp;
tvp = tond.ni_vp;
if (tdvp == vp_crossmp) {
/*
* Rename of the root vnode of the mounted
* filesystem. It is possible to get there with the
* nullfs mount over the regular file.
*/
error = EBUSY;
goto out;
}
if (tvp != NULL && (flags & AT_RENAME_NOREPLACE) != 0) {
/*
* Often filesystems need to relock the vnodes in
+1
View File
@@ -462,6 +462,7 @@ extern struct mount *rootdevmp; /* "/dev" mount */
extern u_long desiredvnodes; /* number of vnodes desired */
extern struct uma_zone *namei_zone;
extern struct vattr va_null; /* predefined null vattr structure */
extern struct vnode *vp_crossmp;
extern u_int vn_lock_pair_pause_max;