Commit c74751f4 authored by Vasundhara Volam's avatar Vasundhara Volam Committed by David S. Miller

bnxt_en: Return error if FW returns more data than dump length

If any change happened in the configuration of VF in VM while
collecting live dump, there could be a race and firmware can return
more data than allocated dump length. Fix it by keeping track of
the accumulated core dump length copied so far and abort the copy
with error code if the next chunk of core dump will exceed the
original dump length.

Fixes: 6c5657d0 ("bnxt_en: Add support for ethtool get dump.")
Signed-off-by: default avatarVasundhara Volam <vasundhara-v.volam@broadcom.com>
Signed-off-by: default avatarMichael Chan <michael.chan@broadcom.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 325f85f3
...@@ -3071,8 +3071,15 @@ static int bnxt_hwrm_dbg_dma_data(struct bnxt *bp, void *msg, int msg_len, ...@@ -3071,8 +3071,15 @@ static int bnxt_hwrm_dbg_dma_data(struct bnxt *bp, void *msg, int msg_len,
} }
} }
if (info->dest_buf) if (info->dest_buf) {
if ((info->seg_start + off + len) <=
BNXT_COREDUMP_BUF_LEN(info->buf_len)) {
memcpy(info->dest_buf + off, dma_buf, len); memcpy(info->dest_buf + off, dma_buf, len);
} else {
rc = -ENOBUFS;
break;
}
}
if (cmn_req->req_type == if (cmn_req->req_type ==
cpu_to_le16(HWRM_DBG_COREDUMP_RETRIEVE)) cpu_to_le16(HWRM_DBG_COREDUMP_RETRIEVE))
...@@ -3126,7 +3133,7 @@ static int bnxt_hwrm_dbg_coredump_initiate(struct bnxt *bp, u16 component_id, ...@@ -3126,7 +3133,7 @@ static int bnxt_hwrm_dbg_coredump_initiate(struct bnxt *bp, u16 component_id,
static int bnxt_hwrm_dbg_coredump_retrieve(struct bnxt *bp, u16 component_id, static int bnxt_hwrm_dbg_coredump_retrieve(struct bnxt *bp, u16 component_id,
u16 segment_id, u32 *seg_len, u16 segment_id, u32 *seg_len,
void *buf, u32 offset) void *buf, u32 buf_len, u32 offset)
{ {
struct hwrm_dbg_coredump_retrieve_input req = {0}; struct hwrm_dbg_coredump_retrieve_input req = {0};
struct bnxt_hwrm_dbg_dma_info info = {NULL}; struct bnxt_hwrm_dbg_dma_info info = {NULL};
...@@ -3141,8 +3148,11 @@ static int bnxt_hwrm_dbg_coredump_retrieve(struct bnxt *bp, u16 component_id, ...@@ -3141,8 +3148,11 @@ static int bnxt_hwrm_dbg_coredump_retrieve(struct bnxt *bp, u16 component_id,
seq_no); seq_no);
info.data_len_off = offsetof(struct hwrm_dbg_coredump_retrieve_output, info.data_len_off = offsetof(struct hwrm_dbg_coredump_retrieve_output,
data_len); data_len);
if (buf) if (buf) {
info.dest_buf = buf + offset; info.dest_buf = buf + offset;
info.buf_len = buf_len;
info.seg_start = offset;
}
rc = bnxt_hwrm_dbg_dma_data(bp, &req, sizeof(req), &info); rc = bnxt_hwrm_dbg_dma_data(bp, &req, sizeof(req), &info);
if (!rc) if (!rc)
...@@ -3232,14 +3242,17 @@ bnxt_fill_coredump_record(struct bnxt *bp, struct bnxt_coredump_record *record, ...@@ -3232,14 +3242,17 @@ bnxt_fill_coredump_record(struct bnxt *bp, struct bnxt_coredump_record *record,
static int bnxt_get_coredump(struct bnxt *bp, void *buf, u32 *dump_len) static int bnxt_get_coredump(struct bnxt *bp, void *buf, u32 *dump_len)
{ {
u32 ver_get_resp_len = sizeof(struct hwrm_ver_get_output); u32 ver_get_resp_len = sizeof(struct hwrm_ver_get_output);
u32 offset = 0, seg_hdr_len, seg_record_len, buf_len = 0;
struct coredump_segment_record *seg_record = NULL; struct coredump_segment_record *seg_record = NULL;
u32 offset = 0, seg_hdr_len, seg_record_len;
struct bnxt_coredump_segment_hdr seg_hdr; struct bnxt_coredump_segment_hdr seg_hdr;
struct bnxt_coredump coredump = {NULL}; struct bnxt_coredump coredump = {NULL};
time64_t start_time; time64_t start_time;
u16 start_utc; u16 start_utc;
int rc = 0, i; int rc = 0, i;
if (buf)
buf_len = *dump_len;
start_time = ktime_get_real_seconds(); start_time = ktime_get_real_seconds();
start_utc = sys_tz.tz_minuteswest * 60; start_utc = sys_tz.tz_minuteswest * 60;
seg_hdr_len = sizeof(seg_hdr); seg_hdr_len = sizeof(seg_hdr);
...@@ -3272,6 +3285,12 @@ static int bnxt_get_coredump(struct bnxt *bp, void *buf, u32 *dump_len) ...@@ -3272,6 +3285,12 @@ static int bnxt_get_coredump(struct bnxt *bp, void *buf, u32 *dump_len)
u32 duration = 0, seg_len = 0; u32 duration = 0, seg_len = 0;
unsigned long start, end; unsigned long start, end;
if (buf && ((offset + seg_hdr_len) >
BNXT_COREDUMP_BUF_LEN(buf_len))) {
rc = -ENOBUFS;
goto err;
}
start = jiffies; start = jiffies;
rc = bnxt_hwrm_dbg_coredump_initiate(bp, comp_id, seg_id); rc = bnxt_hwrm_dbg_coredump_initiate(bp, comp_id, seg_id);
...@@ -3284,9 +3303,11 @@ static int bnxt_get_coredump(struct bnxt *bp, void *buf, u32 *dump_len) ...@@ -3284,9 +3303,11 @@ static int bnxt_get_coredump(struct bnxt *bp, void *buf, u32 *dump_len)
/* Write segment data into the buffer */ /* Write segment data into the buffer */
rc = bnxt_hwrm_dbg_coredump_retrieve(bp, comp_id, seg_id, rc = bnxt_hwrm_dbg_coredump_retrieve(bp, comp_id, seg_id,
&seg_len, buf, &seg_len, buf, buf_len,
offset + seg_hdr_len); offset + seg_hdr_len);
if (rc) if (rc && rc == -ENOBUFS)
goto err;
else if (rc)
netdev_err(bp->dev, netdev_err(bp->dev,
"Failed to retrieve coredump for seg = %d\n", "Failed to retrieve coredump for seg = %d\n",
seg_record->segment_id); seg_record->segment_id);
...@@ -3316,7 +3337,8 @@ static int bnxt_get_coredump(struct bnxt *bp, void *buf, u32 *dump_len) ...@@ -3316,7 +3337,8 @@ static int bnxt_get_coredump(struct bnxt *bp, void *buf, u32 *dump_len)
rc); rc);
kfree(coredump.data); kfree(coredump.data);
*dump_len += sizeof(struct bnxt_coredump_record); *dump_len += sizeof(struct bnxt_coredump_record);
if (rc == -ENOBUFS)
netdev_err(bp->dev, "Firmware returned large coredump buffer");
return rc; return rc;
} }
......
...@@ -31,6 +31,8 @@ struct bnxt_coredump { ...@@ -31,6 +31,8 @@ struct bnxt_coredump {
u16 total_segs; u16 total_segs;
}; };
#define BNXT_COREDUMP_BUF_LEN(len) ((len) - sizeof(struct bnxt_coredump_record))
struct bnxt_hwrm_dbg_dma_info { struct bnxt_hwrm_dbg_dma_info {
void *dest_buf; void *dest_buf;
int dest_buf_size; int dest_buf_size;
...@@ -38,6 +40,8 @@ struct bnxt_hwrm_dbg_dma_info { ...@@ -38,6 +40,8 @@ struct bnxt_hwrm_dbg_dma_info {
u16 seq_off; u16 seq_off;
u16 data_len_off; u16 data_len_off;
u16 segs; u16 segs;
u32 seg_start;
u32 buf_len;
}; };
struct hwrm_dbg_cmn_input { struct hwrm_dbg_cmn_input {
......
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