Skip to content

Commit

Permalink
wifi: iwlwifi: calib: Refactor iwl_calib_result usage for clarity
Browse files Browse the repository at this point in the history
In preparation for FORTIFY_SOURCE performing run-time destination buffer
bounds checking for memcpy(), refactor the use of struct iwl_calib_result:

- Have struct iwl_calib_result contain struct iwl_calib_cmd since
  functions expect to operate on the "data" flex array in "cmd", which
  follows the "hdr" member.
- Switch argument passing around to use struct iwl_calib_cmd instead of
  struct iwl_calib_hdr to prepare functions to see the "data" member.
- Change iwl_calib_set()'s "len" argument to a size_t since it is always
  unsigned and is normally receiving the output of sizeof().
- Add an explicit length sanity check in iwl_calib_set().
- Adjust the memcpy() to avoid copying across the now visible composite
  flex array structure.

This avoids the future run-time warning:

  memcpy: detected field-spanning write (size 8) of single field "&res->hdr" (size 4)

Cc: Luca Coelho <[email protected]>
Cc: Kalle Valo <[email protected]>
Cc: "David S. Miller" <[email protected]>
Cc: Jakub Kicinski <[email protected]>
Cc: Lee Jones <[email protected]>
Cc: Johannes Berg <[email protected]>
Cc: [email protected]
Cc: [email protected]
Reported-by: Andy Lavr <[email protected]>
Signed-off-by: Kees Cook <[email protected]>
Signed-off-by: Kalle Valo <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
  • Loading branch information
kees authored and Kalle Valo committed Sep 7, 2022
1 parent b008f4a commit 0d24201
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 15 deletions.
2 changes: 1 addition & 1 deletion drivers/net/wireless/intel/iwlwifi/dvm/agn.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ int iwl_load_ucode_wait_alive(struct iwl_priv *priv,
enum iwl_ucode_type ucode_type);
int iwl_send_calib_results(struct iwl_priv *priv);
int iwl_calib_set(struct iwl_priv *priv,
const struct iwl_calib_hdr *cmd, int len);
const struct iwl_calib_cmd *cmd, size_t len);
void iwl_calib_free_results(struct iwl_priv *priv);
int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
char **buf);
Expand Down
22 changes: 12 additions & 10 deletions drivers/net/wireless/intel/iwlwifi/dvm/calib.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@
struct iwl_calib_result {
struct list_head list;
size_t cmd_len;
struct iwl_calib_hdr hdr;
/* data follows */
struct iwl_calib_cmd cmd;
};

struct statistics_general_data {
Expand All @@ -43,12 +42,12 @@ int iwl_send_calib_results(struct iwl_priv *priv)
int ret;

hcmd.len[0] = res->cmd_len;
hcmd.data[0] = &res->hdr;
hcmd.data[0] = &res->cmd;
hcmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
ret = iwl_dvm_send_cmd(priv, &hcmd);
if (ret) {
IWL_ERR(priv, "Error %d on calib cmd %d\n",
ret, res->hdr.op_code);
ret, res->cmd.hdr.op_code);
return ret;
}
}
Expand All @@ -57,19 +56,22 @@ int iwl_send_calib_results(struct iwl_priv *priv)
}

int iwl_calib_set(struct iwl_priv *priv,
const struct iwl_calib_hdr *cmd, int len)
const struct iwl_calib_cmd *cmd, size_t len)
{
struct iwl_calib_result *res, *tmp;

res = kmalloc(sizeof(*res) + len - sizeof(struct iwl_calib_hdr),
GFP_ATOMIC);
if (check_sub_overflow(len, sizeof(*cmd), &len))
return -ENOMEM;

res = kmalloc(struct_size(res, cmd.data, len), GFP_ATOMIC);
if (!res)
return -ENOMEM;
memcpy(&res->hdr, cmd, len);
res->cmd_len = len;
res->cmd = *cmd;
memcpy(res->cmd.data, cmd->data, len);
res->cmd_len = struct_size(cmd, data, len);

list_for_each_entry(tmp, &priv->calib_results, list) {
if (tmp->hdr.op_code == res->hdr.op_code) {
if (tmp->cmd.hdr.op_code == res->cmd.hdr.op_code) {
list_replace(&tmp->list, &res->list);
kfree(tmp);
return 0;
Expand Down
8 changes: 4 additions & 4 deletions drivers/net/wireless/intel/iwlwifi/dvm/ucode.c
Original file line number Diff line number Diff line change
Expand Up @@ -356,18 +356,18 @@ static bool iwlagn_wait_calib(struct iwl_notif_wait_data *notif_wait,
struct iwl_rx_packet *pkt, void *data)
{
struct iwl_priv *priv = data;
struct iwl_calib_hdr *hdr;
struct iwl_calib_cmd *cmd;

if (pkt->hdr.cmd != CALIBRATION_RES_NOTIFICATION) {
WARN_ON(pkt->hdr.cmd != CALIBRATION_COMPLETE_NOTIFICATION);
return true;
}

hdr = (struct iwl_calib_hdr *)pkt->data;
cmd = (struct iwl_calib_cmd *)pkt->data;

if (iwl_calib_set(priv, hdr, iwl_rx_packet_payload_len(pkt)))
if (iwl_calib_set(priv, cmd, iwl_rx_packet_payload_len(pkt)))
IWL_ERR(priv, "Failed to record calibration data %d\n",
hdr->op_code);
cmd->hdr.op_code);

return false;
}
Expand Down

0 comments on commit 0d24201

Please sign in to comment.