The branch main has been updated by kib:

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

commit aec97963cd03f10e04083537ed449a84a5e42f87
Author:     Konstantin Belousov <[email protected]>
AuthorDate: 2021-12-26 21:51:48 +0000
Commit:     Konstantin Belousov <[email protected]>
CommitDate: 2022-01-08 03:41:44 +0000

    msdosfs: do no allow lookup to return vdp except for dot lookups
    
    In collaboaration with: pho
    Reviewed by:    markj, mckusick
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D33721
---
 sys/fs/msdosfs/msdosfs_lookup.c | 33 +++++++++++++++++++++++++++++----
 1 file changed, 29 insertions(+), 4 deletions(-)

diff --git a/sys/fs/msdosfs/msdosfs_lookup.c b/sys/fs/msdosfs/msdosfs_lookup.c
index 38bded459692..3db9665f6094 100644
--- a/sys/fs/msdosfs/msdosfs_lookup.c
+++ b/sys/fs/msdosfs/msdosfs_lookup.c
@@ -63,6 +63,28 @@
 #include <fs/msdosfs/fat.h>
 #include <fs/msdosfs/msdosfsmount.h>
 
+static int
+msdosfs_lookup_checker(struct msdosfsmount *pmp, struct vnode *dvp,
+    struct denode *tdp, struct vnode **vpp)
+{
+       struct vnode *vp;
+
+       vp = DETOV(tdp);
+
+       /*
+        * Lookup assumes that directory cannot be hardlinked.
+        * Corrupted msdosfs filesystem could break this assumption.
+        */
+       if (vp == dvp) {
+               vput(vp);
+               *vpp = NULL;
+               return (EBADF);
+       }
+
+       *vpp = vp;
+       return (0);
+}
+
 int
 msdosfs_lookup(struct vop_cachedlookup_args *ap)
 {
@@ -501,8 +523,7 @@ foundroot:
                error = deget(pmp, cluster, blkoff, LK_EXCLUSIVE, &tdp);
                if (error)
                        return (error);
-               *vpp = DETOV(tdp);
-               return (0);
+               return (msdosfs_lookup_checker(pmp, vdp, tdp, vpp));
        }
 
        /*
@@ -529,7 +550,9 @@ foundroot:
                if ((error = deget(pmp, cluster, blkoff, LK_EXCLUSIVE,
                    &tdp)) != 0)
                        return (error);
-               *vpp = DETOV(tdp);
+               if ((error = msdosfs_lookup_checker(pmp, vdp, tdp, vpp))
+                   != 0)
+                       return (error);
                cnp->cn_flags |= SAVENAME;
                return (0);
        }
@@ -572,6 +595,7 @@ foundroot:
                        vput(*vpp);
                        goto restart;
                }
+               return (msdosfs_lookup_checker(pmp, vdp, VTODE(*vpp), vpp));
        } else if (dp->de_StartCluster == scn && isadir) {
                if (cnp->cn_namelen != 1 || cnp->cn_nameptr[0] != '.') {
                        /* fs is corrupted, non-dot lookup returned dvp */
@@ -583,7 +607,8 @@ foundroot:
                if ((error = deget(pmp, cluster, blkoff, LK_EXCLUSIVE,
                    &tdp)) != 0)
                        return (error);
-               *vpp = DETOV(tdp);
+               if ((error = msdosfs_lookup_checker(pmp, vdp, tdp, vpp)) != 0)
+                       return (error);
        }
 
        /*

Reply via email to