[PATCH 11/17] mpi3mr: Fix out-of-bounds read of event data
Chandrakanth Patil <[email protected]>
| Newsgroups | org.kernel.vger.linux-scsi |
|---|---|
| Message-ID | <[email protected]> |
The event data length from the reply is used as is, both when caching
log data and when sizing the buffer handed to the bottom half. A length
larger than the frame makes both of them read past the end of it.
Clamp the length to what the frame can hold.
Fixes: 13ef29ea4aa0 ("scsi: mpi3mr: Add support for device add/remove event handling")
Fixes: d0d19250ed81 ("scsi: mpi3mr: Rename log data save helper to reflect threaded/BH context")
Signed-off-by: Chandrakanth Patil <[email protected]>
---
drivers/scsi/mpi3mr/mpi3mr_os.c | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c
index 94625e5f6af8..6d4ddc78bcd0 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_os.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_os.c
@@ -3109,7 +3109,7 @@ void mpi3mr_add_event_wait_for_device_refresh(struct mpi3mr_ioc *mrioc)
void mpi3mr_os_handle_events(struct mpi3mr_ioc *mrioc,
struct mpi3_event_notification_reply *event_reply)
{
- u16 evt_type, sz;
+ u16 evt_type, sz, avail_reply_room;
struct mpi3mr_fwevt *fwevt = NULL;
bool ack_req = 0, process_evt_bh = 0;
@@ -3170,7 +3170,12 @@ void mpi3mr_os_handle_events(struct mpi3mr_ioc *mrioc,
case MPI3_EVENT_DEVICE_INFO_CHANGED:
case MPI3_EVENT_LOG_DATA:
- sz = event_reply->event_data_length * 4;
+ if (mrioc->reply_sz > offsetof(struct mpi3_event_notification_reply, event_data))
+ avail_reply_room = mrioc->reply_sz -
+ offsetof(struct mpi3_event_notification_reply, event_data);
+ else
+ avail_reply_room = 0;
+ sz = min_t(u16, event_reply->event_data_length * 4, avail_reply_room);
mpi3mr_app_save_logdata_th(mrioc,
(char *)event_reply->event_data, sz);
break;
@@ -3204,7 +3209,12 @@ void mpi3mr_os_handle_events(struct mpi3mr_ioc *mrioc,
dprint_event_th(mrioc,
"scheduling bottom half handler for event(0x%02x) - (0x%08x), ack_required=%d\n",
evt_type, le32_to_cpu(event_reply->event_context), ack_req);
- sz = event_reply->event_data_length * 4;
+ if (mrioc->reply_sz > offsetof(struct mpi3_event_notification_reply, event_data))
+ avail_reply_room = mrioc->reply_sz -
+ offsetof(struct mpi3_event_notification_reply, event_data);
+ else
+ avail_reply_room = 0;
+ sz = min_t(u16, event_reply->event_data_length * 4, avail_reply_room);
fwevt = mpi3mr_alloc_fwevt(sz);
if (!fwevt) {
dprint_event_th(mrioc,