Author: markj
Date: Tue Sep 22 17:05:01 2020
New Revision: 366005
URL: https://svnweb.freebsd.org/changeset/base/366005

Log:
  udf: Validate the full file entry length
  
  Otherwise a corrupted file entry containing invalid extended attribute
  lengths or allocation descriptor lengths can trigger an overflow when
  the file entry is loaded.
  
  admbug:               965
  PR:           248613
  Reported by:  C Turt <ect...@gmail.com>
  MFC after:    3 days
  Sponsored by: The FreeBSD Foundation

Modified:
  head/sys/fs/udf/udf_vfsops.c

Modified: head/sys/fs/udf/udf_vfsops.c
==============================================================================
--- head/sys/fs/udf/udf_vfsops.c        Tue Sep 22 16:18:31 2020        
(r366004)
+++ head/sys/fs/udf/udf_vfsops.c        Tue Sep 22 17:05:01 2020        
(r366005)
@@ -589,6 +589,7 @@ udf_vget(struct mount *mp, ino_t ino, int flags, struc
        struct vnode *vp;
        struct udf_node *unode;
        struct file_entry *fe;
+       uint32_t lea, lad;
        int error, sector, size;
 
        error = vfs_hash_get(mp, ino, flags, curthread, vpp, NULL, NULL);
@@ -644,31 +645,37 @@ udf_vget(struct mount *mp, ino_t ino, int flags, struc
        devvp = udfmp->im_devvp;
        if ((error = RDSECTOR(devvp, sector, udfmp->bsize, &bp)) != 0) {
                printf("Cannot read sector %d\n", sector);
-               vgone(vp);
-               vput(vp);
-               brelse(bp);
-               *vpp = NULL;
-               return (error);
+               goto error;
        }
 
+       /*
+        * File entry length validation.
+        */
        fe = (struct file_entry *)bp->b_data;
        if (udf_checktag(&fe->tag, TAGID_FENTRY)) {
                printf("Invalid file entry!\n");
-               vgone(vp);
-               vput(vp);
-               brelse(bp);
-               *vpp = NULL;
-               return (ENOMEM);
+               error = ENOMEM;
+               goto error;
        }
-       size = UDF_FENTRY_SIZE + le32toh(fe->l_ea) + le32toh(fe->l_ad);
+       lea = le32toh(fe->l_ea);
+       lad = le32toh(fe->l_ad);
+       if (lea > udfmp->bsize || lad > udfmp->bsize) {
+               printf("Invalid EA and AD lengths %u, %u\n", lea, lad);
+               error = EIO;
+               goto error;
+       }
+       size = UDF_FENTRY_SIZE + lea + lad;
+       if (size > udfmp->bsize) {
+               printf("Invalid file entry size %u\n", size);
+               error = EIO;
+               goto error;
+       }
+
        unode->fentry = malloc(size, M_UDFFENTRY, M_NOWAIT | M_ZERO);
        if (unode->fentry == NULL) {
                printf("Cannot allocate file entry block\n");
-               vgone(vp);
-               vput(vp);
-               brelse(bp);
-               *vpp = NULL;
-               return (ENOMEM);
+               error = ENOMEM;
+               goto error;
        }
 
        bcopy(bp->b_data, unode->fentry, size);
@@ -713,6 +720,13 @@ udf_vget(struct mount *mp, ino_t ino, int flags, struc
        *vpp = vp;
 
        return (0);
+
+error:
+       vgone(vp);
+       vput(vp);
+       brelse(bp);
+       *vpp = NULL;
+       return (error);
 }
 
 static int
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to