DivestOS/Patches/Linux_CVEs/CVE-2016-3867/3.10/0001.patch
2017-11-07 17:32:46 -05:00

506 lines
16 KiB
Diff

From 816da3d19cfee937f5add485a112bb1cdfcb72c8 Mon Sep 17 00:00:00 2001
From: Skylar Chang <chiaweic@codeaurora.org>
Date: Fri, 8 Jul 2016 16:20:33 -0700
Subject: msm: ipa: fix potential race condition ioctls
There are numerous potential race condition
ioctls in the IPA driver. The fix is to add
check wherever it copies arguments from
user-space memory and process.
Change-Id: I5a440f89153518507acdf5dad42625503732e59a
Signed-off-by: Skylar Chang <chiaweic@codeaurora.org>
---
drivers/platform/msm/ipa/ipa.c | 236 ++++++++++++++++++++++++++++++++++-------
1 file changed, 196 insertions(+), 40 deletions(-)
diff --git a/drivers/platform/msm/ipa/ipa.c b/drivers/platform/msm/ipa/ipa.c
index adce191..5cfbbc9 100644
--- a/drivers/platform/msm/ipa/ipa.c
+++ b/drivers/platform/msm/ipa/ipa.c
@@ -390,6 +390,7 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
struct ipa_ioc_v4_nat_del nat_del;
struct ipa_ioc_rm_dependency rm_depend;
size_t sz;
+ int pre_entry;
IPADBG("cmd=%x nr=%d\n", cmd, _IOC_NR(cmd));
@@ -438,11 +439,11 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
-
+ pre_entry =
+ ((struct ipa_ioc_nat_dma_cmd *)header)->entries;
pyld_sz =
sizeof(struct ipa_ioc_nat_dma_cmd) +
- ((struct ipa_ioc_nat_dma_cmd *)header)->entries *
- sizeof(struct ipa_ioc_nat_dma_one);
+ pre_entry * sizeof(struct ipa_ioc_nat_dma_one);
param = kzalloc(pyld_sz, GFP_KERNEL);
if (!param) {
retval = -ENOMEM;
@@ -453,7 +454,15 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
-
+ /* add check in case user-space module compromised */
+ if (unlikely(((struct ipa_ioc_nat_dma_cmd *)param)->entries
+ != pre_entry)) {
+ IPAERR("current %d pre %d\n",
+ ((struct ipa_ioc_nat_dma_cmd *)param)->entries,
+ pre_entry);
+ retval = -EFAULT;
+ break;
+ }
if (ipa_nat_dma_cmd((struct ipa_ioc_nat_dma_cmd *)param)) {
retval = -EFAULT;
break;
@@ -478,10 +487,11 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
+ pre_entry =
+ ((struct ipa_ioc_add_hdr *)header)->num_hdrs;
pyld_sz =
sizeof(struct ipa_ioc_add_hdr) +
- ((struct ipa_ioc_add_hdr *)header)->num_hdrs *
- sizeof(struct ipa_hdr_add);
+ pre_entry * sizeof(struct ipa_hdr_add);
param = kzalloc(pyld_sz, GFP_KERNEL);
if (!param) {
retval = -ENOMEM;
@@ -491,6 +501,15 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
+ /* add check in case user-space module compromised */
+ if (unlikely(((struct ipa_ioc_add_hdr *)param)->num_hdrs
+ != pre_entry)) {
+ IPAERR("current %d pre %d\n",
+ ((struct ipa_ioc_add_hdr *)param)->num_hdrs,
+ pre_entry);
+ retval = -EFAULT;
+ break;
+ }
if (ipa_add_hdr((struct ipa_ioc_add_hdr *)param)) {
retval = -EFAULT;
break;
@@ -507,10 +526,11 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
+ pre_entry =
+ ((struct ipa_ioc_del_hdr *)header)->num_hdls;
pyld_sz =
sizeof(struct ipa_ioc_del_hdr) +
- ((struct ipa_ioc_del_hdr *)header)->num_hdls *
- sizeof(struct ipa_hdr_del);
+ pre_entry * sizeof(struct ipa_hdr_del);
param = kzalloc(pyld_sz, GFP_KERNEL);
if (!param) {
retval = -ENOMEM;
@@ -520,6 +540,15 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
+ /* add check in case user-space module compromised */
+ if (unlikely(((struct ipa_ioc_del_hdr *)param)->num_hdls
+ != pre_entry)) {
+ IPAERR("current %d pre %d\n",
+ ((struct ipa_ioc_del_hdr *)param)->num_hdls,
+ pre_entry);
+ retval = -EFAULT;
+ break;
+ }
if (ipa_del_hdr((struct ipa_ioc_del_hdr *)param)) {
retval = -EFAULT;
break;
@@ -536,10 +565,11 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
+ pre_entry =
+ ((struct ipa_ioc_add_rt_rule *)header)->num_rules;
pyld_sz =
sizeof(struct ipa_ioc_add_rt_rule) +
- ((struct ipa_ioc_add_rt_rule *)header)->num_rules *
- sizeof(struct ipa_rt_rule_add);
+ pre_entry * sizeof(struct ipa_rt_rule_add);
param = kzalloc(pyld_sz, GFP_KERNEL);
if (!param) {
retval = -ENOMEM;
@@ -549,6 +579,16 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
+ /* add check in case user-space module compromised */
+ if (unlikely(((struct ipa_ioc_add_rt_rule *)param)->num_rules
+ != pre_entry)) {
+ IPAERR("current %d pre %d\n",
+ ((struct ipa_ioc_add_rt_rule *)param)->
+ num_rules,
+ pre_entry);
+ retval = -EFAULT;
+ break;
+ }
if (ipa_add_rt_rule((struct ipa_ioc_add_rt_rule *)param)) {
retval = -EFAULT;
break;
@@ -565,10 +605,11 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
+ pre_entry =
+ ((struct ipa_ioc_mdfy_rt_rule *)header)->num_rules;
pyld_sz =
sizeof(struct ipa_ioc_mdfy_rt_rule) +
- ((struct ipa_ioc_mdfy_rt_rule *)header)->num_rules *
- sizeof(struct ipa_rt_rule_mdfy);
+ pre_entry * sizeof(struct ipa_rt_rule_mdfy);
param = kzalloc(pyld_sz, GFP_KERNEL);
if (!param) {
retval = -ENOMEM;
@@ -578,6 +619,16 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
+ /* add check in case user-space module compromised */
+ if (unlikely(((struct ipa_ioc_mdfy_rt_rule *)param)->num_rules
+ != pre_entry)) {
+ IPAERR("current %d pre %d\n",
+ ((struct ipa_ioc_mdfy_rt_rule *)param)->
+ num_rules,
+ pre_entry);
+ retval = -EFAULT;
+ break;
+ }
if (ipa_mdfy_rt_rule((struct ipa_ioc_mdfy_rt_rule *)param)) {
retval = -EFAULT;
break;
@@ -594,10 +645,11 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
+ pre_entry =
+ ((struct ipa_ioc_del_rt_rule *)header)->num_hdls;
pyld_sz =
sizeof(struct ipa_ioc_del_rt_rule) +
- ((struct ipa_ioc_del_rt_rule *)header)->num_hdls *
- sizeof(struct ipa_rt_rule_del);
+ pre_entry * sizeof(struct ipa_rt_rule_del);
param = kzalloc(pyld_sz, GFP_KERNEL);
if (!param) {
retval = -ENOMEM;
@@ -607,6 +659,15 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
+ /* add check in case user-space module compromised */
+ if (unlikely(((struct ipa_ioc_del_rt_rule *)param)->num_hdls
+ != pre_entry)) {
+ IPAERR("current %d pre %d\n",
+ ((struct ipa_ioc_del_rt_rule *)param)->num_hdls,
+ pre_entry);
+ retval = -EFAULT;
+ break;
+ }
if (ipa_del_rt_rule((struct ipa_ioc_del_rt_rule *)param)) {
retval = -EFAULT;
break;
@@ -623,10 +684,11 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
+ pre_entry =
+ ((struct ipa_ioc_add_flt_rule *)header)->num_rules;
pyld_sz =
sizeof(struct ipa_ioc_add_flt_rule) +
- ((struct ipa_ioc_add_flt_rule *)header)->num_rules *
- sizeof(struct ipa_flt_rule_add);
+ pre_entry * sizeof(struct ipa_flt_rule_add);
param = kzalloc(pyld_sz, GFP_KERNEL);
if (!param) {
retval = -ENOMEM;
@@ -636,6 +698,16 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
+ /* add check in case user-space module compromised */
+ if (unlikely(((struct ipa_ioc_add_flt_rule *)param)->num_rules
+ != pre_entry)) {
+ IPAERR("current %d pre %d\n",
+ ((struct ipa_ioc_add_flt_rule *)param)->
+ num_rules,
+ pre_entry);
+ retval = -EFAULT;
+ break;
+ }
if (ipa_add_flt_rule((struct ipa_ioc_add_flt_rule *)param)) {
retval = -EFAULT;
break;
@@ -652,10 +724,11 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
+ pre_entry =
+ ((struct ipa_ioc_del_flt_rule *)header)->num_hdls;
pyld_sz =
sizeof(struct ipa_ioc_del_flt_rule) +
- ((struct ipa_ioc_del_flt_rule *)header)->num_hdls *
- sizeof(struct ipa_flt_rule_del);
+ pre_entry * sizeof(struct ipa_flt_rule_del);
param = kzalloc(pyld_sz, GFP_KERNEL);
if (!param) {
retval = -ENOMEM;
@@ -665,6 +738,16 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
+ /* add check in case user-space module compromised */
+ if (unlikely(((struct ipa_ioc_del_flt_rule *)param)->num_hdls
+ != pre_entry)) {
+ IPAERR("current %d pre %d\n",
+ ((struct ipa_ioc_del_flt_rule *)param)->
+ num_hdls,
+ pre_entry);
+ retval = -EFAULT;
+ break;
+ }
if (ipa_del_flt_rule((struct ipa_ioc_del_flt_rule *)param)) {
retval = -EFAULT;
break;
@@ -681,10 +764,11 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
+ pre_entry =
+ ((struct ipa_ioc_mdfy_flt_rule *)header)->num_rules;
pyld_sz =
sizeof(struct ipa_ioc_mdfy_flt_rule) +
- ((struct ipa_ioc_mdfy_flt_rule *)header)->num_rules *
- sizeof(struct ipa_flt_rule_mdfy);
+ pre_entry * sizeof(struct ipa_flt_rule_mdfy);
param = kzalloc(pyld_sz, GFP_KERNEL);
if (!param) {
retval = -ENOMEM;
@@ -694,6 +778,16 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
+ /* add check in case user-space module compromised */
+ if (unlikely(((struct ipa_ioc_mdfy_flt_rule *)param)->num_rules
+ != pre_entry)) {
+ IPAERR("current %d pre %d\n",
+ ((struct ipa_ioc_mdfy_flt_rule *)param)->
+ num_rules,
+ pre_entry);
+ retval = -EFAULT;
+ break;
+ }
if (ipa_mdfy_flt_rule((struct ipa_ioc_mdfy_flt_rule *)param)) {
retval = -EFAULT;
break;
@@ -801,15 +895,15 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
-
- if (((struct ipa_ioc_query_intf_tx_props *)header)->num_tx_props
- > IPA_NUM_PROPS_MAX) {
+ if (((struct ipa_ioc_query_intf_tx_props *)
+ header)->num_tx_props > IPA_NUM_PROPS_MAX) {
retval = -EFAULT;
break;
}
-
- pyld_sz = sz + ((struct ipa_ioc_query_intf_tx_props *)
- header)->num_tx_props *
+ pre_entry =
+ ((struct ipa_ioc_query_intf_tx_props *)
+ header)->num_tx_props;
+ pyld_sz = sz + pre_entry *
sizeof(struct ipa_ioc_tx_intf_prop);
param = kzalloc(pyld_sz, GFP_KERNEL);
if (!param) {
@@ -820,6 +914,16 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
+ /* add check in case user-space module compromised */
+ if (unlikely(((struct ipa_ioc_query_intf_tx_props *)
+ param)->num_tx_props
+ != pre_entry)) {
+ IPAERR("current %d pre %d\n",
+ ((struct ipa_ioc_query_intf_tx_props *)
+ param)->num_tx_props, pre_entry);
+ retval = -EFAULT;
+ break;
+ }
if (ipa_query_intf_tx_props(
(struct ipa_ioc_query_intf_tx_props *)param)) {
retval = -1;
@@ -836,15 +940,15 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
-
- if (((struct ipa_ioc_query_intf_rx_props *)header)->num_rx_props
- > IPA_NUM_PROPS_MAX) {
+ if (((struct ipa_ioc_query_intf_rx_props *)
+ header)->num_rx_props > IPA_NUM_PROPS_MAX) {
retval = -EFAULT;
break;
}
-
- pyld_sz = sz + ((struct ipa_ioc_query_intf_rx_props *)
- header)->num_rx_props *
+ pre_entry =
+ ((struct ipa_ioc_query_intf_rx_props *)
+ header)->num_rx_props;
+ pyld_sz = sz + pre_entry *
sizeof(struct ipa_ioc_rx_intf_prop);
param = kzalloc(pyld_sz, GFP_KERNEL);
if (!param) {
@@ -855,6 +959,15 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
+ /* add check in case user-space module compromised */
+ if (unlikely(((struct ipa_ioc_query_intf_rx_props *)
+ param)->num_rx_props != pre_entry)) {
+ IPAERR("current %d pre %d\n",
+ ((struct ipa_ioc_query_intf_rx_props *)
+ param)->num_rx_props, pre_entry);
+ retval = -EFAULT;
+ break;
+ }
if (ipa_query_intf_rx_props(
(struct ipa_ioc_query_intf_rx_props *)param)) {
retval = -1;
@@ -877,9 +990,10 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
-
- pyld_sz = sz + ((struct ipa_ioc_query_intf_ext_props *)
- header)->num_ext_props *
+ pre_entry =
+ ((struct ipa_ioc_query_intf_ext_props *)
+ header)->num_ext_props;
+ pyld_sz = sz + pre_entry *
sizeof(struct ipa_ioc_ext_intf_prop);
param = kzalloc(pyld_sz, GFP_KERNEL);
if (!param) {
@@ -890,6 +1004,15 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
+ /* add check in case user-space module compromised */
+ if (unlikely(((struct ipa_ioc_query_intf_ext_props *)
+ param)->num_ext_props != pre_entry)) {
+ IPAERR("current %d pre %d\n",
+ ((struct ipa_ioc_query_intf_ext_props *)
+ param)->num_ext_props, pre_entry);
+ retval = -EFAULT;
+ break;
+ }
if (ipa_query_intf_ext_props(
(struct ipa_ioc_query_intf_ext_props *)param)) {
retval = -1;
@@ -906,8 +1029,10 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
+ pre_entry =
+ ((struct ipa_msg_meta *)header)->msg_len;
pyld_sz = sizeof(struct ipa_msg_meta) +
- ((struct ipa_msg_meta *)header)->msg_len;
+ pre_entry;
param = kzalloc(pyld_sz, GFP_KERNEL);
if (!param) {
retval = -ENOMEM;
@@ -917,6 +1042,15 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
+ /* add check in case user-space module compromised */
+ if (unlikely(((struct ipa_msg_meta *)param)->msg_len
+ != pre_entry)) {
+ IPAERR("current %d pre %d\n",
+ ((struct ipa_msg_meta *)param)->msg_len,
+ pre_entry);
+ retval = -EFAULT;
+ break;
+ }
if (ipa_pull_msg((struct ipa_msg_meta *)param,
(char *)param + sizeof(struct ipa_msg_meta),
((struct ipa_msg_meta *)param)->msg_len) !=
@@ -1032,10 +1166,12 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
+ pre_entry =
+ ((struct ipa_ioc_add_hdr_proc_ctx *)
+ header)->num_proc_ctxs;
pyld_sz =
sizeof(struct ipa_ioc_add_hdr_proc_ctx) +
- ((struct ipa_ioc_add_hdr_proc_ctx *)header)->num_proc_ctxs *
- sizeof(struct ipa_hdr_proc_ctx_add);
+ pre_entry * sizeof(struct ipa_hdr_proc_ctx_add);
param = kzalloc(pyld_sz, GFP_KERNEL);
if (!param) {
retval = -ENOMEM;
@@ -1045,6 +1181,15 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
+ /* add check in case user-space module compromised */
+ if (unlikely(((struct ipa_ioc_add_hdr_proc_ctx *)
+ param)->num_proc_ctxs != pre_entry)) {
+ IPAERR("current %d pre %d\n",
+ ((struct ipa_ioc_add_hdr_proc_ctx *)
+ param)->num_proc_ctxs, pre_entry);
+ retval = -EFAULT;
+ break;
+ }
if (ipa_add_hdr_proc_ctx(
(struct ipa_ioc_add_hdr_proc_ctx *)param)) {
retval = -EFAULT;
@@ -1061,10 +1206,11 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
+ pre_entry =
+ ((struct ipa_ioc_del_hdr_proc_ctx *)header)->num_hdls;
pyld_sz =
sizeof(struct ipa_ioc_del_hdr_proc_ctx) +
- ((struct ipa_ioc_del_hdr_proc_ctx *)header)->num_hdls *
- sizeof(struct ipa_hdr_proc_ctx_del);
+ pre_entry * sizeof(struct ipa_hdr_proc_ctx_del);
param = kzalloc(pyld_sz, GFP_KERNEL);
if (!param) {
retval = -ENOMEM;
@@ -1074,6 +1220,16 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
+ /* add check in case user-space module compromised */
+ if (unlikely(((struct ipa_ioc_del_hdr_proc_ctx *)
+ param)->num_hdls != pre_entry)) {
+ IPAERR("current %d pre %d\n",
+ ((struct ipa_ioc_del_hdr_proc_ctx *)param)->
+ num_hdls,
+ pre_entry);
+ retval = -EFAULT;
+ break;
+ }
if (ipa_del_hdr_proc_ctx(
(struct ipa_ioc_del_hdr_proc_ctx *)param)) {
retval = -EFAULT;
--
cgit v1.1