From bc520b9e3e005be1c5925e058f571a76658bbcd8 Mon Sep 17 00:00:00 2001 From: Siba Prasad Date: Wed, 13 Sep 2017 20:43:57 +0530 Subject: [PATCH] mmc: core: Prevent accessing user space buffer directly In mmc_wr_pack_stats_read(), userspace buffer is directly accessed which is violating PAN (Privilege Access Never). So to prevent this, data which needs to be copied to user buffer is gathered into a local buffer and at the end, this local buffer contents are copied back to buffer supplied from user space using copy_to_user(). Change-Id: Id772613fe54c47d64906c18d3d0249eee2f6ac26 Signed-off-by: Siba Prasad --- drivers/mmc/core/debugfs.c | 53 ++++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index 72bfdd835178..26fa4a4d96b0 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -591,9 +591,10 @@ static ssize_t mmc_wr_pack_stats_read(struct file *filp, char __user *ubuf, { struct mmc_card *card = filp->private_data; struct mmc_wr_pack_stats *pack_stats; - int i; + int i, ret = 0; int max_num_of_packed_reqs = 0; - char *temp_buf; + char *temp_buf, *temp_ubuf; + size_t tubuf_cnt = 0; if (!card) return cnt; @@ -619,15 +620,24 @@ static ssize_t mmc_wr_pack_stats_read(struct file *filp, char __user *ubuf, max_num_of_packed_reqs = card->ext_csd.max_packed_writes; - temp_buf = kmalloc(TEMP_BUF_SIZE, GFP_KERNEL); + if (cnt <= (strlen_user(ubuf) + 1)) + goto exit; + + temp_buf = kzalloc(TEMP_BUF_SIZE, GFP_KERNEL); if (!temp_buf) goto exit; + tubuf_cnt = cnt - strlen_user(ubuf) - 1; + + temp_ubuf = kzalloc(tubuf_cnt, GFP_KERNEL); + if (!temp_ubuf) + goto cleanup; + spin_lock(&pack_stats->lock); snprintf(temp_buf, TEMP_BUF_SIZE, "%s: write packing statistics:\n", mmc_hostname(card->host)); - strlcat(ubuf, temp_buf, cnt); + strlcat(temp_ubuf, temp_buf, tubuf_cnt); for (i = 1 ; i <= max_num_of_packed_reqs ; ++i) { if (pack_stats->packing_events[i]) { @@ -635,63 +645,63 @@ static ssize_t mmc_wr_pack_stats_read(struct file *filp, char __user *ubuf, "%s: Packed %d reqs - %d times\n", mmc_hostname(card->host), i, pack_stats->packing_events[i]); - strlcat(ubuf, temp_buf, cnt); + strlcat(temp_ubuf, temp_buf, tubuf_cnt); } } snprintf(temp_buf, TEMP_BUF_SIZE, "%s: stopped packing due to the following reasons:\n", mmc_hostname(card->host)); - strlcat(ubuf, temp_buf, cnt); + strlcat(temp_ubuf, temp_buf, tubuf_cnt); if (pack_stats->pack_stop_reason[EXCEEDS_SEGMENTS]) { snprintf(temp_buf, TEMP_BUF_SIZE, "%s: %d times: exceed max num of segments\n", mmc_hostname(card->host), pack_stats->pack_stop_reason[EXCEEDS_SEGMENTS]); - strlcat(ubuf, temp_buf, cnt); + strlcat(temp_ubuf, temp_buf, tubuf_cnt); } if (pack_stats->pack_stop_reason[EXCEEDS_SECTORS]) { snprintf(temp_buf, TEMP_BUF_SIZE, "%s: %d times: exceed max num of sectors\n", mmc_hostname(card->host), pack_stats->pack_stop_reason[EXCEEDS_SECTORS]); - strlcat(ubuf, temp_buf, cnt); + strlcat(temp_ubuf, temp_buf, tubuf_cnt); } if (pack_stats->pack_stop_reason[WRONG_DATA_DIR]) { snprintf(temp_buf, TEMP_BUF_SIZE, "%s: %d times: wrong data direction\n", mmc_hostname(card->host), pack_stats->pack_stop_reason[WRONG_DATA_DIR]); - strlcat(ubuf, temp_buf, cnt); + strlcat(temp_ubuf, temp_buf, tubuf_cnt); } if (pack_stats->pack_stop_reason[FLUSH_OR_DISCARD]) { snprintf(temp_buf, TEMP_BUF_SIZE, "%s: %d times: flush or discard\n", mmc_hostname(card->host), pack_stats->pack_stop_reason[FLUSH_OR_DISCARD]); - strlcat(ubuf, temp_buf, cnt); + strlcat(temp_ubuf, temp_buf, tubuf_cnt); } if (pack_stats->pack_stop_reason[EMPTY_QUEUE]) { snprintf(temp_buf, TEMP_BUF_SIZE, "%s: %d times: empty queue\n", mmc_hostname(card->host), pack_stats->pack_stop_reason[EMPTY_QUEUE]); - strlcat(ubuf, temp_buf, cnt); + strlcat(temp_ubuf, temp_buf, tubuf_cnt); } if (pack_stats->pack_stop_reason[REL_WRITE]) { snprintf(temp_buf, TEMP_BUF_SIZE, "%s: %d times: rel write\n", mmc_hostname(card->host), pack_stats->pack_stop_reason[REL_WRITE]); - strlcat(ubuf, temp_buf, cnt); + strlcat(temp_ubuf, temp_buf, tubuf_cnt); } if (pack_stats->pack_stop_reason[THRESHOLD]) { snprintf(temp_buf, TEMP_BUF_SIZE, "%s: %d times: Threshold\n", mmc_hostname(card->host), pack_stats->pack_stop_reason[THRESHOLD]); - strlcat(ubuf, temp_buf, cnt); + strlcat(temp_ubuf, temp_buf, tubuf_cnt); } if (pack_stats->pack_stop_reason[LARGE_SEC_ALIGN]) { @@ -699,25 +709,36 @@ static ssize_t mmc_wr_pack_stats_read(struct file *filp, char __user *ubuf, "%s: %d times: Large sector alignment\n", mmc_hostname(card->host), pack_stats->pack_stop_reason[LARGE_SEC_ALIGN]); - strlcat(ubuf, temp_buf, cnt); + strlcat(temp_ubuf, temp_buf, tubuf_cnt); } if (pack_stats->pack_stop_reason[RANDOM]) { snprintf(temp_buf, TEMP_BUF_SIZE, "%s: %d times: random request\n", mmc_hostname(card->host), pack_stats->pack_stop_reason[RANDOM]); - strlcat(ubuf, temp_buf, cnt); + strlcat(temp_ubuf, temp_buf, tubuf_cnt); } if (pack_stats->pack_stop_reason[FUA]) { snprintf(temp_buf, TEMP_BUF_SIZE, "%s: %d times: fua request\n", mmc_hostname(card->host), pack_stats->pack_stop_reason[FUA]); - strlcat(ubuf, temp_buf, cnt); + strlcat(temp_ubuf, temp_buf, tubuf_cnt); } + if (strlen_user(ubuf) < cnt - strlen(temp_ubuf)) + ret = copy_to_user((ubuf + strlen_user(ubuf)), + temp_ubuf, tubuf_cnt); + else + ret = -EFAULT; + if (ret) + pr_err("%s: %s: Copy to userspace failed: %s\n", + mmc_hostname(card->host), __func__, ubuf); spin_unlock(&pack_stats->lock); + kfree(temp_ubuf); + +cleanup: kfree(temp_buf); pr_info("%s", ubuf);