msm: ipa: Correctly allocate memory for copy_from_user

Copying from user to a global variable inside the driver is
unsafe and insecure: allocate and free the memory used for
copying from userspace in the functions doing it.

This also has the good side effect of solving a build failure
when the kernel is built with GCC >=4.9

Change-Id: I04bfb0cd0ffb6870481f639818cf8c51191d927d
Signed-off-by: Yaroslav Furman <yaro330@gmail.com>
Signed-off-by: Panchajanya1999 <panchajanya@azure-dev.live>
(cherry picked from commit 82ac0e2a920a906defba2fe57185728971a914b8)
Signed-off-by: Forenche <prahul2003@gmail.com>
This commit is contained in:
Angelo G. Del Regno 2019-06-06 10:34:58 +02:00 committed by Forenche
parent e391a5bf1f
commit 052f2231c9
No known key found for this signature in database
GPG Key ID: 1337D655BAFE85E2
9 changed files with 110 additions and 41 deletions

View File

@ -136,7 +136,7 @@ struct rdbg_device {
int registers[32] = {0};
static struct rdbg_device g_rdbg_instance = {
{ {0} },
{},
NULL,
0,
SMP2P_NUM_PROCS,

View File

@ -111,6 +111,32 @@ static bool running_emulation;
static enum ipa_hw_type ipa_api_hw_type;
static struct ipa_api_controller *ipa_api_ctrl;
#define MAX_CPY_BUFF_SZ 4096
unsigned long
ipa_safe_copy_from_user(char *dst, const char __user *buf, size_t count)
{
unsigned long missing = 0;
char *from_user = NULL;
int sz;
if (MAX_CPY_BUFF_SZ < count + 1)
return ULONG_MAX;
sz = count * sizeof(char);
from_user = kmalloc(sz + 1, GFP_KERNEL);
if (!from_user)
return ULONG_MAX;
missing = copy_from_user(from_user, buf, count);
if (missing)
goto end;
memcpy(dst, from_user, sz);
end:
kfree(from_user);
return missing;
}
const char *ipa_clients_strings[IPA_CLIENT_MAX] = {
__stringify(IPA_CLIENT_HSIC1_PROD),
__stringify(IPA_CLIENT_HSIC1_CONS),

View File

@ -159,7 +159,7 @@ static struct odu_bridge_ctx *odu_bridge_ctx;
#ifdef CONFIG_DEBUG_FS
#define ODU_MAX_MSG_LEN 512
static char dbg_buff[ODU_MAX_MSG_LEN];
static char *dbg_buff;
#endif
static void odu_bridge_emb_cons_cb(void *priv, enum ipa_dp_evt_type evt,
@ -710,10 +710,10 @@ static ssize_t odu_debugfs_hw_bridge_mode_write(struct file *file,
unsigned long missing;
enum odu_bridge_mode mode;
if (sizeof(dbg_buff) < count + 1)
if (ODU_MAX_MSG_LEN < count + 1)
return -EFAULT;
missing = copy_from_user(dbg_buff, ubuf, min(sizeof(dbg_buff), count));
missing = ipa_safe_copy_from_user(dbg_buff, ubuf, count);
if (missing)
return -EFAULT;
@ -783,6 +783,10 @@ static void odu_debugfs_init(void)
return;
}
dbg_buff = kmalloc(ODU_MAX_MSG_LEN * sizeof(char), GFP_KERNEL);
if (!dbg_buff)
return;
dfile_stats =
debugfs_create_file("stats", read_only_mode, dent,
0, &odu_stats_ops);
@ -802,12 +806,14 @@ static void odu_debugfs_init(void)
return;
fail:
kfree(dbg_buff);
debugfs_remove_recursive(dent);
}
static void odu_debugfs_destroy(void)
{
debugfs_remove_recursive(dent);
kfree(dbg_buff);
}
#else

View File

@ -353,6 +353,9 @@ extern const char *ipa_clients_strings[];
## args); \
} while (0)
unsigned long
ipa_safe_copy_from_user(char *dst, const char __user *buf, size_t count);
void ipa_inc_client_enable_clks(struct ipa_active_client_logging_info *id);
void ipa_dec_client_disable_clks(struct ipa_active_client_logging_info *id);
int ipa_inc_client_enable_clks_no_block(

View File

@ -6691,19 +6691,24 @@ static ssize_t ipa3_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
unsigned long missing;
char dbg_buff[32] = { 0 };
char *dbg_buff = NULL;
int ret = 0;
int i = 0;
if (sizeof(dbg_buff) < count + 1)
if (count < 2)
return -EFAULT;
missing = copy_from_user(dbg_buff, buf, min(sizeof(dbg_buff), count));
dbg_buff = kmalloc((count + 1) * sizeof(char), GFP_KERNEL);
if (!dbg_buff)
return -ENOMEM;
missing = copy_from_user(dbg_buff, buf, count);
if (missing) {
IPAERR("Unable to copy data from user\n");
return -EFAULT;
ret = -EFAULT;
goto end;
}
if (count > 0)
@ -6720,7 +6725,7 @@ static ssize_t ipa3_write(struct file *file, const char __user *buf,
if (i == count) {
IPADBG("Empty ipa_config file\n");
return count;
goto end_msg;
}
/* Check MHI configuration on MDM devices */
@ -6751,7 +6756,7 @@ static ssize_t ipa3_write(struct file *file, const char __user *buf,
ipa3_ctx->vlan_mode_iface[IPA_VLAN_IF_RNDIS]);
IPAERR("ecm vlan(%d)\n",
ipa3_ctx->vlan_mode_iface[IPA_VLAN_IF_ECM]);
return count;
goto end_msg;
}
/* trim ending newline character if any */
@ -6768,7 +6773,7 @@ static ssize_t ipa3_write(struct file *file, const char __user *buf,
} else if (strcmp(dbg_buff, "1")) {
IPAERR("got invalid string %s not loading FW\n",
dbg_buff);
return count;
goto end_msg;
}
pr_info("IPA is loading with %sMHI configuration\n",
ipa3_ctx->ipa_config_is_mhi ? "" : "non ");
@ -6776,12 +6781,12 @@ static ssize_t ipa3_write(struct file *file, const char __user *buf,
/* Prevent consequent calls from trying to load the FW again. */
if (ipa3_is_ready())
return count;
goto end_msg;
/* Prevent multiple calls from trying to load the FW again. */
if (ipa3_ctx->fw_loaded) {
IPAERR("not load FW again\n");
return count;
goto end_msg;
}
/* Schedule WQ to load ipa-fws */
@ -6790,8 +6795,11 @@ static ssize_t ipa3_write(struct file *file, const char __user *buf,
queue_work(ipa3_ctx->transport_power_mgmt_wq,
&ipa3_fw_loading_work);
end_msg:
IPADBG("Scheduled a work to load IPA FW\n");
return count;
end:
kfree(dbg_buff);
return ret < 0 ? ret : count;
}
/**

View File

@ -113,14 +113,15 @@ const char *ipa3_hdr_proc_type_name[] = {
__stringify(IPA_HDR_PROC_SET_DSCP),
};
#define MAX_DBG_BUFF_SZ 4096
static struct dentry *dent;
static char dbg_buff[IPA_MAX_MSG_LEN + 1];
static char *dbg_buff;
static char *active_clients_buf;
static s8 ep_reg_idx;
static void *ipa_ipc_low_buff;
static ssize_t ipa3_read_gen_reg(struct file *file, char __user *ubuf,
size_t count, loff_t *ppos)
{
@ -165,10 +166,10 @@ static ssize_t ipa3_write_ep_holb(struct file *file,
unsigned long missing;
char *sptr, *token;
if (sizeof(dbg_buff) < count + 1)
if (MAX_DBG_BUFF_SZ < count + 1)
return -EFAULT;
missing = copy_from_user(dbg_buff, buf, min(sizeof(dbg_buff), count));
missing = ipa_safe_copy_from_user(dbg_buff, buf, count);
if (missing)
return -EFAULT;
@ -208,10 +209,10 @@ static ssize_t ipa3_write_ep_reg(struct file *file, const char __user *buf,
unsigned long missing;
s8 option = 0;
if (sizeof(dbg_buff) < count + 1)
if (MAX_DBG_BUFF_SZ < count + 1)
return -EFAULT;
missing = copy_from_user(dbg_buff, buf, min(sizeof(dbg_buff), count));
missing = ipa_safe_copy_from_user(dbg_buff, buf, count);
if (missing)
return -EFAULT;
@ -346,10 +347,10 @@ static ssize_t ipa3_write_keep_awake(struct file *file, const char __user *buf,
unsigned long missing;
s8 option = 0;
if (sizeof(dbg_buff) < count + 1)
if (MAX_DBG_BUFF_SZ < count + 1)
return -EFAULT;
missing = copy_from_user(dbg_buff, buf, min(sizeof(dbg_buff), count));
missing = ipa_safe_copy_from_user(dbg_buff, buf, count);
if (missing)
return -EFAULT;
@ -1600,10 +1601,10 @@ static ssize_t ipa3_write_dbg_cnt(struct file *file, const char __user *buf,
return -EPERM;
}
if (sizeof(dbg_buff) < count + 1)
if (MAX_DBG_BUFF_SZ < count + 1)
return -EFAULT;
missing = copy_from_user(dbg_buff, buf, min(sizeof(dbg_buff), count));
missing = ipa_safe_copy_from_user(dbg_buff, buf, count);
if (missing)
return -EFAULT;
@ -2602,10 +2603,10 @@ static ssize_t ipa3_clear_active_clients_log(struct file *file,
unsigned long missing;
s8 option = 0;
if (sizeof(dbg_buff) < count + 1)
if (MAX_DBG_BUFF_SZ < count + 1)
return -EFAULT;
missing = copy_from_user(dbg_buff, ubuf, min(sizeof(dbg_buff), count));
missing = ipa_safe_copy_from_user(dbg_buff, ubuf, count);
if (missing)
return -EFAULT;
@ -2624,10 +2625,10 @@ static ssize_t ipa3_enable_ipc_low(struct file *file,
unsigned long missing;
s8 option = 0;
if (sizeof(dbg_buff) < count + 1)
if (MAX_DBG_BUFF_SZ < count + 1)
return -EFAULT;
missing = copy_from_user(dbg_buff, ubuf, min(sizeof(dbg_buff), count));
missing = ipa_safe_copy_from_user(dbg_buff, ubuf, count);
if (missing)
return -EFAULT;
@ -2965,6 +2966,10 @@ void ipa3_debugfs_post_init(void)
return;
}
dbg_buff = kmalloc(MAX_DBG_BUFF_SZ * sizeof(char), GFP_KERNEL);
if (!dbg_buff)
return;
file = debugfs_create_u32("hw_type", IPA_READ_ONLY_MODE,
dent, &ipa3_ctx->ipa_hw_type);
if (!file) {
@ -3033,6 +3038,7 @@ void ipa3_debugfs_post_init(void)
return;
fail:
kfree(dbg_buff);
debugfs_remove_recursive(dent);
}
@ -3047,6 +3053,9 @@ void ipa3_debugfs_remove(void)
active_clients_buf = NULL;
}
debugfs_remove_recursive(dent);
kfree(dbg_buff);
ipa_debugfs_remove_stats();
}
struct dentry *ipa_debugfs_get_root(void)

View File

@ -67,7 +67,7 @@
#ifdef CONFIG_DEBUG_FS
#define IPADMA_MAX_MSG_LEN 1024
static char dbg_buff[IPADMA_MAX_MSG_LEN];
static char *dbg_buff;
static void ipa3_dma_debugfs_init(void);
static void ipa3_dma_debugfs_destroy(void);
#else
@ -1196,10 +1196,10 @@ static ssize_t ipa3_dma_debugfs_reset_statistics(struct file *file,
unsigned long missing;
s8 in_num = 0;
if (sizeof(dbg_buff) < count + 1)
if (IPADMA_MAX_MSG_LEN < count + 1)
return -EFAULT;
missing = copy_from_user(dbg_buff, ubuf, min(sizeof(dbg_buff), count));
missing = ipa_safe_copy_from_user(dbg_buff, ubuf, count);
if (missing)
return -EFAULT;
@ -1236,6 +1236,10 @@ static void ipa3_dma_debugfs_init(void)
return;
}
dbg_buff = kmalloc(IPADMA_MAX_MSG_LEN * sizeof(char), GFP_KERNEL);
if (!dbg_buff)
return;
dfile_info =
debugfs_create_file("info", read_write_mode, dent,
0, &ipa3_ipadma_stats_ops);
@ -1245,12 +1249,14 @@ static void ipa3_dma_debugfs_init(void)
}
return;
fail:
kfree(dbg_buff);
debugfs_remove_recursive(dent);
}
static void ipa3_dma_debugfs_destroy(void)
{
debugfs_remove_recursive(dent);
kfree(dbg_buff);
}
#endif /* !CONFIG_DEBUG_FS */

View File

@ -1618,7 +1618,7 @@ int ipa_reset_all_drop_stats(void)
int ipa_debugfs_init_stats(struct dentry *parent) { return 0; }
#else
#define IPA_MAX_MSG_LEN 4096
static char dbg_buff[IPA_MAX_MSG_LEN];
static char *dbg_buff;
static ssize_t ipa_debugfs_reset_quota_stats(struct file *file,
const char __user *ubuf, size_t count, loff_t *ppos)
@ -1628,12 +1628,12 @@ static ssize_t ipa_debugfs_reset_quota_stats(struct file *file,
int ret;
mutex_lock(&ipa3_ctx->lock);
if (sizeof(dbg_buff) < count + 1) {
if (IPA_MAX_MSG_LEN < count + 1) {
ret = -EFAULT;
goto bail;
}
missing = copy_from_user(dbg_buff, ubuf, min(sizeof(dbg_buff), count));
missing = ipa_safe_copy_from_user(dbg_buff, ubuf, count);
if (missing) {
ret = -EFAULT;
goto bail;
@ -1727,12 +1727,12 @@ static ssize_t ipa_debugfs_reset_tethering_stats(struct file *file,
int ret;
mutex_lock(&ipa3_ctx->lock);
if (sizeof(dbg_buff) < count + 1) {
if (IPA_MAX_MSG_LEN < count + 1) {
ret = -EFAULT;
goto bail;
}
missing = copy_from_user(dbg_buff, ubuf, min(sizeof(dbg_buff), count));
missing = ipa_safe_copy_from_user(dbg_buff, ubuf, count);
if (missing) {
ret = -EFAULT;
goto bail;
@ -1861,12 +1861,12 @@ static ssize_t ipa_debugfs_control_flt_rt_stats(struct file *file,
}
mutex_lock(&ipa3_ctx->lock);
if (sizeof(dbg_buff) < count + 1) {
if (IPA_MAX_MSG_LEN < count + 1) {
ret = -EFAULT;
goto bail;
}
missing = copy_from_user(dbg_buff, ubuf, min(sizeof(dbg_buff), count));
missing = ipa_safe_copy_from_user(dbg_buff, ubuf, count);
if (missing) {
ret = -EFAULT;
goto bail;
@ -1962,12 +1962,12 @@ static ssize_t ipa_debugfs_reset_drop_stats(struct file *file,
int ret;
mutex_lock(&ipa3_ctx->lock);
if (sizeof(dbg_buff) < count + 1) {
if (IPA_MAX_MSG_LEN < count + 1) {
ret = -EFAULT;
goto bail;
}
missing = copy_from_user(dbg_buff, ubuf, min(sizeof(dbg_buff), count));
missing = ipa_safe_copy_from_user(dbg_buff, ubuf, count);
if (missing) {
ret = -EFAULT;
goto bail;
@ -2166,6 +2166,10 @@ int ipa_debugfs_init_stats(struct dentry *parent)
return -EFAULT;
}
dbg_buff = kmalloc(IPA_MAX_MSG_LEN * sizeof(char), GFP_KERNEL);
if (!dbg_buff)
return -ENOMEM;
file = debugfs_create_file("quota", read_write_mode, dent, NULL,
&ipa3_quota_ops);
if (IS_ERR_OR_NULL(file)) {
@ -2204,6 +2208,12 @@ int ipa_debugfs_init_stats(struct dentry *parent)
return 0;
fail:
debugfs_remove_recursive(dent);
kfree(dbg_buff);
return -EFAULT;
}
void ipa_debugfs_remove_stats(void)
{
kfree(dbg_buff);
}
#endif

View File

@ -3039,6 +3039,7 @@ int ipa_hw_stats_init(void);
int ipa_init_flt_rt_stats(void);
int ipa_debugfs_init_stats(struct dentry *parent);
void ipa_debugfs_remove_stats(void);
int ipa_init_quota_stats(u32 pipe_bitmask);