diff --git a/fs/udf/inode.c b/fs/udf/inode.c index baf9845ac06b..8babc2fbce9a 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -1675,8 +1675,15 @@ static int udf_read_inode(struct inode *inode, bool hidden_inode) struct deviceSpec *dsea = (struct deviceSpec *)udf_get_extendedattr(inode, 12, 1); - if (!dsea || !udf_device_spec_valid(dsea)) + if (IS_ERR(dsea)) { + ret = PTR_ERR(dsea); goto out; + } + /* Device inodes must have a device spec attribute */ + if (!dsea || !udf_device_spec_valid(dsea)) { + ret = -EFSCORRUPTED; + goto out; + } init_special_inode(inode, inode->i_mode, MKDEV(le32_to_cpu(dsea->majorDeviceIdent), le32_to_cpu(dsea->minorDeviceIdent))); @@ -1836,13 +1843,19 @@ int udf_write_inode(struct inode *inode, struct writeback_control *wbc) struct regid *eid; struct deviceSpec *dsea = (struct deviceSpec *)udf_get_extendedattr(inode, 12, 1); + + /* Validity of extended attrs was checked on load */ + if (WARN_ON_ONCE(IS_ERR(dsea))) { + err = PTR_ERR(dsea); + goto out_unlock; + } if (!dsea) { dsea = (struct deviceSpec *) udf_add_extendedattr(inode, sizeof(struct deviceSpec) + sizeof(struct regid), 12, 0x3); - if (!dsea) { - err = -ENOSPC; + if (IS_ERR(dsea)) { + err = PTR_ERR(dsea); goto out_unlock; } dsea->attrType = cpu_to_le32(12); @@ -1852,10 +1865,6 @@ int udf_write_inode(struct inode *inode, struct writeback_control *wbc) sizeof(struct regid)); dsea->impUseLength = cpu_to_le32(sizeof(struct regid)); } - if (!udf_device_spec_valid(dsea)) { - err = -EFSCORRUPTED; - goto out_unlock; - } eid = (struct regid *)dsea->impUse; memset(eid, 0, sizeof(*eid)); strcpy(eid->ident, UDF_ID_DEVELOPER); diff --git a/fs/udf/misc.c b/fs/udf/misc.c index 6928e378fbbd..a2084dfbfbd6 100644 --- a/fs/udf/misc.c +++ b/fs/udf/misc.c @@ -58,7 +58,7 @@ struct genericFormat *udf_add_extendedattr(struct inode *inode, uint32_t size, cpu_to_le16(TAG_IDENT_EAHD) || le32_to_cpu(eahd->descTag.tagLocation) != iinfo->i_location.logicalBlockNum) - return NULL; + return ERR_PTR(-EFSCORRUPTED); } else { struct udf_sb_info *sbi = UDF_SB(inode->i_sb); @@ -122,7 +122,7 @@ struct genericFormat *udf_add_extendedattr(struct inode *inode, uint32_t size, return (struct genericFormat *)&ea[offset]; } - return NULL; + return ERR_PTR(-ENOSPC); } struct genericFormat *udf_get_extendedattr(struct inode *inode, uint32_t type, @@ -144,7 +144,7 @@ struct genericFormat *udf_get_extendedattr(struct inode *inode, uint32_t type, cpu_to_le16(TAG_IDENT_EAHD) || le32_to_cpu(eahd->descTag.tagLocation) != iinfo->i_location.logicalBlockNum) - return NULL; + return ERR_PTR(-EFSCORRUPTED); if (type < 2048) offset = sizeof(struct extendedAttrHeaderDesc); @@ -153,16 +153,17 @@ struct genericFormat *udf_get_extendedattr(struct inode *inode, uint32_t type, else offset = le32_to_cpu(eahd->appAttrLocation); - while (offset + sizeof(*gaf) < iinfo->i_lenEAttr) { + while (offset < + iinfo->i_lenEAttr - sizeof(struct genericFormat)) { uint32_t attrLength; gaf = (struct genericFormat *)&ea[offset]; attrLength = le32_to_cpu(gaf->attrLength); /* Detect undersized elements and buffer overflows */ - if ((attrLength < sizeof(*gaf)) || - (attrLength > (iinfo->i_lenEAttr - offset))) - break; + if (attrLength < sizeof(struct genericFormat) || + attrLength > iinfo->i_lenEAttr - offset) + return ERR_PTR(-EFSCORRUPTED); if (le32_to_cpu(gaf->attrType) == type && gaf->attrSubtype == subtype)