udf: Avoid confusion of missing and corrupted extended attributes

udf_get_extendedattr() returns NULL either when extended attribute was
not found or when some corrupted attribute was found. Similarly
udf_add_extendedattr() returns NULL when extended attributes are
corrupted or when there's no space to insert the extended attribute.
Make both functions return proper error codes to discern these cases and
handle them in the callers.

Signed-off-by: Jan Kara <jack@suse.cz>
This commit is contained in:
Jan Kara 2026-09-01 10:55:38 +02:00
parent 9a23909596
commit 127b0d8764
2 changed files with 24 additions and 14 deletions

View File

@ -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);

View File

@ -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)