diff options
| author | Sujeev Dias <sdias@codeaurora.org> | 2017-05-01 23:15:10 -0700 |
|---|---|---|
| committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2017-05-24 11:28:32 -0700 |
| commit | 632e3c71d32fe845d2051ccfee0eb3511a62908a (patch) | |
| tree | 732ebe6a27f8a36ffef45ba8adf5448174069aa7 /drivers/platform | |
| parent | 60be71604a84d2e047215cb702d6324379a353bb (diff) | |
mhi: core: fix potential buffer overflow
Fix a potential buffer overflow that could occur
during firmware download by storing buffer address
locally instead of inside MHI context.
CRs-Fixed: 1109397
Change-Id: If27ba602cdafdc8d25a94fdc0d74e8970bf0b0f4
Signed-off-by: Sujeev Dias <sdias@codeaurora.org>
Diffstat (limited to 'drivers/platform')
| -rw-r--r-- | drivers/platform/msm/mhi/mhi.h | 6 | ||||
| -rw-r--r-- | drivers/platform/msm/mhi/mhi_bhi.c | 85 |
2 files changed, 36 insertions, 55 deletions
diff --git a/drivers/platform/msm/mhi/mhi.h b/drivers/platform/msm/mhi/mhi.h index b4f3df4ec3d2..7b57c49f0d9e 100644 --- a/drivers/platform/msm/mhi/mhi.h +++ b/drivers/platform/msm/mhi/mhi.h @@ -82,12 +82,6 @@ struct bhie_vec_table { struct bhi_ctxt_t { void __iomem *bhi_base; - void *unaligned_image_loc; - dma_addr_t dma_handle; - size_t alloc_size; - void *image_loc; - dma_addr_t phy_image_loc; - size_t image_size; dev_t bhi_dev; struct cdev cdev; struct device *dev; diff --git a/drivers/platform/msm/mhi/mhi_bhi.c b/drivers/platform/msm/mhi/mhi_bhi.c index 3bc8205b5f0f..5b05270b1e66 100644 --- a/drivers/platform/msm/mhi/mhi_bhi.c +++ b/drivers/platform/msm/mhi/mhi_bhi.c @@ -109,30 +109,29 @@ alloc_bhi_mem_info_error: } static int bhi_alloc_pbl_xfer(struct mhi_device_ctxt *mhi_dev_ctxt, + struct bhie_mem_info *const mem_info, size_t size) { struct bhi_ctxt_t *bhi_ctxt = &mhi_dev_ctxt->bhi_ctxt; const phys_addr_t align_len = bhi_ctxt->alignment; - size_t alloc_size = size + (align_len - 1); struct device *dev = &mhi_dev_ctxt->plat_dev->dev; - bhi_ctxt->unaligned_image_loc = - dma_alloc_coherent(dev, alloc_size, &bhi_ctxt->dma_handle, - GFP_KERNEL); - if (bhi_ctxt->unaligned_image_loc == NULL) + mem_info->size = size; + mem_info->alloc_size = size + (align_len - 1); + mem_info->pre_aligned = + dma_alloc_coherent(dev, mem_info->alloc_size, + &mem_info->dma_handle, GFP_KERNEL); + if (mem_info->pre_aligned == NULL) return -ENOMEM; - bhi_ctxt->alloc_size = alloc_size; - bhi_ctxt->phy_image_loc = (bhi_ctxt->dma_handle + (align_len - 1)) & + mem_info->phys_addr = (mem_info->dma_handle + (align_len - 1)) & ~(align_len - 1); - bhi_ctxt->image_loc = bhi_ctxt->unaligned_image_loc + - (bhi_ctxt->phy_image_loc - bhi_ctxt->dma_handle); - bhi_ctxt->image_size = size; - + mem_info->aligned = mem_info->pre_aligned + (mem_info->phys_addr - + mem_info->dma_handle); mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "alloc_size:%lu image_size:%lu unal_addr:0x%llx0x al_addr:0x%llx\n", - bhi_ctxt->alloc_size, bhi_ctxt->image_size, - bhi_ctxt->dma_handle, bhi_ctxt->phy_image_loc); + mem_info->alloc_size, mem_info->size, + mem_info->dma_handle, mem_info->phys_addr); return 0; } @@ -264,7 +263,8 @@ int bhi_rddm(struct mhi_device_ctxt *mhi_dev_ctxt, bool in_panic) return -EINVAL; } -static int bhi_load_firmware(struct mhi_device_ctxt *mhi_dev_ctxt) +static int bhi_load_firmware(struct mhi_device_ctxt *mhi_dev_ctxt, + const struct bhie_mem_info *const mem_info) { struct bhi_ctxt_t *bhi_ctxt = &mhi_dev_ctxt->bhi_ctxt; u32 pcie_word_val = 0; @@ -278,28 +278,21 @@ static int bhi_load_firmware(struct mhi_device_ctxt *mhi_dev_ctxt) read_unlock_bh(pm_xfer_lock); return -EIO; } - pcie_word_val = HIGH_WORD(bhi_ctxt->phy_image_loc); - mhi_reg_write_field(mhi_dev_ctxt, bhi_ctxt->bhi_base, - BHI_IMGADDR_HIGH, - 0xFFFFFFFF, - 0, - pcie_word_val); + pcie_word_val = HIGH_WORD(mem_info->phys_addr); + mhi_reg_write_field(mhi_dev_ctxt, bhi_ctxt->bhi_base, BHI_IMGADDR_HIGH, + 0xFFFFFFFF, 0, pcie_word_val); - pcie_word_val = LOW_WORD(bhi_ctxt->phy_image_loc); + pcie_word_val = LOW_WORD(mem_info->phys_addr); + mhi_reg_write_field(mhi_dev_ctxt, bhi_ctxt->bhi_base, BHI_IMGADDR_LOW, + 0xFFFFFFFF, 0, pcie_word_val); - mhi_reg_write_field(mhi_dev_ctxt, bhi_ctxt->bhi_base, - BHI_IMGADDR_LOW, - 0xFFFFFFFF, - 0, - pcie_word_val); - - pcie_word_val = bhi_ctxt->image_size; + pcie_word_val = mem_info->size; mhi_reg_write_field(mhi_dev_ctxt, bhi_ctxt->bhi_base, BHI_IMGSIZE, - 0xFFFFFFFF, 0, pcie_word_val); + 0xFFFFFFFF, 0, pcie_word_val); pcie_word_val = mhi_reg_read(bhi_ctxt->bhi_base, BHI_IMGTXDB); mhi_reg_write_field(mhi_dev_ctxt, bhi_ctxt->bhi_base, - BHI_IMGTXDB, 0xFFFFFFFF, 0, ++pcie_word_val); + BHI_IMGTXDB, 0xFFFFFFFF, 0, ++pcie_word_val); read_unlock_bh(pm_xfer_lock); timeout = jiffies + msecs_to_jiffies(bhi_ctxt->poll_timeout); while (time_before(jiffies, timeout)) { @@ -342,6 +335,7 @@ static ssize_t bhi_write(struct file *file, int ret_val = 0; struct mhi_device_ctxt *mhi_dev_ctxt = file->private_data; struct bhi_ctxt_t *bhi_ctxt = &mhi_dev_ctxt->bhi_ctxt; + struct bhie_mem_info mem_info; long timeout; if (buf == NULL || 0 == count) @@ -350,11 +344,11 @@ static ssize_t bhi_write(struct file *file, if (count > BHI_MAX_IMAGE_SIZE) return -ENOMEM; - ret_val = bhi_alloc_pbl_xfer(mhi_dev_ctxt, count); + ret_val = bhi_alloc_pbl_xfer(mhi_dev_ctxt, &mem_info, count); if (ret_val) return -ENOMEM; - if (copy_from_user(bhi_ctxt->image_loc, buf, count)) { + if (copy_from_user(mem_info.aligned, buf, count)) { ret_val = -ENOMEM; goto bhi_copy_error; } @@ -370,15 +364,13 @@ static ssize_t bhi_write(struct file *file, goto bhi_copy_error; } - ret_val = bhi_load_firmware(mhi_dev_ctxt); + ret_val = bhi_load_firmware(mhi_dev_ctxt, &mem_info); if (ret_val) { mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Failed to load bhi image\n"); } - dma_free_coherent(&mhi_dev_ctxt->plat_dev->dev, - bhi_ctxt->alloc_size, - bhi_ctxt->unaligned_image_loc, - bhi_ctxt->dma_handle); + dma_free_coherent(&mhi_dev_ctxt->plat_dev->dev, mem_info.alloc_size, + mem_info.pre_aligned, mem_info.dma_handle); /* Regardless of failure set to RESET state */ ret_val = mhi_init_state_transition(mhi_dev_ctxt, @@ -390,10 +382,8 @@ static ssize_t bhi_write(struct file *file, return count; bhi_copy_error: - dma_free_coherent(&mhi_dev_ctxt->plat_dev->dev, - bhi_ctxt->alloc_size, - bhi_ctxt->unaligned_image_loc, - bhi_ctxt->dma_handle); + dma_free_coherent(&mhi_dev_ctxt->plat_dev->dev, mem_info.alloc_size, + mem_info.pre_aligned, mem_info.dma_handle); return ret_val; } @@ -447,6 +437,7 @@ void bhi_firmware_download(struct work_struct *work) { struct mhi_device_ctxt *mhi_dev_ctxt; struct bhi_ctxt_t *bhi_ctxt; + struct bhie_mem_info mem_info; int ret; long timeout; @@ -459,7 +450,10 @@ void bhi_firmware_download(struct work_struct *work) wait_event_interruptible(*mhi_dev_ctxt->mhi_ev_wq.bhi_event, mhi_dev_ctxt->mhi_state == MHI_STATE_BHI); - ret = bhi_load_firmware(mhi_dev_ctxt); + /* PBL image is the first segment in firmware vector table */ + mem_info = *bhi_ctxt->fw_table.bhie_mem_info; + mem_info.size = bhi_ctxt->firmware_info.max_sbl_len; + ret = bhi_load_firmware(mhi_dev_ctxt, &mem_info); if (ret) { mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Failed to Load sbl firmware\n"); @@ -547,13 +541,6 @@ int bhi_probe(struct mhi_device_ctxt *mhi_dev_ctxt) image += to_copy; } - /* - * Re-use BHI/E pointer for BHI since we guranteed BHI/E segment - * is >= to SBL image. - */ - bhi_ctxt->phy_image_loc = sg_dma_address(&fw_table->sg_list[1]); - bhi_ctxt->image_size = fw_info->max_sbl_len; - fw_table->sequence++; release_firmware(firmware); |
