From d12370c7f3ecded1867fbd6b70ded35db55cab1d Mon Sep 17 00:00:00 2001 From: Skylar Chang Date: Wed, 19 Oct 2016 13:30:44 -0700 Subject: msm: ipa: fix ioctl input param validation Fix input parameter validation in order to avoid device crash because of incorrect parameter in IPA driver. Change-Id: Icbdb05aeb9211665420a872d3453dbbd24fd347b CRs-Fixed: 1069060 Acked-by: Ady Abraham Signed-off-by: Skylar Chang --- drivers/platform/msm/ipa/ipa_v2/ipa_flt.c | 36 ++++++++++++--- drivers/platform/msm/ipa/ipa_v2/ipa_i.h | 2 +- drivers/platform/msm/ipa/ipa_v2/ipa_nat.c | 77 ++++++++++++++++++++++++++++++- drivers/platform/msm/ipa/ipa_v2/ipa_rt.c | 26 +++++++++-- drivers/platform/msm/ipa/ipa_v3/ipa_nat.c | 76 ++++++++++++++++++++++++++++++ 5 files changed, 205 insertions(+), 12 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c b/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c index c36ecfe..d6e563b 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2016, 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 @@ -235,7 +235,7 @@ static int ipa_generate_flt_hw_rule(enum ipa_ip_type ip, * @ip: the ip address family type * @hdr_sz: header size * - * Returns: 0 on success, negative on failure + * Returns: size on success, negative on failure * * caller needs to hold any needed locks to ensure integrity * @@ -373,7 +373,12 @@ static int ipa_generate_flt_hw_tbl_common(enum ipa_ip_type ip, u8 *base, ((long)body & IPA_FLT_ENTRY_MEMORY_ALLIGNMENT)); } else { - WARN_ON(tbl->sz == 0); + if (tbl->sz == 0) { + IPAERR("tbl size is 0\n"); + WARN_ON(1); + goto proc_err; + } + /* allocate memory for the flt tbl */ flt_tbl_mem.size = tbl->sz; flt_tbl_mem.base = @@ -460,7 +465,12 @@ static int ipa_generate_flt_hw_tbl_common(enum ipa_ip_type ip, u8 *base, ((long)body & IPA_FLT_ENTRY_MEMORY_ALLIGNMENT)); } else { - WARN_ON(tbl->sz == 0); + if (tbl->sz == 0) { + IPAERR("tbl size is 0\n"); + WARN_ON(1); + goto proc_err; + } + /* allocate memory for the flt tbl */ flt_tbl_mem.size = tbl->sz; flt_tbl_mem.base = @@ -534,8 +544,15 @@ static int ipa_generate_flt_hw_tbl_v1_1(enum ipa_ip_type ip, u8 *hdr; u8 *body; u8 *base; + int res; + + res = ipa_get_flt_hw_tbl_size(ip, &hdr_sz); + if (res < 0) { + IPAERR("ipa_get_flt_hw_tbl_size failed %d\n", res); + return res; + } - mem->size = ipa_get_flt_hw_tbl_size(ip, &hdr_sz); + mem->size = res; mem->size = IPA_HW_TABLE_ALIGNMENT(mem->size); if (mem->size == 0) { @@ -720,6 +737,7 @@ static int ipa_generate_flt_hw_tbl_v2(enum ipa_ip_type ip, u32 *entr; u32 body_start_offset; u32 hdr_top; + int res; if (ip == IPA_IP_v4) body_start_offset = IPA_MEM_PART(apps_v4_flt_ofst) - @@ -756,7 +774,13 @@ static int ipa_generate_flt_hw_tbl_v2(enum ipa_ip_type ip, entr++; } - mem->size = ipa_get_flt_hw_tbl_size(ip, &hdr_sz); + res = ipa_get_flt_hw_tbl_size(ip, &hdr_sz); + if (res < 0) { + IPAERR("ipa_get_flt_hw_tbl_size failed %d\n", res); + goto body_err; + } + + mem->size = res; mem->size -= hdr_sz; mem->size = IPA_HW_TABLE_ALIGNMENT(mem->size); diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h index ba16682..1e3c098 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h @@ -137,7 +137,7 @@ #define IPA_HW_TABLE_ALIGNMENT(start_ofst) \ (((start_ofst) + 127) & ~127) -#define IPA_RT_FLT_HW_RULE_BUF_SIZE (128) +#define IPA_RT_FLT_HW_RULE_BUF_SIZE (256) #define IPA_HDR_PROC_CTX_TABLE_ALIGNMENT_BYTE 8 #define IPA_HDR_PROC_CTX_TABLE_ALIGNMENT(start_ofst) \ diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_nat.c b/drivers/platform/msm/ipa/ipa_v2/ipa_nat.c index 6202992..314b095 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_nat.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_nat.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2016, 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 @@ -25,6 +25,16 @@ #define IPA_NAT_SHARED_MEMORY 1 #define IPA_NAT_TEMP_MEM_SIZE 128 +enum nat_table_type { + IPA_NAT_BASE_TBL = 0, + IPA_NAT_EXPN_TBL = 1, + IPA_NAT_INDX_TBL = 2, + IPA_NAT_INDEX_EXPN_TBL = 3, +}; + +#define NAT_TABLE_ENTRY_SIZE_BYTE 32 +#define NAT_INTEX_TABLE_ENTRY_SIZE_BYTE 4 + static int ipa_nat_vma_fault_remap( struct vm_area_struct *vma, struct vm_fault *vmf) { @@ -568,6 +578,71 @@ int ipa2_nat_dma_cmd(struct ipa_ioc_nat_dma_cmd *dma) goto bail; } + for (cnt = 0; cnt < dma->entries; cnt++) { + if (dma->dma[cnt].table_index >= 1) { + IPAERR("Invalid table index %d\n", + dma->dma[cnt].table_index); + ret = -EPERM; + goto bail; + } + + switch (dma->dma[cnt].base_addr) { + case IPA_NAT_BASE_TBL: + if (dma->dma[cnt].offset >= + (ipa_ctx->nat_mem.size_base_tables + 1) * + NAT_TABLE_ENTRY_SIZE_BYTE) { + IPAERR("Invalid offset %d\n", + dma->dma[cnt].offset); + ret = -EPERM; + goto bail; + } + + break; + + case IPA_NAT_EXPN_TBL: + if (dma->dma[cnt].offset >= + ipa_ctx->nat_mem.size_expansion_tables * + NAT_TABLE_ENTRY_SIZE_BYTE) { + IPAERR("Invalid offset %d\n", + dma->dma[cnt].offset); + ret = -EPERM; + goto bail; + } + + break; + + case IPA_NAT_INDX_TBL: + if (dma->dma[cnt].offset >= + (ipa_ctx->nat_mem.size_base_tables + 1) * + NAT_INTEX_TABLE_ENTRY_SIZE_BYTE) { + IPAERR("Invalid offset %d\n", + dma->dma[cnt].offset); + ret = -EPERM; + goto bail; + } + + break; + + case IPA_NAT_INDEX_EXPN_TBL: + if (dma->dma[cnt].offset >= + ipa_ctx->nat_mem.size_expansion_tables * + NAT_INTEX_TABLE_ENTRY_SIZE_BYTE) { + IPAERR("Invalid offset %d\n", + dma->dma[cnt].offset); + ret = -EPERM; + goto bail; + } + + break; + + default: + IPAERR("Invalid base_addr %d\n", + dma->dma[cnt].base_addr); + ret = -EPERM; + goto bail; + } + } + size = sizeof(struct ipa_desc) * NUM_OF_DESC; desc = kzalloc(size, GFP_KERNEL); if (desc == NULL) { diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c index 4ec43dd..8efc2d8 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c @@ -227,7 +227,7 @@ int __ipa_generate_rt_hw_rule_v2_6L(enum ipa_ip_type ip, * @hdr_sz: header size * @max_rt_idx: maximal index * - * Returns: 0 on success, negative on failure + * Returns: size on success, negative on failure * * caller needs to hold any needed locks to ensure integrity * @@ -356,7 +356,11 @@ static int ipa_generate_rt_hw_tbl_common(enum ipa_ip_type ip, u8 *base, u8 *hdr, ((long)body & IPA_RT_ENTRY_MEMORY_ALLIGNMENT)); } else { - WARN_ON(tbl->sz == 0); + if (tbl->sz == 0) { + IPAERR("cannot generate 0 size table\n"); + goto proc_err; + } + /* allocate memory for the RT tbl */ rt_tbl_mem.size = tbl->sz; rt_tbl_mem.base = @@ -429,8 +433,15 @@ static int ipa_generate_rt_hw_tbl_v1_1(enum ipa_ip_type ip, u8 *base; int max_rt_idx; int i; + int res; - mem->size = ipa_get_rt_hw_tbl_size(ip, &hdr_sz, &max_rt_idx); + res = ipa_get_rt_hw_tbl_size(ip, &hdr_sz, &max_rt_idx); + if (res < 0) { + IPAERR("ipa_get_rt_hw_tbl_size failed %d\n", res); + goto error; + } + + mem->size = res; mem->size = (mem->size + IPA_RT_TABLE_MEMORY_ALLIGNMENT) & ~IPA_RT_TABLE_MEMORY_ALLIGNMENT; @@ -603,6 +614,7 @@ static int ipa_generate_rt_hw_tbl_v2(enum ipa_ip_type ip, int num_index; u32 body_start_offset; u32 apps_start_idx; + int res; if (ip == IPA_IP_v4) { num_index = IPA_MEM_PART(v4_apps_rt_index_hi) - @@ -632,7 +644,13 @@ static int ipa_generate_rt_hw_tbl_v2(enum ipa_ip_type ip, entr++; } - mem->size = ipa_get_rt_hw_tbl_size(ip, &hdr_sz, &max_rt_idx); + res = ipa_get_rt_hw_tbl_size(ip, &hdr_sz, &max_rt_idx); + if (res < 0) { + IPAERR("ipa_get_rt_hw_tbl_size failed %d\n", res); + goto base_err; + } + + mem->size = res; mem->size -= hdr_sz; mem->size = (mem->size + IPA_RT_TABLE_MEMORY_ALLIGNMENT) & ~IPA_RT_TABLE_MEMORY_ALLIGNMENT; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c b/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c index 67e9b39..e7e5cf1 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c @@ -24,6 +24,17 @@ #define IPA_NAT_TEMP_MEM_SIZE 128 +enum nat_table_type { + IPA_NAT_BASE_TBL = 0, + IPA_NAT_EXPN_TBL = 1, + IPA_NAT_INDX_TBL = 2, + IPA_NAT_INDEX_EXPN_TBL = 3, +}; + +#define NAT_TABLE_ENTRY_SIZE_BYTE 32 +#define NAT_INTEX_TABLE_ENTRY_SIZE_BYTE 4 + + static int ipa3_nat_vma_fault_remap( struct vm_area_struct *vma, struct vm_fault *vmf) { @@ -571,6 +582,71 @@ int ipa3_nat_dma_cmd(struct ipa_ioc_nat_dma_cmd *dma) goto bail; } + for (cnt = 0; cnt < dma->entries; cnt++) { + if (dma->dma[cnt].table_index >= 1) { + IPAERR("Invalid table index %d\n", + dma->dma[cnt].table_index); + ret = -EPERM; + goto bail; + } + + switch (dma->dma[cnt].base_addr) { + case IPA_NAT_BASE_TBL: + if (dma->dma[cnt].offset >= + (ipa3_ctx->nat_mem.size_base_tables + 1) * + NAT_TABLE_ENTRY_SIZE_BYTE) { + IPAERR("Invalid offset %d\n", + dma->dma[cnt].offset); + ret = -EPERM; + goto bail; + } + + break; + + case IPA_NAT_EXPN_TBL: + if (dma->dma[cnt].offset >= + ipa3_ctx->nat_mem.size_expansion_tables * + NAT_TABLE_ENTRY_SIZE_BYTE) { + IPAERR("Invalid offset %d\n", + dma->dma[cnt].offset); + ret = -EPERM; + goto bail; + } + + break; + + case IPA_NAT_INDX_TBL: + if (dma->dma[cnt].offset >= + (ipa3_ctx->nat_mem.size_base_tables + 1) * + NAT_INTEX_TABLE_ENTRY_SIZE_BYTE) { + IPAERR("Invalid offset %d\n", + dma->dma[cnt].offset); + ret = -EPERM; + goto bail; + } + + break; + + case IPA_NAT_INDEX_EXPN_TBL: + if (dma->dma[cnt].offset >= + ipa3_ctx->nat_mem.size_expansion_tables * + NAT_INTEX_TABLE_ENTRY_SIZE_BYTE) { + IPAERR("Invalid offset %d\n", + dma->dma[cnt].offset); + ret = -EPERM; + goto bail; + } + + break; + + default: + IPAERR("Invalid base_addr %d\n", + dma->dma[cnt].base_addr); + ret = -EPERM; + goto bail; + } + } + size = sizeof(struct ipa3_desc) * NUM_OF_DESC; desc = kzalloc(size, GFP_KERNEL); if (desc == NULL) { -- cgit v1.1