| From foo@baz Wed Sep 21 12:45:10 CEST 2016 |
| From: Paul Blakey <paulb@mellanox.com> |
| Date: Thu, 18 Aug 2016 21:09:05 +0300 |
| Subject: net/mlx5: Added missing check of msg length in verifying its signature |
| |
| From: Paul Blakey <paulb@mellanox.com> |
| |
| |
| [ Upstream commit 2c0f8ce1b584a4d7b8ff53140d21dfed99834940 ] |
| |
| Set and verify signature calculates the signature for each of the |
| mailbox nodes, even for those that are unused (from cache). Added |
| a missing length check to set and verify only those which are used. |
| |
| While here, also moved the setting of msg's nodes token to where we |
| already go over them. This saves a pass because checksum is disabled, |
| and the only useful thing remaining that set signature does is setting |
| the token. |
| |
| Fixes: e126ba97dba9 ('mlx5: Add driver for Mellanox Connect-IB |
| adapters') |
| Signed-off-by: Paul Blakey <paulb@mellanox.com> |
| Signed-off-by: Saeed Mahameed <saeedm@mellanox.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/net/ethernet/mellanox/mlx5/core/cmd.c | 83 ++++++++++++++++---------- |
| 1 file changed, 53 insertions(+), 30 deletions(-) |
| |
| --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c |
| +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c |
| @@ -143,13 +143,14 @@ static struct mlx5_cmd_layout *get_inst( |
| return cmd->cmd_buf + (idx << cmd->log_stride); |
| } |
| |
| -static u8 xor8_buf(void *buf, int len) |
| +static u8 xor8_buf(void *buf, size_t offset, int len) |
| { |
| u8 *ptr = buf; |
| u8 sum = 0; |
| int i; |
| + int end = len + offset; |
| |
| - for (i = 0; i < len; i++) |
| + for (i = offset; i < end; i++) |
| sum ^= ptr[i]; |
| |
| return sum; |
| @@ -157,41 +158,49 @@ static u8 xor8_buf(void *buf, int len) |
| |
| static int verify_block_sig(struct mlx5_cmd_prot_block *block) |
| { |
| - if (xor8_buf(block->rsvd0, sizeof(*block) - sizeof(block->data) - 1) != 0xff) |
| + size_t rsvd0_off = offsetof(struct mlx5_cmd_prot_block, rsvd0); |
| + int xor_len = sizeof(*block) - sizeof(block->data) - 1; |
| + |
| + if (xor8_buf(block, rsvd0_off, xor_len) != 0xff) |
| return -EINVAL; |
| |
| - if (xor8_buf(block, sizeof(*block)) != 0xff) |
| + if (xor8_buf(block, 0, sizeof(*block)) != 0xff) |
| return -EINVAL; |
| |
| return 0; |
| } |
| |
| -static void calc_block_sig(struct mlx5_cmd_prot_block *block, u8 token, |
| - int csum) |
| +static void calc_block_sig(struct mlx5_cmd_prot_block *block) |
| { |
| - block->token = token; |
| - if (csum) { |
| - block->ctrl_sig = ~xor8_buf(block->rsvd0, sizeof(*block) - |
| - sizeof(block->data) - 2); |
| - block->sig = ~xor8_buf(block, sizeof(*block) - 1); |
| - } |
| + int ctrl_xor_len = sizeof(*block) - sizeof(block->data) - 2; |
| + size_t rsvd0_off = offsetof(struct mlx5_cmd_prot_block, rsvd0); |
| + |
| + block->ctrl_sig = ~xor8_buf(block, rsvd0_off, ctrl_xor_len); |
| + block->sig = ~xor8_buf(block, 0, sizeof(*block) - 1); |
| } |
| |
| -static void calc_chain_sig(struct mlx5_cmd_msg *msg, u8 token, int csum) |
| +static void calc_chain_sig(struct mlx5_cmd_msg *msg) |
| { |
| struct mlx5_cmd_mailbox *next = msg->next; |
| + int size = msg->len; |
| + int blen = size - min_t(int, sizeof(msg->first.data), size); |
| + int n = (blen + MLX5_CMD_DATA_BLOCK_SIZE - 1) |
| + / MLX5_CMD_DATA_BLOCK_SIZE; |
| + int i = 0; |
| |
| - while (next) { |
| - calc_block_sig(next->buf, token, csum); |
| + for (i = 0; i < n && next; i++) { |
| + calc_block_sig(next->buf); |
| next = next->next; |
| } |
| } |
| |
| static void set_signature(struct mlx5_cmd_work_ent *ent, int csum) |
| { |
| - ent->lay->sig = ~xor8_buf(ent->lay, sizeof(*ent->lay)); |
| - calc_chain_sig(ent->in, ent->token, csum); |
| - calc_chain_sig(ent->out, ent->token, csum); |
| + ent->lay->sig = ~xor8_buf(ent->lay, 0, sizeof(*ent->lay)); |
| + if (csum) { |
| + calc_chain_sig(ent->in); |
| + calc_chain_sig(ent->out); |
| + } |
| } |
| |
| static void poll_timeout(struct mlx5_cmd_work_ent *ent) |
| @@ -222,12 +231,17 @@ static int verify_signature(struct mlx5_ |
| struct mlx5_cmd_mailbox *next = ent->out->next; |
| int err; |
| u8 sig; |
| + int size = ent->out->len; |
| + int blen = size - min_t(int, sizeof(ent->out->first.data), size); |
| + int n = (blen + MLX5_CMD_DATA_BLOCK_SIZE - 1) |
| + / MLX5_CMD_DATA_BLOCK_SIZE; |
| + int i = 0; |
| |
| - sig = xor8_buf(ent->lay, sizeof(*ent->lay)); |
| + sig = xor8_buf(ent->lay, 0, sizeof(*ent->lay)); |
| if (sig != 0xff) |
| return -EINVAL; |
| |
| - while (next) { |
| + for (i = 0; i < n && next; i++) { |
| err = verify_block_sig(next->buf); |
| if (err) |
| return err; |
| @@ -641,7 +655,6 @@ static void cmd_work_handler(struct work |
| spin_unlock_irqrestore(&cmd->alloc_lock, flags); |
| } |
| |
| - ent->token = alloc_token(cmd); |
| cmd->ent_arr[ent->idx] = ent; |
| lay = get_inst(cmd, ent->idx); |
| ent->lay = lay; |
| @@ -755,7 +768,8 @@ static u8 *get_status_ptr(struct mlx5_ou |
| static int mlx5_cmd_invoke(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *in, |
| struct mlx5_cmd_msg *out, void *uout, int uout_size, |
| mlx5_cmd_cbk_t callback, |
| - void *context, int page_queue, u8 *status) |
| + void *context, int page_queue, u8 *status, |
| + u8 token) |
| { |
| struct mlx5_cmd *cmd = &dev->cmd; |
| struct mlx5_cmd_work_ent *ent; |
| @@ -772,6 +786,8 @@ static int mlx5_cmd_invoke(struct mlx5_c |
| if (IS_ERR(ent)) |
| return PTR_ERR(ent); |
| |
| + ent->token = token; |
| + |
| if (!callback) |
| init_completion(&ent->done); |
| |
| @@ -844,7 +860,8 @@ static const struct file_operations fops |
| .write = dbg_write, |
| }; |
| |
| -static int mlx5_copy_to_msg(struct mlx5_cmd_msg *to, void *from, int size) |
| +static int mlx5_copy_to_msg(struct mlx5_cmd_msg *to, void *from, int size, |
| + u8 token) |
| { |
| struct mlx5_cmd_prot_block *block; |
| struct mlx5_cmd_mailbox *next; |
| @@ -870,6 +887,7 @@ static int mlx5_copy_to_msg(struct mlx5_ |
| memcpy(block->data, from, copy); |
| from += copy; |
| size -= copy; |
| + block->token = token; |
| next = next->next; |
| } |
| |
| @@ -939,7 +957,8 @@ static void free_cmd_box(struct mlx5_cor |
| } |
| |
| static struct mlx5_cmd_msg *mlx5_alloc_cmd_msg(struct mlx5_core_dev *dev, |
| - gfp_t flags, int size) |
| + gfp_t flags, int size, |
| + u8 token) |
| { |
| struct mlx5_cmd_mailbox *tmp, *head = NULL; |
| struct mlx5_cmd_prot_block *block; |
| @@ -968,6 +987,7 @@ static struct mlx5_cmd_msg *mlx5_alloc_c |
| tmp->next = head; |
| block->next = cpu_to_be64(tmp->next ? tmp->next->dma : 0); |
| block->block_num = cpu_to_be32(n - i - 1); |
| + block->token = token; |
| head = tmp; |
| } |
| msg->next = head; |
| @@ -1351,7 +1371,7 @@ static struct mlx5_cmd_msg *alloc_msg(st |
| } |
| |
| if (IS_ERR(msg)) |
| - msg = mlx5_alloc_cmd_msg(dev, gfp, in_size); |
| + msg = mlx5_alloc_cmd_msg(dev, gfp, in_size, 0); |
| |
| return msg; |
| } |
| @@ -1376,6 +1396,7 @@ static int cmd_exec(struct mlx5_core_dev |
| int err; |
| u8 status = 0; |
| u32 drv_synd; |
| + u8 token; |
| |
| if (pci_channel_offline(dev->pdev) || |
| dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) { |
| @@ -1394,20 +1415,22 @@ static int cmd_exec(struct mlx5_core_dev |
| return err; |
| } |
| |
| - err = mlx5_copy_to_msg(inb, in, in_size); |
| + token = alloc_token(&dev->cmd); |
| + |
| + err = mlx5_copy_to_msg(inb, in, in_size, token); |
| if (err) { |
| mlx5_core_warn(dev, "err %d\n", err); |
| goto out_in; |
| } |
| |
| - outb = mlx5_alloc_cmd_msg(dev, gfp, out_size); |
| + outb = mlx5_alloc_cmd_msg(dev, gfp, out_size, token); |
| if (IS_ERR(outb)) { |
| err = PTR_ERR(outb); |
| goto out_in; |
| } |
| |
| err = mlx5_cmd_invoke(dev, inb, outb, out, out_size, callback, context, |
| - pages_queue, &status); |
| + pages_queue, &status, token); |
| if (err) |
| goto out_out; |
| |
| @@ -1475,7 +1498,7 @@ static int create_msg_cache(struct mlx5_ |
| INIT_LIST_HEAD(&cmd->cache.med.head); |
| |
| for (i = 0; i < NUM_LONG_LISTS; i++) { |
| - msg = mlx5_alloc_cmd_msg(dev, GFP_KERNEL, LONG_LIST_SIZE); |
| + msg = mlx5_alloc_cmd_msg(dev, GFP_KERNEL, LONG_LIST_SIZE, 0); |
| if (IS_ERR(msg)) { |
| err = PTR_ERR(msg); |
| goto ex_err; |
| @@ -1485,7 +1508,7 @@ static int create_msg_cache(struct mlx5_ |
| } |
| |
| for (i = 0; i < NUM_MED_LISTS; i++) { |
| - msg = mlx5_alloc_cmd_msg(dev, GFP_KERNEL, MED_LIST_SIZE); |
| + msg = mlx5_alloc_cmd_msg(dev, GFP_KERNEL, MED_LIST_SIZE, 0); |
| if (IS_ERR(msg)) { |
| err = PTR_ERR(msg); |
| goto ex_err; |