From 80decd6365deec08c35ecb902a58f9210599b39a Mon Sep 17 00:00:00 2001 From: ansharma Date: Fri, 20 Jan 2017 14:43:57 +0530 Subject: platform: msm: spmi: Fix possible race condition in debugfs There is a possible race condition when debugfs files are concurrently accessed by multiple threads. Fix this. CRs-Fixed: 1106842 Change-Id: Ifd092143f428db3cf73c45ec4f0aaa96318ae165 Signed-off-by: ansharma --- drivers/platform/msm/spmi/spmi-dbgfs.c | 37 +++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/drivers/platform/msm/spmi/spmi-dbgfs.c b/drivers/platform/msm/spmi/spmi-dbgfs.c index b0a354b..86f1b0d 100644 --- a/drivers/platform/msm/spmi/spmi-dbgfs.c +++ b/drivers/platform/msm/spmi/spmi-dbgfs.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014, 2017, 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 @@ -69,6 +69,7 @@ struct spmi_trans { u32 addr; /* 20-bit address: SID + PID + Register offset */ u32 offset; /* Offset of last read data */ bool raw_data; /* Set to true for raw data dump */ + struct mutex spmi_dfs_lock; /* Prevent thread concurrency */ struct spmi_controller *ctrl; struct spmi_log_buffer *log; /* log buffer */ }; @@ -168,6 +169,7 @@ static int spmi_dfs_open(struct spmi_ctrl_data *ctrl_data, struct file *file) trans->addr = ctrl_data->addr; trans->ctrl = ctrl_data->ctrl; trans->offset = trans->addr; + mutex_init(&trans->spmi_dfs_lock); file->private_data = trans; return 0; @@ -197,6 +199,7 @@ static int spmi_dfs_close(struct inode *inode, struct file *file) if (trans && trans->log) { file->private_data = NULL; + mutex_destroy(&trans->spmi_dfs_lock); kfree(trans->log); kfree(trans); } @@ -473,14 +476,21 @@ static ssize_t spmi_dfs_reg_write(struct file *file, const char __user *buf, int cnt = 0; u8 *values; size_t ret = 0; - + u32 offset; + char *kbuf; struct spmi_trans *trans = file->private_data; - u32 offset = trans->offset; + + mutex_lock(&trans->spmi_dfs_lock); + + trans = file->private_data; + offset = trans->offset; /* Make a copy of the user data */ - char *kbuf = kmalloc(count + 1, GFP_KERNEL); - if (!kbuf) - return -ENOMEM; + kbuf = kmalloc(count + 1, GFP_KERNEL); + if (!kbuf) { + ret = -ENOMEM; + goto unlock_mutex; + } ret = copy_from_user(kbuf, buf, count); if (ret == count) { @@ -517,6 +527,8 @@ static ssize_t spmi_dfs_reg_write(struct file *file, const char __user *buf, free_buf: kfree(kbuf); +unlock_mutex: + mutex_unlock(&trans->spmi_dfs_lock); return ret; } @@ -537,10 +549,13 @@ static ssize_t spmi_dfs_reg_read(struct file *file, char __user *buf, size_t ret; size_t len; + mutex_lock(&trans->spmi_dfs_lock); /* Is the the log buffer empty */ if (log->rpos >= log->wpos) { - if (get_log_data(trans) <= 0) - return 0; + if (get_log_data(trans) <= 0) { + len = 0; + goto unlock_mutex; + } } len = min(count, log->wpos - log->rpos); @@ -548,7 +563,8 @@ static ssize_t spmi_dfs_reg_read(struct file *file, char __user *buf, ret = copy_to_user(buf, &log->data[log->rpos], len); if (ret == len) { pr_err("error copy SPMI register values to user\n"); - return -EFAULT; + len = -EFAULT; + goto unlock_mutex; } /* 'ret' is the number of bytes not copied */ @@ -556,6 +572,9 @@ static ssize_t spmi_dfs_reg_read(struct file *file, char __user *buf, *ppos += len; log->rpos += len; + +unlock_mutex: + mutex_unlock(&trans->spmi_dfs_lock); return len; } -- cgit v1.1