mirror of
https://github.com/rd-stuffs/msm-4.14.git
synced 2025-02-20 11:45:48 +08:00
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:
parent
e391a5bf1f
commit
052f2231c9
@ -136,7 +136,7 @@ struct rdbg_device {
|
||||
|
||||
int registers[32] = {0};
|
||||
static struct rdbg_device g_rdbg_instance = {
|
||||
{ {0} },
|
||||
{},
|
||||
NULL,
|
||||
0,
|
||||
SMP2P_NUM_PROCS,
|
||||
|
@ -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),
|
||||
|
@ -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
|
||||
|
@ -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(
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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)
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user