diff --git a/sys/vfs/udf/udf_vfsops.c b/sys/vfs/udf/udf_vfsops.c --- a/sys/vfs/udf/udf_vfsops.c +++ b/sys/vfs/udf/udf_vfsops.c @@ -525,6 +525,22 @@ return(ENOMEM); } size = UDF_FENTRY_SIZE + fe->l_ea + fe->l_ad; + /* + * A file entry occupies exactly one block (ECMA-167 [4/14.9]). + * l_ea and l_ad are attacker-controlled uint32s read off disk and + * must not drive `size` past the bsize bytes we read into bp->b_data, + * otherwise the bcopy below over-reads the buffer. The size < check + * also catches uint32 overflow wrapping the int back below the + * header size. + */ + if (size > udfmp->bsize || size < (int)UDF_FENTRY_SIZE) { + kprintf("udf_vget: file entry too large (%d > %d)\n", + size, udfmp->bsize); + error = EINVAL; + brelse(bp); + kfree(unode, M_UDFNODE); + return(error); + } unode->fentry = kmalloc(size, M_UDFFENTRY, M_WAITOK | M_ZERO); bcopy(bp->b_data, unode->fentry, size);