qcacld-3.0: Race condition while memdump read

There can be a race condition if two threads tries to execute
memdump read which may lead to use-after-free case.

To address this issue implement the use and free of the memory into
the lock.

Change-Id: Ie4d15e9a6414f556a622869d561c331c6bc5d85e
CRs-Fixed: 2023313
This commit is contained in:
Ashish Kumar Dhanotiya
2017-04-07 13:03:36 +05:30
committed by Sandeep Puligilla
parent 5591b487f4
commit 1f75a53ecc

View File

@@ -404,29 +404,36 @@ static ssize_t memdump_read(struct file *file, char __user *buf,
return -EINVAL; return -EINVAL;
} }
mutex_lock(&hdd_ctx->memdump_lock);
if (!hdd_ctx->memdump_in_progress) { if (!hdd_ctx->memdump_in_progress) {
hdd_err("Current mem dump request timed out/failed"); hdd_err("Current mem dump request timed out/failed");
return -EINVAL; status = -EINVAL;
goto memdump_read_fail;
} }
if (*pos < 0) { if (*pos < 0) {
hdd_err("Invalid start offset for memdump read"); hdd_err("Invalid start offset for memdump read");
return -EINVAL; status = -EINVAL;
goto memdump_read_fail;
} else if (*pos >= FW_MEM_DUMP_SIZE || !count) { } else if (*pos >= FW_MEM_DUMP_SIZE || !count) {
hdd_debug("No more data to copy"); hdd_debug("No more data to copy");
return 0; status = 0;
goto memdump_read_fail;
} else if (count > FW_MEM_DUMP_SIZE - *pos) { } else if (count > FW_MEM_DUMP_SIZE - *pos) {
count = FW_MEM_DUMP_SIZE - *pos; count = FW_MEM_DUMP_SIZE - *pos;
} }
if (!hdd_ctx->fw_dump_loc) { if (!hdd_ctx->fw_dump_loc) {
hdd_err("Invalid fw mem dump location"); hdd_err("Invalid fw mem dump location");
return -EINVAL; status = -EINVAL;
goto memdump_read_fail;
} }
if (copy_to_user(buf, hdd_ctx->fw_dump_loc + *pos, count)) { if (copy_to_user(buf, hdd_ctx->fw_dump_loc + *pos, count)) {
hdd_err("copy to user space failed"); hdd_err("copy to user space failed");
return -EFAULT; status = -EFAULT;
goto memdump_read_fail;
} }
/* offset(pos) should be updated here based on the copy done*/ /* offset(pos) should be updated here based on the copy done*/
@@ -435,7 +442,6 @@ static ssize_t memdump_read(struct file *file, char __user *buf,
/* Entire FW memory dump copy completed */ /* Entire FW memory dump copy completed */
if (*pos >= FW_MEM_DUMP_SIZE) { if (*pos >= FW_MEM_DUMP_SIZE) {
paddr = hdd_ctx->dump_loc_paddr; paddr = hdd_ctx->dump_loc_paddr;
mutex_lock(&hdd_ctx->memdump_lock);
qdf_mem_free_consistent(qdf_ctx, qdf_ctx->dev, qdf_mem_free_consistent(qdf_ctx, qdf_ctx->dev,
FW_MEM_DUMP_SIZE, hdd_ctx->fw_dump_loc, paddr, dma_ctx); FW_MEM_DUMP_SIZE, hdd_ctx->fw_dump_loc, paddr, dma_ctx);
hdd_ctx->fw_dump_loc = NULL; hdd_ctx->fw_dump_loc = NULL;
@@ -445,10 +451,12 @@ static ssize_t memdump_read(struct file *file, char __user *buf,
&hdd_ctx->memdump_cleanup_timer)) { &hdd_ctx->memdump_cleanup_timer)) {
qdf_mc_timer_stop(&hdd_ctx->memdump_cleanup_timer); qdf_mc_timer_stop(&hdd_ctx->memdump_cleanup_timer);
} }
mutex_unlock(&hdd_ctx->memdump_lock);
}
return count; }
status = count;
memdump_read_fail:
mutex_unlock(&hdd_ctx->memdump_lock);
return status;
} }
/** /**