aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Eßer <se@FreeBSD.org>2024-02-20 12:02:24 +0000
committerStefan Eßer <se@FreeBSD.org>2024-02-23 10:47:58 +0000
commitfba1a994acfe31d957e9e26a5f12a6fdd1689bd2 (patch)
tree9ce2c4b57b2fa8a0612dda43b70bcdcd66567bd0
parentc76878c656e91aa595c2c81e86ac5adb59a15c98 (diff)
downloadsrc-fba1a994acfe31d957e9e26a5f12a6fdd1689bd2.tar.gz
src-fba1a994acfe31d957e9e26a5f12a6fdd1689bd2.zip
msdosfs: fix potential inode collision on FAT12 and FAT16
PR: 277239 Approved by: mckusick (cherry picked from commit 445d3d227e68f85157d0301d1706aa488e8423da)
-rw-r--r--sys/fs/msdosfs/denode.h8
-rw-r--r--sys/fs/msdosfs/msdosfs_denode.c19
-rw-r--r--sys/fs/msdosfs/msdosfs_lookup.c2
3 files changed, 24 insertions, 5 deletions
diff --git a/sys/fs/msdosfs/denode.h b/sys/fs/msdosfs/denode.h
index ad52a736592c..0d31b0583fa6 100644
--- a/sys/fs/msdosfs/denode.h
+++ b/sys/fs/msdosfs/denode.h
@@ -162,7 +162,7 @@ struct denode {
u_long de_FileSize; /* size of file in bytes */
struct fatcache de_fc[FC_SIZE]; /* FAT cache */
u_quad_t de_modrev; /* Revision level for lease. */
- uint64_t de_inode; /* Inode number (really byte offset of direntry) */
+ uint64_t de_inode; /* Inode number (really index of DOS style direntry) */
};
/*
@@ -217,6 +217,12 @@ struct denode {
#define VTODE(vp) ((struct denode *)(vp)->v_data)
#define DETOV(de) ((de)->de_vnode)
+#define DETOI(pmp, cn, off) \
+ ((cn) == MSDOSFSROOT \
+ ? (((uint64_t)(off) >> 5)) \
+ : (((((uint64_t)pmp->pm_bpcluster * ((cn) - 2) + (off))) >> 5) \
+ + pmp->pm_RootDirEnts))
+
#define DETIMES(dep, acc, mod, cre) do { \
if ((dep)->de_flag & DE_UPDATE) { \
(dep)->de_flag |= DE_MODIFIED; \
diff --git a/sys/fs/msdosfs/msdosfs_denode.c b/sys/fs/msdosfs/msdosfs_denode.c
index 612b318ce6e8..7f275d387a25 100644
--- a/sys/fs/msdosfs/msdosfs_denode.c
+++ b/sys/fs/msdosfs/msdosfs_denode.c
@@ -133,10 +133,13 @@ deget(struct msdosfsmount *pmp, u_long dirclust, u_long diroffset,
* entry that represented the file happens to be reused while the
* deleted file is still open.
*/
- inode = (uint64_t)pmp->pm_bpcluster * dirclust + diroffset;
+ inode = DETOI(pmp, dirclust, diroffset);
error = vfs_hash_get(mntp, inode, lkflags, curthread, &nvp,
de_vncmpf, &inode);
+#ifdef MSDOSFS_DEBUG
+ printf("vfs_hash_get(inode %lu) error %d\n", inode, error);
+#endif
if (error)
return (error);
if (nvp != NULL) {
@@ -191,6 +194,9 @@ badoff:
}
error = vfs_hash_insert(nvp, inode, lkflags, curthread, &xvp,
de_vncmpf, &inode);
+#ifdef MSDOSFS_DEBUG
+ printf("vfs_hash_insert(inode %lu) error %d\n", inode, error);
+#endif
if (error) {
*depp = NULL;
return (error);
@@ -589,8 +595,11 @@ reinsert(struct denode *dep)
return;
#endif
vp = DETOV(dep);
- dep->de_inode = (uint64_t)dep->de_pmp->pm_bpcluster * dep->de_dirclust +
- dep->de_diroffset;
+ dep->de_inode = DETOI(dep->de_pmp, dep->de_dirclust, dep->de_diroffset);
+#ifdef MSDOSFS_DEBUG
+ printf("vfs_hash_rehash(inode %lu, refcnt %lu, vp %p)\n",
+ dep->de_inode, dep->de_refcnt, vp);
+#endif
vfs_hash_rehash(vp, dep->de_inode);
}
@@ -608,6 +617,10 @@ msdosfs_reclaim(struct vop_reclaim_args *ap)
/*
* Remove the denode from its hash chain.
*/
+#ifdef MSDOSFS_DEBUG
+ printf("vfs_hash_remove(inode %lu, refcnt %lu, vp %p)\n",
+ dep->de_inode, dep->de_refcnt, vp);
+#endif
vfs_hash_remove(vp);
/*
* Purge old data structures associated with the denode.
diff --git a/sys/fs/msdosfs/msdosfs_lookup.c b/sys/fs/msdosfs/msdosfs_lookup.c
index eb4cbaa21ab7..2a90339d0878 100644
--- a/sys/fs/msdosfs/msdosfs_lookup.c
+++ b/sys/fs/msdosfs/msdosfs_lookup.c
@@ -586,7 +586,7 @@ foundroot:
}
if (FAT32(pmp) && scn == MSDOSFSROOT)
scn = pmp->pm_rootdirblk;
- inode1 = scn * pmp->pm_bpcluster + blkoff;
+ inode1 = DETOI(pmp, scn, blkoff);
if (VTODE(*vpp)->de_inode != inode1) {
vput(*vpp);
goto restart;