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 <ecturt@gmail.com>
MFC after:	3 days
Sponsored by:	The FreeBSD Foundation
This commit is contained in:
Mark Johnston 2020-09-22 17:05:01 +00:00
parent 58f351825a
commit 8e13d6dfb6
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=366005

View File

@ -589,6 +589,7 @@ udf_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp)
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, struct vnode **vpp)
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, struct vnode **vpp)
*vpp = vp;
return (0);
error:
vgone(vp);
vput(vp);
brelse(bp);
*vpp = NULL;
return (error);
}
static int