summaryrefslogtreecommitdiff
path: root/drivers/platform
diff options
context:
space:
mode:
authorSujeev Dias <sdias@codeaurora.org>2017-05-01 23:15:10 -0700
committerGerrit - the friendly Code Review server <code-review@localhost>2017-05-24 11:28:32 -0700
commit632e3c71d32fe845d2051ccfee0eb3511a62908a (patch)
tree732ebe6a27f8a36ffef45ba8adf5448174069aa7 /drivers/platform
parent60be71604a84d2e047215cb702d6324379a353bb (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.h6
-rw-r--r--drivers/platform/msm/mhi/mhi_bhi.c85
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);