summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/adfs/dir_fplus.c29
1 files changed, 28 insertions, 1 deletions
diff --git a/fs/adfs/dir_fplus.c b/fs/adfs/dir_fplus.c
index b83a74e9ff6d..a2fa416fbb6d 100644
--- a/fs/adfs/dir_fplus.c
+++ b/fs/adfs/dir_fplus.c
@@ -19,11 +19,38 @@ static unsigned int adfs_fplus_offset(const struct adfs_bigdirheader *h,
static int adfs_fplus_validate_header(const struct adfs_bigdirheader *h)
{
unsigned int size = le32_to_cpu(h->bigdirsize);
+ unsigned int len;
if (h->bigdirversion[0] != 0 || h->bigdirversion[1] != 0 ||
h->bigdirversion[2] != 0 ||
h->bigdirstartname != cpu_to_le32(BIGDIRSTARTNAME) ||
- size & 2047)
+ !size || size & 2047 || size > SZ_4M)
+ return -EIO;
+
+ size -= sizeof(struct adfs_bigdirtail) +
+ offsetof(struct adfs_bigdirheader, bigdirname);
+
+ /* Check that bigdirnamelen fits within the directory */
+ len = ALIGN(le32_to_cpu(h->bigdirnamelen), 4);
+ if (len > size)
+ return -EIO;
+
+ size -= len;
+
+ /* Check that bigdirnamesize fits within the directory */
+ len = le32_to_cpu(h->bigdirnamesize);
+ if (len > size)
+ return -EIO;
+
+ size -= len;
+
+ /*
+ * Avoid division, we know that absolute maximum number of entries
+ * can not be so large to cause overflow of the multiplication below.
+ */
+ len = le32_to_cpu(h->bigdirentries);
+ if (len > SZ_4M / sizeof(struct adfs_bigdirentry) ||
+ len * sizeof(struct adfs_bigdirentry) > size)
return -EIO;
return 0;