aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBiswajit Paul <biswajitpaul@codeaurora.org>2017-01-16 00:17:04 +0200
committerPatrick Tjin <pattjin@google.com>2017-01-18 22:01:36 -0800
commite0bfb9bb9fbbd47b6009726a971726d1288ec998 (patch)
tree96262fada12a4af0f3e9c1bfcf27e2ccfada2c8d
parent0ab30d91fb178c5967753343029581983a4e9b67 (diff)
msm: ipa: Prevent multiple header deletion from user spaceandroid-7.1.1_r0.48
An IPA header or processing context can be added once and later deleted once from user space. Multiple deletion may cause invalid state of the headers software cache. Bug: 33139056 Change-Id: Ic0b8472b7fd8a76233a007d90c832af726184574 CRs-fixed: 1097714 Signed-off-by: Ghanim Fodi <gfodi@codeaurora.org> Signed-off-by: Biswajit Paul <biswajitpaul@codeaurora.org>
-rw-r--r--drivers/platform/msm/ipa/ipa.c13
-rw-r--r--drivers/platform/msm/ipa/ipa_hdr.c77
-rw-r--r--drivers/platform/msm/ipa/ipa_i.h11
3 files changed, 79 insertions, 22 deletions
diff --git a/drivers/platform/msm/ipa/ipa.c b/drivers/platform/msm/ipa/ipa.c
index 7edeb1b4ce36..601081d715fc 100644
--- a/drivers/platform/msm/ipa/ipa.c
+++ b/drivers/platform/msm/ipa/ipa.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
@@ -431,7 +431,8 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
- if (ipa_del_hdr((struct ipa_ioc_del_hdr *)param)) {
+ if (ipa_del_hdr_by_user((struct ipa_ioc_del_hdr *)param,
+ true)) {
retval = -EFAULT;
break;
}
@@ -1106,8 +1107,8 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
- if (ipa_del_hdr_proc_ctx(
- (struct ipa_ioc_del_hdr_proc_ctx *)param)) {
+ if (ipa_del_hdr_proc_ctx_by_user(
+ (struct ipa_ioc_del_hdr_proc_ctx *)param, true)) {
retval = -EFAULT;
break;
}
@@ -2246,7 +2247,7 @@ fail_schedule_delayed_work:
if (ipa_ctx->dflt_v4_rt_rule_hdl)
__ipa_del_rt_rule(ipa_ctx->dflt_v4_rt_rule_hdl);
if (ipa_ctx->excp_hdr_hdl)
- __ipa_del_hdr(ipa_ctx->excp_hdr_hdl);
+ __ipa_del_hdr(ipa_ctx->excp_hdr_hdl, false);
ipa_teardown_sys_pipe(ipa_ctx->clnt_hdl_cmd);
fail_cmd:
return result;
@@ -2258,7 +2259,7 @@ static void ipa_teardown_apps_pipes(void)
ipa_teardown_sys_pipe(ipa_ctx->clnt_hdl_data_in);
__ipa_del_rt_rule(ipa_ctx->dflt_v6_rt_rule_hdl);
__ipa_del_rt_rule(ipa_ctx->dflt_v4_rt_rule_hdl);
- __ipa_del_hdr(ipa_ctx->excp_hdr_hdl);
+ __ipa_del_hdr(ipa_ctx->excp_hdr_hdl, false);
ipa_teardown_sys_pipe(ipa_ctx->clnt_hdl_cmd);
}
diff --git a/drivers/platform/msm/ipa/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_hdr.c
index c1e920539b0e..1426e4bc66e2 100644
--- a/drivers/platform/msm/ipa/ipa_hdr.c
+++ b/drivers/platform/msm/ipa/ipa_hdr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
@@ -719,7 +719,8 @@ error:
return -EPERM;
}
-static int __ipa_del_hdr_proc_ctx(u32 proc_ctx_hdl, bool release_hdr)
+static int __ipa_del_hdr_proc_ctx(u32 proc_ctx_hdl,
+ bool release_hdr, bool by_user)
{
struct ipa_hdr_proc_ctx_entry *entry;
struct ipa_hdr_proc_ctx_tbl *htbl = &ipa_ctx->hdr_proc_ctx_tbl;
@@ -733,6 +734,14 @@ static int __ipa_del_hdr_proc_ctx(u32 proc_ctx_hdl, bool release_hdr)
IPADBG("del ctx proc cnt=%d ofst=%d\n",
htbl->proc_ctx_cnt, entry->offset_entry->offset);
+ if (by_user && entry->user_deleted) {
+ IPAERR("proc_ctx already deleted by user\n");
+ return -EINVAL;
+ }
+
+ if (by_user)
+ entry->user_deleted = true;
+
if (--entry->ref_cnt) {
IPADBG("proc_ctx_hdl %x ref_cnt %d\n",
proc_ctx_hdl, entry->ref_cnt);
@@ -740,7 +749,7 @@ static int __ipa_del_hdr_proc_ctx(u32 proc_ctx_hdl, bool release_hdr)
}
if (release_hdr)
- __ipa_release_hdr(entry->hdr->id);
+ __ipa_del_hdr(entry->hdr->id, false);
/* move the offset entry to appropriate free list */
list_move(&entry->offset_entry->link,
@@ -757,7 +766,7 @@ static int __ipa_del_hdr_proc_ctx(u32 proc_ctx_hdl, bool release_hdr)
}
-int __ipa_del_hdr(u32 hdr_hdl)
+int __ipa_del_hdr(u32 hdr_hdl, bool by_user)
{
struct ipa_hdr_entry *entry;
struct ipa_hdr_tbl *htbl = &ipa_ctx->hdr_tbl;
@@ -776,6 +785,14 @@ int __ipa_del_hdr(u32 hdr_hdl)
IPADBG("del hdr of sz=%d hdr_cnt=%d ofst=%d\n", entry->hdr_len,
htbl->hdr_cnt, entry->offset_entry->offset);
+ if (by_user && entry->user_deleted) {
+ IPAERR("hdr already deleted by user\n");
+ return -EINVAL;
+ }
+
+ if (by_user)
+ entry->user_deleted = true;
+
if (--entry->ref_cnt) {
IPADBG("hdr_hdl %x ref_cnt %d\n", hdr_hdl, entry->ref_cnt);
return 0;
@@ -786,7 +803,7 @@ int __ipa_del_hdr(u32 hdr_hdl)
entry->phys_base,
entry->hdr_len,
DMA_TO_DEVICE);
- __ipa_del_hdr_proc_ctx(entry->proc_ctx->id, false);
+ __ipa_del_hdr_proc_ctx(entry->proc_ctx->id, false, false);
} else {
/* move the offset entry to appropriate free list */
list_move(&entry->offset_entry->link,
@@ -849,15 +866,16 @@ bail:
EXPORT_SYMBOL(ipa_add_hdr);
/**
- * ipa_del_hdr() - Remove the specified headers from SW and optionally commit them
- * to IPA HW
+ * ipa_del_hdr_by_user() - Remove the specified headers
+ * from SW and optionally commit them to IPA HW
* @hdls: [inout] set of headers to delete
+ * @by_user: Operation requested by user?
*
* Returns: 0 on success, negative on failure
*
* Note: Should not be called from atomic context
*/
-int ipa_del_hdr(struct ipa_ioc_del_hdr *hdls)
+int ipa_del_hdr_by_user(struct ipa_ioc_del_hdr *hdls, bool by_user)
{
int i;
int result = -EFAULT;
@@ -869,7 +887,7 @@ int ipa_del_hdr(struct ipa_ioc_del_hdr *hdls)
mutex_lock(&ipa_ctx->lock);
for (i = 0; i < hdls->num_hdls; i++) {
- if (__ipa_del_hdr(hdls->hdl[i].hdl)) {
+ if (__ipa_del_hdr(hdls->hdl[i].hdl, by_user)) {
IPAERR("failed to del hdr %i\n", i);
hdls->hdl[i].status = -1;
} else {
@@ -888,6 +906,20 @@ bail:
mutex_unlock(&ipa_ctx->lock);
return result;
}
+
+/**
+ * ipa_del_hdr() - Remove the specified headers from SW and optionally commit them
+ * to IPA HW
+ * @hdls: [inout] set of headers to delete
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ * Note: Should not be called from atomic context
+ */
+int ipa_del_hdr(struct ipa_ioc_del_hdr *hdls)
+{
+ return ipa_del_hdr_by_user(hdls, false);
+}
EXPORT_SYMBOL(ipa_del_hdr);
/**
@@ -936,16 +968,18 @@ bail:
EXPORT_SYMBOL(ipa_add_hdr_proc_ctx);
/**
- * ipa_del_hdr_proc_ctx() -
+ * ipa_del_hdr_proc_ctx_by_user() -
* Remove the specified processing context headers from SW and
* optionally commit them to IPA HW.
* @hdls: [inout] set of processing context headers to delete
+ * @by_user: Operation requested by user?
*
* Returns: 0 on success, negative on failure
*
* Note: Should not be called from atomic context
*/
-int ipa_del_hdr_proc_ctx(struct ipa_ioc_del_hdr_proc_ctx *hdls)
+int ipa_del_hdr_proc_ctx_by_user(struct ipa_ioc_del_hdr_proc_ctx *hdls,
+ bool by_user)
{
int i;
int result;
@@ -957,7 +991,7 @@ int ipa_del_hdr_proc_ctx(struct ipa_ioc_del_hdr_proc_ctx *hdls)
mutex_lock(&ipa_ctx->lock);
for (i = 0; i < hdls->num_hdls; i++) {
- if (__ipa_del_hdr_proc_ctx(hdls->hdl[i].hdl, true)) {
+ if (__ipa_del_hdr_proc_ctx(hdls->hdl[i].hdl, true, by_user)) {
IPAERR("failed to del hdr %i\n", i);
hdls->hdl[i].status = -1;
} else {
@@ -976,6 +1010,21 @@ bail:
mutex_unlock(&ipa_ctx->lock);
return result;
}
+
+/**
+ * ipa_del_hdr_proc_ctx() -
+ * Remove the specified processing context headers from SW and
+ * optionally commit them to IPA HW.
+ * @hdls: [inout] set of processing context headers to delete
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ * Note: Should not be called from atomic context
+ */
+int ipa_del_hdr_proc_ctx(struct ipa_ioc_del_hdr_proc_ctx *hdls)
+{
+ return ipa_del_hdr_proc_ctx_by_user(hdls, false);
+}
EXPORT_SYMBOL(ipa_del_hdr_proc_ctx);
/**
@@ -1197,7 +1246,7 @@ int __ipa_release_hdr(u32 hdr_hdl)
{
int result = 0;
- if (__ipa_del_hdr(hdr_hdl)) {
+ if (__ipa_del_hdr(hdr_hdl, false)) {
IPADBG("fail to del hdr %x\n", hdr_hdl);
result = -EFAULT;
goto bail;
@@ -1225,7 +1274,7 @@ int __ipa_release_hdr_proc_ctx(u32 proc_ctx_hdl)
{
int result = 0;
- if (__ipa_del_hdr_proc_ctx(proc_ctx_hdl, true)) {
+ if (__ipa_del_hdr_proc_ctx(proc_ctx_hdl, true, false)) {
IPADBG("fail to del hdr %x\n", proc_ctx_hdl);
result = -EFAULT;
goto bail;
diff --git a/drivers/platform/msm/ipa/ipa_i.h b/drivers/platform/msm/ipa/ipa_i.h
index 14ddf1299512..7c4deca1ba41 100644
--- a/drivers/platform/msm/ipa/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_i.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2015, 2017 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
@@ -226,6 +226,7 @@ struct ipa_rt_tbl {
* @id: header entry id
* @is_eth2_ofst_valid: is eth2_ofst field valid?
* @eth2_ofst: offset to start of Ethernet-II/802.3 header
+ * @user_deleted: is the header deleted by the user?
*/
struct ipa_hdr_entry {
struct list_head link;
@@ -243,6 +244,7 @@ struct ipa_hdr_entry {
int id;
u8 is_eth2_ofst_valid;
u16 eth2_ofst;
+ bool user_deleted;
};
/**
@@ -318,6 +320,7 @@ struct ipa_hdr_proc_ctx_add_hdr_cmd_seq {
* @cookie: cookie used for validity check
* @ref_cnt: reference counter of routing table
* @id: processing context header entry id
+ * @user_deleted: is the hdr processing context deleted by the user?
*/
struct ipa_hdr_proc_ctx_entry {
struct list_head link;
@@ -327,6 +330,7 @@ struct ipa_hdr_proc_ctx_entry {
u32 cookie;
u32 ref_cnt;
int id;
+ bool user_deleted;
};
/**
@@ -1397,8 +1401,11 @@ void ipa_inc_client_enable_clks(void);
int ipa_inc_client_enable_clks_no_block(void);
void ipa_dec_client_disable_clks(void);
int ipa_interrupts_init(u32 ipa_irq, u32 ee, struct device *ipa_dev);
+int ipa_del_hdr_by_user(struct ipa_ioc_del_hdr *hdls, bool by_user);
+int ipa_del_hdr_proc_ctx_by_user(struct ipa_ioc_del_hdr_proc_ctx *hdls,
+ bool by_user);
int __ipa_del_rt_rule(u32 rule_hdl);
-int __ipa_del_hdr(u32 hdr_hdl);
+int __ipa_del_hdr(u32 hdr_hdl, bool by_user);
int __ipa_release_hdr(u32 hdr_hdl);
int __ipa_release_hdr_proc_ctx(u32 proc_ctx_hdl);
int _ipa_read_gen_reg_v1_1(char *buff, int max_len);