From ca3e7ebe4fa60545dd3296e507607da921cb895d Mon Sep 17 00:00:00 2001 From: "Isaac J. Manjarres" Date: Wed, 20 May 2020 17:19:09 -0700 Subject: [PATCH 1/3] soc: qcom: mem-buf: Configure the mem-buf device's DMA mask The mem-buf device can handle memory from anywhere in the system. This includes memory with a physical address above 32 bits, so configure the DMA mask for the mem-buf device based on the system configuration. Change-Id: If91bb6d8044e8e6f47994acd7e50633b46596808 Signed-off-by: Isaac J. Manjarres --- drivers/soc/qcom/mem-buf.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/soc/qcom/mem-buf.c b/drivers/soc/qcom/mem-buf.c index 6636ba5c3dad..4a4af066ea90 100644 --- a/drivers/soc/qcom/mem-buf.c +++ b/drivers/soc/qcom/mem-buf.c @@ -1560,6 +1560,8 @@ static int mem_buf_probe(struct platform_device *pdev) int ret; struct device *dev = &pdev->dev; struct device *class_dev; + u64 dma_mask = IS_ENABLED(CONFIG_ARM64) ? DMA_BIT_MASK(64) : + DMA_BIT_MASK(32); if (of_property_match_string(dev->of_node, "qcom,mem-buf-capabilities", "supplier") >= 0) { @@ -1577,6 +1579,12 @@ static int mem_buf_probe(struct platform_device *pdev) return -EINVAL; } + ret = dma_set_mask_and_coherent(dev, dma_mask); + if (ret) { + dev_err(dev, "Unable to set dma mask: %d\n", ret); + return ret; + } + mem_buf_msgq_recv_thr = kthread_create(mem_buf_msgq_recv_fn, NULL, "mem_buf_rcvr"); if (IS_ERR(mem_buf_msgq_recv_thr)) { From 75455dfc54ef642fd2c26d8ac554e301407add58 Mon Sep 17 00:00:00 2001 From: "Isaac J. Manjarres" Date: Thu, 14 May 2020 17:18:42 -0700 Subject: [PATCH 2/3] soc: qcom: mem-buf: Fix message queue registration check The condition that determines if we print an error after failing to register for the mem-buf message queue checks the return code against EPROBE_DEFER. This is not correct, as error codes are negative, so fix the check. Change-Id: I4ed03bde56c6edf66e0ffed060ec23a87a46be54 Signed-off-by: Isaac J. Manjarres --- drivers/soc/qcom/mem-buf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/qcom/mem-buf.c b/drivers/soc/qcom/mem-buf.c index 4a4af066ea90..ad34a20e2ccc 100644 --- a/drivers/soc/qcom/mem-buf.c +++ b/drivers/soc/qcom/mem-buf.c @@ -1596,7 +1596,7 @@ static int mem_buf_probe(struct platform_device *pdev) mem_buf_hh_msgq_hdl = hh_msgq_register(HH_MSGQ_LABEL_MEMBUF); if (IS_ERR(mem_buf_hh_msgq_hdl)) { ret = PTR_ERR(mem_buf_hh_msgq_hdl); - if (ret != EPROBE_DEFER) + if (ret != -EPROBE_DEFER) dev_err(dev, "Message queue registration failed: rc: %d\n", ret); From 0d121e6dc31de8fd8731032c0e7db45c49c670db Mon Sep 17 00:00:00 2001 From: "Isaac J. Manjarres" Date: Tue, 12 May 2020 11:37:21 -0700 Subject: [PATCH 3/3] soc: qcom: mem-buf: Limit the number of input ACL entries The number of ACL entries is currently not sanitized, which can allow for unreasonably large ACL to be allocated for later processing. Allowing for this to happen doesn't make much sense, as there aren't any valid usecases that require a large ACL, so restrict the number of ACL entries to 16. Also, while we're here, fix up some of the error handling in a few places. Change-Id: I5d1371ed180608486bcde1e208a36782986313af Signed-off-by: Isaac J. Manjarres --- drivers/soc/qcom/mem-buf.c | 35 ++++++++++++++++++++++++----------- include/uapi/linux/mem-buf.h | 2 ++ 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/drivers/soc/qcom/mem-buf.c b/drivers/soc/qcom/mem-buf.c index ad34a20e2ccc..969fb10585fe 100644 --- a/drivers/soc/qcom/mem-buf.c +++ b/drivers/soc/qcom/mem-buf.c @@ -1128,6 +1128,9 @@ static int mem_buf_vmid_to_vmid(u32 mem_buf_vmid) hh_vmid_t vmid; enum hh_vm_names vm_name; + if (!is_valid_mem_buf_vmid(mem_buf_vmid)) + return -EINVAL; + if (mem_buf_vmid == MEM_BUF_VMID_PRIMARY_VM) vm_name = HH_PRIMARY_VM; else if (mem_buf_vmid == MEM_BUF_VMID_TRUSTED_VM) @@ -1145,6 +1148,9 @@ static int mem_buf_perms_to_perms(u32 mem_buf_perms) { int perms = 0; + if (!is_valid_mem_buf_perms(mem_buf_perms)) + return -EINVAL; + if (mem_buf_perms & MEM_BUF_PERM_FLAG_READ) perms |= PERM_READ; if (mem_buf_perms & MEM_BUF_PERM_FLAG_WRITE) @@ -1173,13 +1179,12 @@ static struct hh_acl_desc *mem_buf_acl_to_hh_acl(unsigned int nr_acl_entries, for (i = 0; i < nr_acl_entries; i++) { mem_buf_vmid = entries[i].vmid; mem_buf_perms = entries[i].perms; - if (!is_valid_mem_buf_vmid(mem_buf_vmid) || - !is_valid_mem_buf_perms(mem_buf_perms)) { + vmid = mem_buf_vmid_to_vmid(mem_buf_vmid); + perms = mem_buf_perms_to_perms(mem_buf_perms); + if (vmid < 0 || perms < 0) { ret = -EINVAL; goto err_inv_vmid_perms; } - vmid = mem_buf_vmid_to_vmid(mem_buf_vmid); - perms = mem_buf_perms_to_perms(mem_buf_perms); acl_desc->acl_entries[i].vmid = vmid; acl_desc->acl_entries[i].perms = perms; } @@ -1266,6 +1271,12 @@ static const struct file_operations mem_buf_fops = { .release = mem_buf_buffer_release, }; +static bool is_valid_mem_type(enum mem_buf_mem_type mem_type) +{ + return mem_type >= MEM_BUF_ION_MEM_TYPE && + mem_type < MEM_BUF_MAX_MEM_TYPE; +} + void *mem_buf_alloc(struct mem_buf_allocation_data *alloc_data) { int ret; @@ -1275,7 +1286,11 @@ void *mem_buf_alloc(struct mem_buf_allocation_data *alloc_data) if (!(mem_buf_capability & MEM_BUF_CAP_CONSUMER)) return ERR_PTR(-ENOTSUPP); - if (!alloc_data) + if (!alloc_data || !alloc_data->size || !alloc_data->nr_acl_entries || + !alloc_data->acl_list || + (alloc_data->nr_acl_entries > MEM_BUF_MAX_NR_ACL_ENTS) || + !is_valid_mem_type(alloc_data->src_mem_type) || + !is_valid_mem_type(alloc_data->dst_mem_type)) return ERR_PTR(-EINVAL); membuf = kzalloc(sizeof(*membuf), GFP_KERNEL); @@ -1363,6 +1378,9 @@ int mem_buf_get_fd(void *membuf_desc) int fd; struct mem_buf_desc *membuf = membuf_desc; + if (!membuf_desc) + return -EINVAL; + fd = get_unused_fd_flags(O_CLOEXEC); if (fd < 0) return fd; @@ -1486,16 +1504,11 @@ out: return ret; } -static bool is_valid_mem_type(enum mem_buf_mem_type mem_type) -{ - return mem_type >= MEM_BUF_ION_MEM_TYPE && - mem_type < MEM_BUF_MAX_MEM_TYPE; -} - static int validate_ioctl_arg(struct mem_buf_alloc_ioctl_arg *allocation) { if (!allocation->size || !allocation->nr_acl_entries || !allocation->acl_list || + (allocation->nr_acl_entries > MEM_BUF_MAX_NR_ACL_ENTS) || !is_valid_mem_type(allocation->src_mem_type) || !is_valid_mem_type(allocation->dst_mem_type) || allocation->reserved0 || allocation->reserved1 || diff --git a/include/uapi/linux/mem-buf.h b/include/uapi/linux/mem-buf.h index 1567e2144018..025e1acd3bc8 100644 --- a/include/uapi/linux/mem-buf.h +++ b/include/uapi/linux/mem-buf.h @@ -31,6 +31,8 @@ enum mem_buf_mem_type { (MEM_BUF_PERM_FLAG_READ | MEM_BUF_PERM_FLAG_WRITE |\ MEM_BUF_PERM_FLAG_EXEC) +#define MEM_BUF_MAX_NR_ACL_ENTS 16 + /** * struct acl_entry: Represents the access control permissions for a VMID. * @vmid: The mem-buf VMID specifier associated with the VMID that will access