| From c0cef7a615b4b22c834f83dfe5e99b93737bf0ef Mon Sep 17 00:00:00 2001 |
| From: Veera Sundaram Sankaran <veeras@codeaurora.org> |
| Date: Tue, 15 Mar 2016 18:42:27 -0700 |
| Subject: [PATCH] msm: mdss: fix possible out-of-bounds and overflow issue in |
| mdp debugfs |
| |
| There are few cases where the count argument passed by the user |
| space is not validated, which can potentially lead to out of bounds |
| or overflow issues. In some cases, kernel might copy more data than |
| what is requested. Add necessary checks to avoid such cases. |
| |
| Change-Id: Ifa42fbd475665a0ca581c907ce5432584ea0e7ed |
| Signed-off-by: Veera Sundaram Sankaran <veeras@codeaurora.org> |
| --- |
| drivers/video/msm/mdss/mdss_debug.c | 44 +++++++++++++++++++++---------------- |
| 1 file changed, 25 insertions(+), 19 deletions(-) |
| |
| diff --git a/drivers/video/msm/mdss/mdss_debug.c b/drivers/video/msm/mdss/mdss_debug.c |
| index 3b01bfc..e07aeeb 100644 |
| --- a/drivers/video/msm/mdss/mdss_debug.c |
| +++ b/drivers/video/msm/mdss/mdss_debug.c |
| @@ -1,4 +1,4 @@ |
| -/* Copyright (c) 2009-2015, The Linux Foundation. All rights reserved. |
| +/* Copyright (c) 2009-2016, The Linux Foundation. All rights reserved. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 and |
| @@ -109,10 +109,10 @@ static ssize_t panel_debug_base_offset_read(struct file *file, |
| return 0; /* the end */ |
| |
| len = snprintf(buf, sizeof(buf), "0x%02zx %zx\n", dbg->off, dbg->cnt); |
| - if (len < 0) |
| + if (len < 0 || len >= sizeof(buf)) |
| return 0; |
| |
| - if (copy_to_user(buff, buf, len)) |
| + if ((count < sizeof(buf)) || copy_to_user(buff, buf, len)) |
| return -EFAULT; |
| |
| *ppos += len; /* increase offset */ |
| @@ -231,10 +231,11 @@ static ssize_t panel_debug_base_reg_read(struct file *file, |
| if (mdata->debug_inf.debug_enable_clock) |
| mdata->debug_inf.debug_enable_clock(0); |
| |
| - if (len < 0) |
| + if (len < 0 || len >= sizeof(to_user_buf)) |
| return 0; |
| |
| - if (copy_to_user(user_buf, to_user_buf, len)) |
| + if ((count < sizeof(to_user_buf)) |
| + || copy_to_user(user_buf, to_user_buf, len)) |
| return -EFAULT; |
| |
| *ppos += len; /* increase offset */ |
| @@ -368,7 +369,7 @@ static ssize_t mdss_debug_base_offset_read(struct file *file, |
| { |
| struct mdss_debug_base *dbg = file->private_data; |
| int len = 0; |
| - char buf[24]; |
| + char buf[24] = {'\0'}; |
| |
| if (!dbg) |
| return -ENODEV; |
| @@ -377,10 +378,10 @@ static ssize_t mdss_debug_base_offset_read(struct file *file, |
| return 0; /* the end */ |
| |
| len = snprintf(buf, sizeof(buf), "0x%08zx %zx\n", dbg->off, dbg->cnt); |
| - if (len < 0) |
| + if (len < 0 || len >= sizeof(buf)) |
| return 0; |
| |
| - if (copy_to_user(buff, buf, len)) |
| + if ((count < sizeof(buf)) || copy_to_user(buff, buf, len)) |
| return -EFAULT; |
| |
| *ppos += len; /* increase offset */ |
| @@ -702,7 +703,7 @@ static ssize_t mdss_debug_factor_read(struct file *file, |
| { |
| struct mdss_fudge_factor *factor = file->private_data; |
| int len = 0; |
| - char buf[32]; |
| + char buf[32] = {'\0'}; |
| |
| if (!factor) |
| return -ENODEV; |
| @@ -712,10 +713,10 @@ static ssize_t mdss_debug_factor_read(struct file *file, |
| |
| len = snprintf(buf, sizeof(buf), "%d/%d\n", |
| factor->numer, factor->denom); |
| - if (len < 0) |
| + if (len < 0 || len >= sizeof(buf)) |
| return 0; |
| |
| - if (copy_to_user(buff, buf, len)) |
| + if ((count < sizeof(buf)) || copy_to_user(buff, buf, len)) |
| return -EFAULT; |
| |
| *ppos += len; /* increase offset */ |
| @@ -746,6 +747,8 @@ static ssize_t mdss_debug_perf_mode_write(struct file *file, |
| if (copy_from_user(buf, user_buf, count)) |
| return -EFAULT; |
| |
| + buf[count] = 0; /* end of string */ |
| + |
| if (sscanf(buf, "%d", &perf_mode) != 1) |
| return -EFAULT; |
| |
| @@ -766,7 +769,7 @@ static ssize_t mdss_debug_perf_mode_read(struct file *file, |
| { |
| struct mdss_perf_tune *perf_tune = file->private_data; |
| int len = 0; |
| - char buf[40]; |
| + char buf[40] = {'\0'}; |
| |
| if (!perf_tune) |
| return -ENODEV; |
| @@ -774,14 +777,12 @@ static ssize_t mdss_debug_perf_mode_read(struct file *file, |
| if (*ppos) |
| return 0; /* the end */ |
| |
| - buf[count] = 0; |
| - |
| len = snprintf(buf, sizeof(buf), "min_mdp_clk %lu min_bus_vote %llu\n", |
| perf_tune->min_mdp_clk, perf_tune->min_bus_vote); |
| - if (len < 0) |
| + if (len < 0 || len >= sizeof(buf)) |
| return 0; |
| |
| - if (copy_to_user(buff, buf, len)) |
| + if ((count < sizeof(buf)) || copy_to_user(buff, buf, len)) |
| return -EFAULT; |
| |
| *ppos += len; /* increase offset */ |
| @@ -801,7 +802,7 @@ static ssize_t mdss_debug_perf_panic_read(struct file *file, |
| { |
| struct mdss_data_type *mdata = file->private_data; |
| int len = 0; |
| - char buf[40]; |
| + char buf[40] = {'\0'}; |
| |
| if (!mdata) |
| return -ENODEV; |
| @@ -811,10 +812,10 @@ static ssize_t mdss_debug_perf_panic_read(struct file *file, |
| |
| len = snprintf(buf, sizeof(buf), "%d\n", |
| !mdata->has_panic_ctrl); |
| - if (len < 0) |
| + if (len < 0 || len >= sizeof(buf)) |
| return 0; |
| |
| - if (copy_to_user(buff, buf, len)) |
| + if ((count < sizeof(buf)) || copy_to_user(buff, buf, len)) |
| return -EFAULT; |
| |
| *ppos += len; /* increase offset */ |
| @@ -877,9 +878,14 @@ static ssize_t mdss_debug_perf_panic_write(struct file *file, |
| if (!mdata) |
| return -EFAULT; |
| |
| + if (count >= sizeof(buf)) |
| + return -EFAULT; |
| + |
| if (copy_from_user(buf, user_buf, count)) |
| return -EFAULT; |
| |
| + buf[count] = 0; /* end of string */ |
| + |
| if (sscanf(buf, "%d", &disable_panic) != 1) |
| return -EFAULT; |
| |
| -- |
| 1.8.2.1 |
| |