| From 1309ecc90f16ee9cc3077761e7f4474369747e6e Mon Sep 17 00:00:00 2001 |
| From: Alexander Usyskin <alexander.usyskin@intel.com> |
| Date: Fri, 29 Jan 2021 14:07:46 +0200 |
| Subject: mei: fix transfer over dma with extended header |
| |
| From: Alexander Usyskin <alexander.usyskin@intel.com> |
| |
| commit 1309ecc90f16ee9cc3077761e7f4474369747e6e upstream. |
| |
| The size in header field for packet transferred over DMA |
| includes size of the extended header. |
| Include extended header in size check. |
| Add size and sanity checks on extended header. |
| |
| Cc: <stable@vger.kernel.org> # v5.10+ |
| Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com> |
| Signed-off-by: Tomas Winkler <tomas.winkler@intel.com> |
| Link: https://lore.kernel.org/r/20210129120752.850325-1-tomas.winkler@intel.com |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/misc/mei/interrupt.c | 33 ++++++++++++++++++++++++++++++--- |
| 1 file changed, 30 insertions(+), 3 deletions(-) |
| |
| --- a/drivers/misc/mei/interrupt.c |
| +++ b/drivers/misc/mei/interrupt.c |
| @@ -295,12 +295,17 @@ static inline bool hdr_is_fixed(struct m |
| static inline int hdr_is_valid(u32 msg_hdr) |
| { |
| struct mei_msg_hdr *mei_hdr; |
| + u32 expected_len = 0; |
| |
| mei_hdr = (struct mei_msg_hdr *)&msg_hdr; |
| if (!msg_hdr || mei_hdr->reserved) |
| return -EBADMSG; |
| |
| - if (mei_hdr->dma_ring && mei_hdr->length != MEI_SLOT_SIZE) |
| + if (mei_hdr->dma_ring) |
| + expected_len += MEI_SLOT_SIZE; |
| + if (mei_hdr->extended) |
| + expected_len += MEI_SLOT_SIZE; |
| + if (mei_hdr->length < expected_len) |
| return -EBADMSG; |
| |
| return 0; |
| @@ -324,6 +329,8 @@ int mei_irq_read_handler(struct mei_devi |
| struct mei_cl *cl; |
| int ret; |
| u32 ext_meta_hdr_u32; |
| + u32 hdr_size_left; |
| + u32 hdr_size_ext; |
| int i; |
| int ext_hdr_end; |
| |
| @@ -353,6 +360,7 @@ int mei_irq_read_handler(struct mei_devi |
| } |
| |
| ext_hdr_end = 1; |
| + hdr_size_left = mei_hdr->length; |
| |
| if (mei_hdr->extended) { |
| if (!dev->rd_msg_hdr[1]) { |
| @@ -363,8 +371,21 @@ int mei_irq_read_handler(struct mei_devi |
| dev_dbg(dev->dev, "extended header is %08x\n", |
| ext_meta_hdr_u32); |
| } |
| - meta_hdr = ((struct mei_ext_meta_hdr *) |
| - dev->rd_msg_hdr + 1); |
| + meta_hdr = ((struct mei_ext_meta_hdr *)dev->rd_msg_hdr + 1); |
| + if (check_add_overflow((u32)sizeof(*meta_hdr), |
| + mei_slots2data(meta_hdr->size), |
| + &hdr_size_ext)) { |
| + dev_err(dev->dev, "extended message size too big %d\n", |
| + meta_hdr->size); |
| + return -EBADMSG; |
| + } |
| + if (hdr_size_left < hdr_size_ext) { |
| + dev_err(dev->dev, "corrupted message header len %d\n", |
| + mei_hdr->length); |
| + return -EBADMSG; |
| + } |
| + hdr_size_left -= hdr_size_ext; |
| + |
| ext_hdr_end = meta_hdr->size + 2; |
| for (i = dev->rd_msg_hdr_count; i < ext_hdr_end; i++) { |
| dev->rd_msg_hdr[i] = mei_read_hdr(dev); |
| @@ -376,6 +397,12 @@ int mei_irq_read_handler(struct mei_devi |
| } |
| |
| if (mei_hdr->dma_ring) { |
| + if (hdr_size_left != sizeof(dev->rd_msg_hdr[ext_hdr_end])) { |
| + dev_err(dev->dev, "corrupted message header len %d\n", |
| + mei_hdr->length); |
| + return -EBADMSG; |
| + } |
| + |
| dev->rd_msg_hdr[ext_hdr_end] = mei_read_hdr(dev); |
| dev->rd_msg_hdr_count++; |
| (*slots)--; |