From a65aa65ad1c1520ebb405b1bd5ae8d5d3986f2d0 Mon Sep 17 00:00:00 2001 From: YangYi Date: Wed, 26 Oct 2022 11:27:31 +0800 Subject: [PATCH] Penang: resolve kasan panic Penang: KASAN: slab-out-of-bounds in qrtr_endpoint_register Change-Id: I7542a0f2af0ceb0fdd04291b86795ba942ffe8d7 Signed-off-by: YangYi Reviewed-on: https://gerrit.mot.com/2413704 SME-Granted: SME Approvals Granted SLTApproved: Slta Waiver Tested-by: Jira Key Reviewed-by: Yuchang Guo Reviewed-by: Xiangpo Zhao Submit-Approved: Jira Key --- net/qrtr/qrtr.c | 20 +++++++++++++++----- net/qrtr/qrtr.h | 14 +++++++++++++- net/qrtr/smd.c | 16 ++++++++++------ 3 files changed, 38 insertions(+), 12 deletions(-) diff --git a/net/qrtr/qrtr.c b/net/qrtr/qrtr.c index fd1591c3fbcf..30584254f785 100644 --- a/net/qrtr/qrtr.c +++ b/net/qrtr/qrtr.c @@ -193,6 +193,7 @@ struct qrtr_node { void *ilc; u32 nonwake_svc[MAX_NON_WAKE_SVC_LEN]; + struct qrtr_array no_wake_svc; }; struct qrtr_tx_flow_waiter { @@ -421,6 +422,7 @@ static void __qrtr_node_release(struct kref *kref) kthread_stop(node->task); skb_queue_purge(&node->rx_queue); + kfree(node->no_wake_svc.arr); kfree(node); } @@ -944,8 +946,12 @@ int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len) if (svc_id > 0) { for (i = 0; i < MAX_NON_WAKE_SVC_LEN; i++) { if (svc_id == node->nonwake_svc[i]) { - wake = false; - break; + for (i = 0; i < node->no_wake_svc.size; i++) { + if (svc_id == node->no_wake_svc.arr[i]) { + wake = false; + break; + } + } } } } @@ -964,7 +970,6 @@ int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len) qrtr_port_put(ipc); } - return 0; err: @@ -1170,7 +1175,7 @@ static void qrtr_hello_work(struct kthread_work *work) * The specified endpoint must have the xmit function pointer set on call. */ int qrtr_endpoint_register(struct qrtr_endpoint *ep, unsigned int net_id, - bool rt, u32 *svc_arr) + bool rt, struct qrtr_array *svc_arr) { struct qrtr_node *node; struct sched_param param = {.sched_priority = 1}; @@ -1203,7 +1208,12 @@ int qrtr_endpoint_register(struct qrtr_endpoint *ep, unsigned int net_id, if (svc_arr) memcpy(node->nonwake_svc, svc_arr, MAX_NON_WAKE_SVC_LEN * sizeof(int)); - + if(svc_arr && svc_arr->size) { + node->no_wake_svc.arr = kmalloc_array(svc_arr->size, sizeof(u32), GFP_KERNEL); + memcpy((void *)node->no_wake_svc.arr, (void *)svc_arr->arr, + svc_arr->size * sizeof(u32)); + node->no_wake_svc.size = svc_arr->size; + } mutex_init(&node->qrtr_tx_lock); INIT_RADIX_TREE(&node->qrtr_tx_flow, GFP_KERNEL); init_waitqueue_head(&node->resume_tx); diff --git a/net/qrtr/qrtr.h b/net/qrtr/qrtr.h index 449028c2ec93..f58117d6fb03 100644 --- a/net/qrtr/qrtr.h +++ b/net/qrtr/qrtr.h @@ -28,8 +28,20 @@ struct qrtr_endpoint { struct qrtr_node *node; }; +/** + * struct qrtr_array - array with size + * @arr: elements in the array + * @size: number of elements + * + * An array with its size provided. + */ +struct qrtr_array { + u32 *arr; + size_t size; +}; + int qrtr_endpoint_register(struct qrtr_endpoint *ep, unsigned int net_id, - bool rt, u32 *svc_arr); + bool rt, struct qrtr_array *svc_arr); void qrtr_endpoint_unregister(struct qrtr_endpoint *ep); diff --git a/net/qrtr/smd.c b/net/qrtr/smd.c index 705e6523e1b2..1939bc1c98bb 100644 --- a/net/qrtr/smd.c +++ b/net/qrtr/smd.c @@ -64,8 +64,9 @@ static int qcom_smd_qrtr_probe(struct rpmsg_device *rpdev) struct qrtr_smd_dev *qdev; u32 net_id; bool rt; - int rc, size; - u32 *svc_arr = NULL; + int rc; + size_t size; + struct qrtr_array svc_arr = {NULL, 0}; pr_info("%s:Entered\n", __func__); qdev = devm_kzalloc(&rpdev->dev, sizeof(*qdev), GFP_KERNEL); @@ -87,13 +88,16 @@ static int qcom_smd_qrtr_probe(struct rpmsg_device *rpdev) if (size > 0) { if (size > MAX_NON_WAKE_SVC_LEN) size = MAX_NON_WAKE_SVC_LEN; - svc_arr = kmalloc_array(size, sizeof(u32), GFP_KERNEL); + svc_arr.size = size; + svc_arr.arr = kmalloc_array(size, sizeof(u32), GFP_KERNEL); + if (!svc_arr.arr) + return -ENOMEM; of_property_read_u32_array(rpdev->dev.of_node, "qcom,non-wake-svc", - svc_arr, size); + svc_arr.arr, size); } - rc = qrtr_endpoint_register(&qdev->ep, net_id, rt, svc_arr); - kfree(svc_arr); + rc = qrtr_endpoint_register(&qdev->ep, net_id, rt, &svc_arr); + kfree(svc_arr.arr); if (rc) return rc;