From 0095fe909e259525e093650cf799ceecf4ec3447 Mon Sep 17 00:00:00 2001 From: Ingrid Gallardo Date: Wed, 1 Mar 2017 12:24:06 -0800 Subject: [PATCH] msm: mdss: fix race condition in mdp debugfs Fix race condition in mdp debugfs properties during the read and write of the panel and mdp registers. This race condition can cause accessing memory out bounderies. Change-Id: I97a90a154237343d4aaf237c11f525bcc2c3a8e3 Signed-off-by: Ingrid Gallardo --- drivers/video/fbdev/msm/mdss_debug.c | 46 +++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/drivers/video/fbdev/msm/mdss_debug.c b/drivers/video/fbdev/msm/mdss_debug.c index 3e1dbba7c9ae..e60869144339 100644 --- a/drivers/video/fbdev/msm/mdss_debug.c +++ b/drivers/video/fbdev/msm/mdss_debug.c @@ -44,6 +44,8 @@ #define INVALID_XIN_ID 0xFF +static DEFINE_MUTEX(mdss_debug_lock); + static char panel_reg[2] = {DEFAULT_READ_PANEL_POWER_MODE_REG, 0x00}; static int panel_debug_base_open(struct inode *inode, struct file *file) @@ -93,8 +95,10 @@ static ssize_t panel_debug_base_offset_write(struct file *file, if (cnt > (dbg->max_offset - off)) cnt = dbg->max_offset - off; + mutex_lock(&mdss_debug_lock); dbg->off = off; dbg->cnt = cnt; + mutex_unlock(&mdss_debug_lock); pr_debug("offset=%x cnt=%d\n", off, cnt); @@ -114,15 +118,21 @@ static ssize_t panel_debug_base_offset_read(struct file *file, if (*ppos) return 0; /* the end */ + mutex_lock(&mdss_debug_lock); len = snprintf(buf, sizeof(buf), "0x%02zx %zx\n", dbg->off, dbg->cnt); - if (len < 0 || len >= sizeof(buf)) + if (len < 0 || len >= sizeof(buf)) { + mutex_unlock(&mdss_debug_lock); return 0; + } - if ((count < sizeof(buf)) || copy_to_user(buff, buf, len)) + if ((count < sizeof(buf)) || copy_to_user(buff, buf, len)) { + mutex_unlock(&mdss_debug_lock); return -EFAULT; + } *ppos += len; /* increase offset */ + mutex_unlock(&mdss_debug_lock); return len; } @@ -220,11 +230,16 @@ static ssize_t panel_debug_base_reg_read(struct file *file, if (!dbg) return -ENODEV; - if (!dbg->cnt) + mutex_lock(&mdss_debug_lock); + if (!dbg->cnt) { + mutex_unlock(&mdss_debug_lock); return 0; + } - if (*ppos) + if (*ppos) { + mutex_unlock(&mdss_debug_lock); return 0; /* the end */ + } /* '0x' + 2 digit + blank = 5 bytes for each number */ reg_buf_len = (dbg->cnt * PANEL_REG_FORMAT_LEN) @@ -265,11 +280,13 @@ static ssize_t panel_debug_base_reg_read(struct file *file, kfree(panel_reg_buf); *ppos += len; /* increase offset */ + mutex_unlock(&mdss_debug_lock); return len; read_reg_fail: kfree(rx_buf); kfree(panel_reg_buf); + mutex_unlock(&mdss_debug_lock); return rc; } @@ -403,8 +420,10 @@ static ssize_t mdss_debug_base_offset_write(struct file *file, if (cnt > (dbg->max_offset - off)) cnt = dbg->max_offset - off; + mutex_lock(&mdss_debug_lock); dbg->off = off; dbg->cnt = cnt; + mutex_unlock(&mdss_debug_lock); pr_debug("offset=%x cnt=%x\n", off, cnt); @@ -424,15 +443,21 @@ static ssize_t mdss_debug_base_offset_read(struct file *file, if (*ppos) return 0; /* the end */ + mutex_lock(&mdss_debug_lock); len = snprintf(buf, sizeof(buf), "0x%08zx %zx\n", dbg->off, dbg->cnt); - if (len < 0 || len >= sizeof(buf)) + if (len < 0 || len >= sizeof(buf)) { + mutex_unlock(&mdss_debug_lock); return 0; + } - if ((count < sizeof(buf)) || copy_to_user(buff, buf, len)) + if ((count < sizeof(buf)) || copy_to_user(buff, buf, len)) { + mutex_unlock(&mdss_debug_lock); return -EFAULT; + } *ppos += len; /* increase offset */ + mutex_unlock(&mdss_debug_lock); return len; } @@ -489,6 +514,8 @@ static ssize_t mdss_debug_base_reg_read(struct file *file, return -ENODEV; } + mutex_lock(&mdss_debug_lock); + if (!dbg->buf) { char dump_buf[64]; char *ptr; @@ -500,6 +527,7 @@ static ssize_t mdss_debug_base_reg_read(struct file *file, if (!dbg->buf) { pr_err("not enough memory to hold reg dump\n"); + mutex_unlock(&mdss_debug_lock); return -ENOMEM; } @@ -530,17 +558,21 @@ static ssize_t mdss_debug_base_reg_read(struct file *file, dbg->buf_len = tot; } - if (*ppos >= dbg->buf_len) + if (*ppos >= dbg->buf_len) { + mutex_unlock(&mdss_debug_lock); return 0; /* done reading */ + } len = min(count, dbg->buf_len - (size_t) *ppos); if (copy_to_user(user_buf, dbg->buf + *ppos, len)) { pr_err("failed to copy to user\n"); + mutex_unlock(&mdss_debug_lock); return -EFAULT; } *ppos += len; /* increase offset */ + mutex_unlock(&mdss_debug_lock); return len; }