git: 54c0eac7c101 - stable/13 - cache: only let non-dir descriptors through when doing EMPTYPATH lookups

From: Mateusz Guzik <mjg_at_FreeBSD.org>
Date: Sat, 05 Mar 2022 19:56:52 UTC
The branch stable/13 has been updated by mjg:

URL: https://cgit.FreeBSD.org/src/commit/?id=54c0eac7c101c9927d581c12dcf2d6a2514d6aaf

commit 54c0eac7c101c9927d581c12dcf2d6a2514d6aaf
Author:     Mateusz Guzik <mjg@FreeBSD.org>
AuthorDate: 2021-10-27 18:17:59 +0000
Commit:     Mateusz Guzik <mjg@FreeBSD.org>
CommitDate: 2022-03-05 19:52:57 +0000

    cache: only let non-dir descriptors through when doing EMPTYPATH lookups
    
    Otherwise things like realpath against a file and '.' end up with an
    illegal state of having a regular vnode for the parent.
    
    Reported by:    syzbot+9aa5439dd9c708aeb1a8@syzkaller.appspotmail.com
    
    (cherry picked from commit 628c3b307fb29e9812008b8a0b3ccb73e0f0ecfa)
---
 sys/kern/vfs_cache.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c
index 14e148b2f839..bc85c96c045f 100644
--- a/sys/kern/vfs_cache.c
+++ b/sys/kern/vfs_cache.c
@@ -4242,19 +4242,28 @@ cache_can_fplookup(struct cache_fpl *fpl)
 	return (true);
 }
 
-static int
+static int __noinline
 cache_fplookup_dirfd(struct cache_fpl *fpl, struct vnode **vpp)
 {
 	struct nameidata *ndp;
+	struct componentname *cnp;
 	int error;
 	bool fsearch;
 
 	ndp = fpl->ndp;
+	cnp = fpl->cnp;
+
 	error = fgetvp_lookup_smr(ndp->ni_dirfd, ndp, vpp, &fsearch);
 	if (__predict_false(error != 0)) {
 		return (cache_fpl_aborted(fpl));
 	}
 	fpl->fsearch = fsearch;
+	if ((*vpp)->v_type != VDIR) {
+		if (!((cnp->cn_flags & EMPTYPATH) != 0 && cnp->cn_pnbuf[0] == '\0')) {
+			cache_fpl_smr_exit(fpl);
+			return (cache_fpl_handled_error(fpl, ENOTDIR));
+		}
+	}
 	return (0);
 }