xfs: validate recovered name buffers when recovering xattr items
commit 1c7f09d210aba2f2bb206e2e8c97c9f11a3fd880 upstream. 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: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Catherine Hoang <catherine.hoang@oracle.com> Acked-by: Darrick J. Wong <djwong@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
db460c26f0
commit
9716cdcc2f
|
@ -719,22 +719,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -763,31 +761,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in New Issue