The branch main has been updated by des:

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

commit 55f80afa17e8926f69660f19631194bcf7fa66f4
Author:     Dag-Erling Smørgrav <d...@freebsd.org>
AuthorDate: 2025-07-16 19:33:24 +0000
Commit:     Dag-Erling Smørgrav <d...@freebsd.org>
CommitDate: 2025-07-16 19:33:41 +0000

    udf: Improve input validation.
    
    The existing code frequently assigns unsigned 64-bit values to variables
    that are signed and / or shorter without checking for overflow.  Try to
    deal with these cases.
    
    While here, fix two structs that used single-element arrays in place of
    flexible array members.
    
    PR:             287896
    MFC after:      1 week
    Reviewed by:    imp
    Differential Revision:  https://reviews.freebsd.org/D51339
---
 sys/fs/udf/ecma167-udf.h |  4 ++--
 sys/fs/udf/udf_vfsops.c  |  7 ++++++-
 sys/fs/udf/udf_vnops.c   | 48 ++++++++++++++++++++++++++++++++++++------------
 3 files changed, 44 insertions(+), 15 deletions(-)

diff --git a/sys/fs/udf/ecma167-udf.h b/sys/fs/udf/ecma167-udf.h
index 839bbec08254..19e114763cac 100644
--- a/sys/fs/udf/ecma167-udf.h
+++ b/sys/fs/udf/ecma167-udf.h
@@ -243,7 +243,7 @@ struct part_map_spare {
        uint8_t                 n_st;   /* Number of Sparing Tables */
        uint8_t                 reserved1;
        uint32_t                st_size;
-       uint32_t                st_loc[1];
+       uint32_t                st_loc[];
 } __packed;
 
 union udf_pmap {
@@ -266,7 +266,7 @@ struct udf_sparing_table {
        uint16_t                rt_l;   /* Relocation Table len */
        uint8_t                 reserved[2];
        uint32_t                seq_num;
-       struct spare_map_entry  entries[1];
+       struct spare_map_entry  entries[];
 } __packed;
 
 /* Partition Descriptor [3/10.5] */
diff --git a/sys/fs/udf/udf_vfsops.c b/sys/fs/udf/udf_vfsops.c
index c7438147c0a0..c5ef1f686093 100644
--- a/sys/fs/udf/udf_vfsops.c
+++ b/sys/fs/udf/udf_vfsops.c
@@ -81,6 +81,7 @@
 #include <sys/fcntl.h>
 #include <sys/iconv.h>
 #include <sys/kernel.h>
+#include <sys/limits.h>
 #include <sys/malloc.h>
 #include <sys/mount.h>
 #include <sys/namei.h>
@@ -729,7 +730,7 @@ udf_fhtovp(struct mount *mp, struct fid *fhp, int flags, 
struct vnode **vpp)
        struct ifid *ifhp;
        struct vnode *nvp;
        struct udf_node *np;
-       off_t fsize;
+       uint64_t fsize;
        int error;
 
        ifhp = (struct ifid *)fhp;
@@ -741,6 +742,10 @@ udf_fhtovp(struct mount *mp, struct fid *fhp, int flags, 
struct vnode **vpp)
 
        np = VTON(nvp);
        fsize = le64toh(np->fentry->inf_len);
+       if (fsize > OFF_MAX) {
+               *vpp = NULLVP;
+               return (EIO);
+       }
 
        *vpp = nvp;
        vnode_create_vobject(*vpp, fsize, curthread);
diff --git a/sys/fs/udf/udf_vnops.c b/sys/fs/udf/udf_vnops.c
index 88bf4917a851..37889241e8c3 100644
--- a/sys/fs/udf/udf_vnops.c
+++ b/sys/fs/udf/udf_vnops.c
@@ -39,6 +39,7 @@
 #include <sys/conf.h>
 #include <sys/buf.h>
 #include <sys/iconv.h>
+#include <sys/limits.h>
 #include <sys/mount.h>
 #include <sys/vnode.h>
 #include <sys/dirent.h>
@@ -182,11 +183,14 @@ udf_access(struct vop_access_args *a)
 }
 
 static int
-udf_open(struct vop_open_args *ap) {
+udf_open(struct vop_open_args *ap)
+{
        struct udf_node *np = VTON(ap->a_vp);
-       off_t fsize;
+       uint64_t fsize;
 
        fsize = le64toh(np->fentry->inf_len);
+       if (fsize > OFF_MAX)
+               return (EIO);
        vnode_create_vobject(ap->a_vp, fsize, ap->a_td);
        return 0;
 }
@@ -314,12 +318,13 @@ udf_getattr(struct vop_getattr_args *a)
                 * that directories consume at least one logical block,
                 * make it appear so.
                 */
-               if (fentry->logblks_rec != 0) {
-                       vap->va_size =
-                           le64toh(fentry->logblks_rec) * node->udfmp->bsize;
-               } else {
+               vap->va_size = le64toh(fentry->logblks_rec);
+               if (vap->va_size == 0)
                        vap->va_size = node->udfmp->bsize;
-               }
+               else if (vap->va_size > UINT64_MAX / node->udfmp->bsize)
+                       vap->va_size = UINT64_MAX;
+               else
+                       vap->va_size *= node->udfmp->bsize;
        } else {
                vap->va_size = le64toh(fentry->inf_len);
        }
@@ -446,6 +451,7 @@ udf_read(struct vop_read_args *ap)
        struct buf *bp;
        uint8_t *data;
        daddr_t lbn, rablock;
+       uint64_t len;
        off_t diff, fsize;
        ssize_t n;
        int error = 0;
@@ -471,7 +477,12 @@ udf_read(struct vop_read_args *ap)
                return (error);
        }
 
-       fsize = le64toh(node->fentry->inf_len);
+       len = le64toh(node->fentry->inf_len);
+       if (len > OFF_MAX) {
+               /* too big, just cap to the requested length */
+               len = uio->uio_resid;
+       }
+       fsize = len;
        udfmp = node->udfmp;
        do {
                lbn = lblkno(udfmp, uio->uio_offset);
@@ -783,6 +794,7 @@ udf_readdir(struct vop_readdir_args *a)
        struct udf_uiodir uiodir;
        struct udf_dirstream *ds;
        uint64_t *cookies = NULL;
+       uint64_t len;
        int ncookies;
        int error = 0;
 
@@ -811,8 +823,12 @@ udf_readdir(struct vop_readdir_args *a)
         * Iterate through the file id descriptors.  Give the parent dir
         * entry special attention.
         */
-       ds = udf_opendir(node, uio->uio_offset, le64toh(node->fentry->inf_len),
-           node->udfmp);
+       len = le64toh(node->fentry->inf_len);
+       if (len > INT_MAX) {
+               /* too big, just cap to INT_MAX */
+               len = INT_MAX;
+       }
+       ds = udf_opendir(node, uio->uio_offset, len, node->udfmp);
 
        while ((fid = udf_getfid(ds)) != NULL) {
                /* XXX Should we return an error on a bad fid? */
@@ -904,7 +920,8 @@ udf_readlink(struct vop_readlink_args *ap)
        struct udf_node *node;
        void *buf;
        char *cp;
-       int error, len, root;
+       uint64_t len;
+       int error, root;
 
        /*
         * A symbolic link in UDF is a list of variable-length path
@@ -914,6 +931,8 @@ udf_readlink(struct vop_readlink_args *ap)
        vp = ap->a_vp;
        node = VTON(vp);
        len = le64toh(node->fentry->inf_len);
+       if (len > MAXPATHLEN)
+               return (EIO);
        buf = malloc(len, M_DEVBUF, M_WAITOK);
        iov[0].iov_len = len;
        iov[0].iov_base = buf;
@@ -1116,13 +1135,14 @@ udf_lookup(struct vop_cachedlookup_args *a)
        struct udf_mnt *udfmp;
        struct fileid_desc *fid = NULL;
        struct udf_dirstream *ds;
+       uint64_t fsize;
        u_long nameiop;
        u_long flags;
        char *nameptr;
        long namelen;
        ino_t id = 0;
        int offset, error = 0;
-       int fsize, lkflags, ltype, numdirpasses;
+       int lkflags, ltype, numdirpasses;
 
        dvp = a->a_dvp;
        node = VTON(dvp);
@@ -1133,6 +1153,10 @@ udf_lookup(struct vop_cachedlookup_args *a)
        nameptr = a->a_cnp->cn_nameptr;
        namelen = a->a_cnp->cn_namelen;
        fsize = le64toh(node->fentry->inf_len);
+       if (fsize > INT_MAX) {
+               /* too big, just cap to INT_MAX */
+               fsize = INT_MAX;
+       }
 
        /*
         * If this is a LOOKUP and we've already partially searched through

Reply via email to