Commit 1c7f09d2 authored by Darrick J. Wong's avatar Darrick J. Wong

xfs: validate recovered name buffers when recovering xattr items

Strengthen the xattri log item recovery code by checking that we
actually have the required name and newname buffers for whatever
operation we're replaying.
Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
parent 2a2c05d0
...@@ -741,22 +741,20 @@ xlog_recover_attri_commit_pass2( ...@@ -741,22 +741,20 @@ xlog_recover_attri_commit_pass2(
const void *attr_value = NULL; const void *attr_value = NULL;
const void *attr_name; const void *attr_name;
size_t len; size_t len;
unsigned int op; unsigned int op, i = 0;
attri_formatp = item->ri_buf[0].i_addr;
attr_name = item->ri_buf[1].i_addr;
/* Validate xfs_attri_log_format before the large memory allocation */ /* Validate xfs_attri_log_format before the large memory allocation */
len = sizeof(struct xfs_attri_log_format); len = sizeof(struct xfs_attri_log_format);
if (item->ri_buf[0].i_len != len) { if (item->ri_buf[i].i_len != len) {
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
item->ri_buf[0].i_addr, item->ri_buf[0].i_len); item->ri_buf[0].i_addr, item->ri_buf[0].i_len);
return -EFSCORRUPTED; return -EFSCORRUPTED;
} }
attri_formatp = item->ri_buf[i].i_addr;
if (!xfs_attri_validate(mp, attri_formatp)) { if (!xfs_attri_validate(mp, attri_formatp)) {
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
item->ri_buf[0].i_addr, item->ri_buf[0].i_len); attri_formatp, len);
return -EFSCORRUPTED; return -EFSCORRUPTED;
} }
...@@ -785,31 +783,69 @@ xlog_recover_attri_commit_pass2( ...@@ -785,31 +783,69 @@ xlog_recover_attri_commit_pass2(
attri_formatp, len); attri_formatp, len);
return -EFSCORRUPTED; return -EFSCORRUPTED;
} }
i++;
/* Validate the attr name */ /* Validate the attr name */
if (item->ri_buf[1].i_len != if (item->ri_buf[i].i_len !=
xlog_calc_iovec_len(attri_formatp->alfi_name_len)) { xlog_calc_iovec_len(attri_formatp->alfi_name_len)) {
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
item->ri_buf[0].i_addr, item->ri_buf[0].i_len); attri_formatp, len);
return -EFSCORRUPTED; return -EFSCORRUPTED;
} }
attr_name = item->ri_buf[i].i_addr;
if (!xfs_attr_namecheck(attr_name, attri_formatp->alfi_name_len)) { if (!xfs_attr_namecheck(attr_name, attri_formatp->alfi_name_len)) {
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
item->ri_buf[1].i_addr, item->ri_buf[1].i_len); attri_formatp, len);
return -EFSCORRUPTED; return -EFSCORRUPTED;
} }
i++;
/* Validate the attr value, if present */ /* Validate the attr value, if present */
if (attri_formatp->alfi_value_len != 0) { if (attri_formatp->alfi_value_len != 0) {
if (item->ri_buf[2].i_len != xlog_calc_iovec_len(attri_formatp->alfi_value_len)) { if (item->ri_buf[i].i_len != xlog_calc_iovec_len(attri_formatp->alfi_value_len)) {
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
item->ri_buf[0].i_addr, item->ri_buf[0].i_addr,
item->ri_buf[0].i_len); item->ri_buf[0].i_len);
return -EFSCORRUPTED; return -EFSCORRUPTED;
} }
attr_value = item->ri_buf[2].i_addr; attr_value = item->ri_buf[i].i_addr;
i++;
}
/*
* Make sure we got the correct number of buffers for the operation
* that we just loaded.
*/
if (i != item->ri_total) {
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
attri_formatp, len);
return -EFSCORRUPTED;
}
switch (op) {
case XFS_ATTRI_OP_FLAGS_REMOVE:
/* Regular remove operations operate only on names. */
if (attr_value != NULL || attri_formatp->alfi_value_len != 0) {
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
attri_formatp, len);
return -EFSCORRUPTED;
}
fallthrough;
case XFS_ATTRI_OP_FLAGS_SET:
case XFS_ATTRI_OP_FLAGS_REPLACE:
/*
* Regular xattr set/remove/replace operations require a name
* and do not take a newname. Values are optional for set and
* replace.
*/
if (attr_name == NULL || attri_formatp->alfi_name_len == 0) {
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
attri_formatp, len);
return -EFSCORRUPTED;
}
break;
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment