Commit 6dd0e5cc authored by Alison Schofield's avatar Alison Schofield Committed by Dan Williams

cxl/mbox: Move cxl_mem_command construction to helper funcs

Sanitizing and constructing a cxl_mem_command from a userspace
command is part of the validation process prior to submitting
the command to a CXL device. Move this work to helper functions:
cxl_to_mem_cmd(), cxl_to_mem_cmd_raw().

This declutters cxl_validate_cmd_from_user() in preparation for
adding new validation steps.
Signed-off-by: default avatarAlison Schofield <alison.schofield@intel.com>
Reviewed-by: default avatarJonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: default avatarDan Williams <dan.j.williams@intel.com>
Link: https://lore.kernel.org/r/7d9b826f29262e3a484cb4bb7b63872134d60bd7.1648687552.git.alison.schofield@intel.comSigned-off-by: default avatarDan Williams <dan.j.williams@intel.com>
parent ce522ba9
...@@ -207,76 +207,42 @@ static bool cxl_mem_raw_command_allowed(u16 opcode) ...@@ -207,76 +207,42 @@ static bool cxl_mem_raw_command_allowed(u16 opcode)
return true; return true;
} }
/** static int cxl_to_mem_cmd_raw(struct cxl_mem_command *mem_cmd,
* cxl_validate_cmd_from_user() - Check fields for CXL_MEM_SEND_COMMAND. const struct cxl_send_command *send_cmd,
* @cxlds: The device data for the operation struct cxl_dev_state *cxlds)
* @send_cmd: &struct cxl_send_command copied in from userspace.
* @out_cmd: Sanitized and populated &struct cxl_mem_command.
*
* Return:
* * %0 - @out_cmd is ready to send.
* * %-ENOTTY - Invalid command specified.
* * %-EINVAL - Reserved fields or invalid values were used.
* * %-ENOMEM - Input or output buffer wasn't sized properly.
* * %-EPERM - Attempted to use a protected command.
* * %-EBUSY - Kernel has claimed exclusive access to this opcode
*
* The result of this command is a fully validated command in @out_cmd that is
* safe to send to the hardware.
*
* See handle_mailbox_cmd_from_user()
*/
static int cxl_validate_cmd_from_user(struct cxl_dev_state *cxlds,
const struct cxl_send_command *send_cmd,
struct cxl_mem_command *out_cmd)
{ {
const struct cxl_command_info *info; if (send_cmd->raw.rsvd)
struct cxl_mem_command *c;
if (send_cmd->id == 0 || send_cmd->id >= CXL_MEM_COMMAND_ID_MAX)
return -ENOTTY;
/*
* The user can never specify an input payload larger than what hardware
* supports, but output can be arbitrarily large (simply write out as
* much data as the hardware provides).
*/
if (send_cmd->in.size > cxlds->payload_size)
return -EINVAL; return -EINVAL;
/* /*
* Checks are bypassed for raw commands but a WARN/taint will occur * Unlike supported commands, the output size of RAW commands
* later in the callchain * gets passed along without further checking, so it must be
* validated here.
*/ */
if (send_cmd->id == CXL_MEM_COMMAND_ID_RAW) { if (send_cmd->out.size > cxlds->payload_size)
const struct cxl_mem_command temp = { return -EINVAL;
.info = {
.id = CXL_MEM_COMMAND_ID_RAW,
.flags = 0,
.size_in = send_cmd->in.size,
.size_out = send_cmd->out.size,
},
.opcode = send_cmd->raw.opcode
};
if (send_cmd->raw.rsvd)
return -EINVAL;
/* if (!cxl_mem_raw_command_allowed(send_cmd->raw.opcode))
* Unlike supported commands, the output size of RAW commands return -EPERM;
* gets passed along without further checking, so it must be
* validated here.
*/
if (send_cmd->out.size > cxlds->payload_size)
return -EINVAL;
if (!cxl_mem_raw_command_allowed(send_cmd->raw.opcode)) *mem_cmd = (struct cxl_mem_command) {
return -EPERM; .info = {
.id = CXL_MEM_COMMAND_ID_RAW,
.size_in = send_cmd->in.size,
.size_out = send_cmd->out.size,
},
.opcode = send_cmd->raw.opcode
};
memcpy(out_cmd, &temp, sizeof(temp)); return 0;
}
return 0; static int cxl_to_mem_cmd(struct cxl_mem_command *mem_cmd,
} const struct cxl_send_command *send_cmd,
struct cxl_dev_state *cxlds)
{
struct cxl_mem_command *c = &cxl_mem_commands[send_cmd->id];
const struct cxl_command_info *info = &c->info;
if (send_cmd->flags & ~CXL_MEM_COMMAND_FLAG_MASK) if (send_cmd->flags & ~CXL_MEM_COMMAND_FLAG_MASK)
return -EINVAL; return -EINVAL;
...@@ -287,10 +253,6 @@ static int cxl_validate_cmd_from_user(struct cxl_dev_state *cxlds, ...@@ -287,10 +253,6 @@ static int cxl_validate_cmd_from_user(struct cxl_dev_state *cxlds,
if (send_cmd->in.rsvd || send_cmd->out.rsvd) if (send_cmd->in.rsvd || send_cmd->out.rsvd)
return -EINVAL; return -EINVAL;
/* Convert user's command into the internal representation */
c = &cxl_mem_commands[send_cmd->id];
info = &c->info;
/* Check that the command is enabled for hardware */ /* Check that the command is enabled for hardware */
if (!test_bit(info->id, cxlds->enabled_cmds)) if (!test_bit(info->id, cxlds->enabled_cmds))
return -ENOTTY; return -ENOTTY;
...@@ -307,15 +269,58 @@ static int cxl_validate_cmd_from_user(struct cxl_dev_state *cxlds, ...@@ -307,15 +269,58 @@ static int cxl_validate_cmd_from_user(struct cxl_dev_state *cxlds,
if (info->size_out >= 0 && send_cmd->out.size < info->size_out) if (info->size_out >= 0 && send_cmd->out.size < info->size_out)
return -ENOMEM; return -ENOMEM;
memcpy(out_cmd, c, sizeof(*c)); *mem_cmd = (struct cxl_mem_command) {
out_cmd->info.size_in = send_cmd->in.size; .info = {
.id = info->id,
.flags = info->flags,
.size_in = send_cmd->in.size,
.size_out = send_cmd->out.size,
},
.opcode = c->opcode
};
return 0;
}
/**
* cxl_validate_cmd_from_user() - Check fields for CXL_MEM_SEND_COMMAND.
* @cxlds: The device data for the operation
* @send_cmd: &struct cxl_send_command copied in from userspace.
* @out_cmd: Sanitized and populated &struct cxl_mem_command.
*
* Return:
* * %0 - @out_cmd is ready to send.
* * %-ENOTTY - Invalid command specified.
* * %-EINVAL - Reserved fields or invalid values were used.
* * %-ENOMEM - Input or output buffer wasn't sized properly.
* * %-EPERM - Attempted to use a protected command.
* * %-EBUSY - Kernel has claimed exclusive access to this opcode
*
* The result of this command is a fully validated command in @out_cmd that is
* safe to send to the hardware.
*
* See handle_mailbox_cmd_from_user()
*/
static int cxl_validate_cmd_from_user(struct cxl_dev_state *cxlds,
const struct cxl_send_command *send_cmd,
struct cxl_mem_command *out_cmd)
{
if (send_cmd->id == 0 || send_cmd->id >= CXL_MEM_COMMAND_ID_MAX)
return -ENOTTY;
/* /*
* XXX: out_cmd->info.size_out will be controlled by the driver, and the * The user can never specify an input payload larger than what hardware
* specified number of bytes @send_cmd->out.size will be copied back out * supports, but output can be arbitrarily large (simply write out as
* to userspace. * much data as the hardware provides).
*/ */
if (send_cmd->in.size > cxlds->payload_size)
return -EINVAL;
return 0; /* Sanitize and construct a cxl_mem_command */
if (send_cmd->id == CXL_MEM_COMMAND_ID_RAW)
return cxl_to_mem_cmd_raw(out_cmd, send_cmd, cxlds);
else
return cxl_to_mem_cmd(out_cmd, send_cmd, cxlds);
} }
int cxl_query_cmd(struct cxl_memdev *cxlmd, int cxl_query_cmd(struct cxl_memdev *cxlmd,
......
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