Merge "mmc: core: Prevent accessing user space buffer directly"

This commit is contained in:
Linux Build Service Account 2017-10-23 05:47:58 -07:00 committed by Gerrit - the friendly Code Review server
commit 82e598b10a

View file

@ -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_card *card = filp->private_data;
struct mmc_wr_pack_stats *pack_stats; struct mmc_wr_pack_stats *pack_stats;
int i; int i, ret = 0;
int max_num_of_packed_reqs = 0; int max_num_of_packed_reqs = 0;
char *temp_buf; char *temp_buf, *temp_ubuf;
size_t tubuf_cnt = 0;
if (!card) if (!card)
return cnt; 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; 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) if (!temp_buf)
goto exit; 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); spin_lock(&pack_stats->lock);
snprintf(temp_buf, TEMP_BUF_SIZE, "%s: write packing statistics:\n", snprintf(temp_buf, TEMP_BUF_SIZE, "%s: write packing statistics:\n",
mmc_hostname(card->host)); 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) { for (i = 1 ; i <= max_num_of_packed_reqs ; ++i) {
if (pack_stats->packing_events[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", "%s: Packed %d reqs - %d times\n",
mmc_hostname(card->host), i, mmc_hostname(card->host), i,
pack_stats->packing_events[i]); pack_stats->packing_events[i]);
strlcat(ubuf, temp_buf, cnt); strlcat(temp_ubuf, temp_buf, tubuf_cnt);
} }
} }
snprintf(temp_buf, TEMP_BUF_SIZE, snprintf(temp_buf, TEMP_BUF_SIZE,
"%s: stopped packing due to the following reasons:\n", "%s: stopped packing due to the following reasons:\n",
mmc_hostname(card->host)); mmc_hostname(card->host));
strlcat(ubuf, temp_buf, cnt); strlcat(temp_ubuf, temp_buf, tubuf_cnt);
if (pack_stats->pack_stop_reason[EXCEEDS_SEGMENTS]) { if (pack_stats->pack_stop_reason[EXCEEDS_SEGMENTS]) {
snprintf(temp_buf, TEMP_BUF_SIZE, snprintf(temp_buf, TEMP_BUF_SIZE,
"%s: %d times: exceed max num of segments\n", "%s: %d times: exceed max num of segments\n",
mmc_hostname(card->host), mmc_hostname(card->host),
pack_stats->pack_stop_reason[EXCEEDS_SEGMENTS]); 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]) { if (pack_stats->pack_stop_reason[EXCEEDS_SECTORS]) {
snprintf(temp_buf, TEMP_BUF_SIZE, snprintf(temp_buf, TEMP_BUF_SIZE,
"%s: %d times: exceed max num of sectors\n", "%s: %d times: exceed max num of sectors\n",
mmc_hostname(card->host), mmc_hostname(card->host),
pack_stats->pack_stop_reason[EXCEEDS_SECTORS]); 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]) { if (pack_stats->pack_stop_reason[WRONG_DATA_DIR]) {
snprintf(temp_buf, TEMP_BUF_SIZE, snprintf(temp_buf, TEMP_BUF_SIZE,
"%s: %d times: wrong data direction\n", "%s: %d times: wrong data direction\n",
mmc_hostname(card->host), mmc_hostname(card->host),
pack_stats->pack_stop_reason[WRONG_DATA_DIR]); 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]) { if (pack_stats->pack_stop_reason[FLUSH_OR_DISCARD]) {
snprintf(temp_buf, TEMP_BUF_SIZE, snprintf(temp_buf, TEMP_BUF_SIZE,
"%s: %d times: flush or discard\n", "%s: %d times: flush or discard\n",
mmc_hostname(card->host), mmc_hostname(card->host),
pack_stats->pack_stop_reason[FLUSH_OR_DISCARD]); 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]) { if (pack_stats->pack_stop_reason[EMPTY_QUEUE]) {
snprintf(temp_buf, TEMP_BUF_SIZE, snprintf(temp_buf, TEMP_BUF_SIZE,
"%s: %d times: empty queue\n", "%s: %d times: empty queue\n",
mmc_hostname(card->host), mmc_hostname(card->host),
pack_stats->pack_stop_reason[EMPTY_QUEUE]); 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]) { if (pack_stats->pack_stop_reason[REL_WRITE]) {
snprintf(temp_buf, TEMP_BUF_SIZE, snprintf(temp_buf, TEMP_BUF_SIZE,
"%s: %d times: rel write\n", "%s: %d times: rel write\n",
mmc_hostname(card->host), mmc_hostname(card->host),
pack_stats->pack_stop_reason[REL_WRITE]); 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]) { if (pack_stats->pack_stop_reason[THRESHOLD]) {
snprintf(temp_buf, TEMP_BUF_SIZE, snprintf(temp_buf, TEMP_BUF_SIZE,
"%s: %d times: Threshold\n", "%s: %d times: Threshold\n",
mmc_hostname(card->host), mmc_hostname(card->host),
pack_stats->pack_stop_reason[THRESHOLD]); 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]) { 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", "%s: %d times: Large sector alignment\n",
mmc_hostname(card->host), mmc_hostname(card->host),
pack_stats->pack_stop_reason[LARGE_SEC_ALIGN]); 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]) { if (pack_stats->pack_stop_reason[RANDOM]) {
snprintf(temp_buf, TEMP_BUF_SIZE, snprintf(temp_buf, TEMP_BUF_SIZE,
"%s: %d times: random request\n", "%s: %d times: random request\n",
mmc_hostname(card->host), mmc_hostname(card->host),
pack_stats->pack_stop_reason[RANDOM]); 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]) { if (pack_stats->pack_stop_reason[FUA]) {
snprintf(temp_buf, TEMP_BUF_SIZE, snprintf(temp_buf, TEMP_BUF_SIZE,
"%s: %d times: fua request\n", "%s: %d times: fua request\n",
mmc_hostname(card->host), mmc_hostname(card->host),
pack_stats->pack_stop_reason[FUA]); 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); spin_unlock(&pack_stats->lock);
kfree(temp_ubuf);
cleanup:
kfree(temp_buf); kfree(temp_buf);
pr_info("%s", ubuf); pr_info("%s", ubuf);