diff options
author | Biswajit Paul <biswajitpaul@codeaurora.org> | 2017-01-16 00:17:04 +0200 |
---|---|---|
committer | Patrick Tjin <pattjin@google.com> | 2017-01-18 22:01:36 -0800 |
commit | e0bfb9bb9fbbd47b6009726a971726d1288ec998 (patch) | |
tree | 96262fada12a4af0f3e9c1bfcf27e2ccfada2c8d | |
parent | 0ab30d91fb178c5967753343029581983a4e9b67 (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.c | 13 | ||||
-rw-r--r-- | drivers/platform/msm/ipa/ipa_hdr.c | 77 | ||||
-rw-r--r-- | drivers/platform/msm/ipa/ipa_i.h | 11 |
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); |