From 6308db721874c0fe08964e6848dedc62caf3b2df Mon Sep 17 00:00:00 2001 From: Mohammed Javid Date: Thu, 19 Apr 2018 13:41:16 +0530 Subject: [PATCH 01/53] msm: ipa: rmnet: Make code changes with respect to CR#2046006 Check for CAP_NET_ADMIN capability of the user space application who tries to access rmnet driver IOCTL. Bug: 36367253 Change-Id: If6bb4b54659306c5103b5e34bf02c7234c851e0a CRs-Fixed: 2226355 Signed-off-by: Mohammed Javid --- drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c | 2 ++ drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c index 84bd6e32bcf..c15c76f354b 100644 --- a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c @@ -1305,6 +1305,8 @@ static int ipa_wwan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) /* Extended IOCTLs */ case RMNET_IOCTL_EXTENDED: + if (!ns_capable(dev_net(dev)->user_ns, CAP_NET_ADMIN)) + return -EPERM; IPAWANDBG("get ioctl: RMNET_IOCTL_EXTENDED\n"); if (copy_from_user(&extend_ioctl_data, (u8 *)ifr->ifr_ifru.ifru_data, diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c index a225826b5e7..a91e577f563 100644 --- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c @@ -1326,6 +1326,8 @@ static int ipa3_wwan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) /* Extended IOCTLs */ case RMNET_IOCTL_EXTENDED: + if (!ns_capable(dev_net(dev)->user_ns, CAP_NET_ADMIN)) + return -EPERM; IPAWANDBG("get ioctl: RMNET_IOCTL_EXTENDED\n"); if (copy_from_user(&extend_ioctl_data, (u8 *)ifr->ifr_ifru.ifru_data, From cfe3642b4f6541dffb4899963c61770f54b674ee Mon Sep 17 00:00:00 2001 From: Todd Kjos Date: Fri, 10 Nov 2017 15:30:27 -0800 Subject: [PATCH 02/53] FROMLIST: binder: fix proc->files use-after-free (from https://patchwork.kernel.org/patch/10058587/) proc->files cleanup is initiated by binder_vma_close. Therefore a reference on the binder_proc is not enough to prevent the files_struct from being released while the binder_proc still has a reference. This can lead to an attempt to dereference the stale pointer obtained from proc->files prior to proc->files cleanup. This has been seen once in task_get_unused_fd_flags() when __alloc_fd() is called with a stale "files". The fix is to always use get_files_struct() to obtain struct_files so that the refcount on the files_struct is used to prevent a premature free. proc->files is removed since we get it every time. Bug: 69164715 Change-Id: I6431027d3d569e76913935c21885201505627982 Signed-off-by: Todd Kjos Signed-off-by: Siqi Lin --- drivers/staging/android/binder.c | 63 +++++++++++++++----------------- 1 file changed, 30 insertions(+), 33 deletions(-) diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c index a875dd38c94..f2e24afb247 100644 --- a/drivers/staging/android/binder.c +++ b/drivers/staging/android/binder.c @@ -462,9 +462,8 @@ struct binder_ref { }; enum binder_deferred_state { - BINDER_DEFERRED_PUT_FILES = 0x01, - BINDER_DEFERRED_FLUSH = 0x02, - BINDER_DEFERRED_RELEASE = 0x04, + BINDER_DEFERRED_FLUSH = 0x01, + BINDER_DEFERRED_RELEASE = 0x02, }; /** @@ -501,8 +500,6 @@ struct binder_priority { * (invariant after initialized) * @tsk task_struct for group_leader of process * (invariant after initialized) - * @files files_struct for process - * (invariant after initialized) * @deferred_work_node: element for binder_deferred_list * (protected by binder_deferred_lock) * @deferred_work: bitmap of deferred work to perform @@ -549,7 +546,6 @@ struct binder_proc { struct list_head waiting_threads; int pid; struct task_struct *tsk; - struct files_struct *files; struct hlist_node deferred_work_node; int deferred_work; bool is_dead; @@ -945,22 +941,34 @@ static void binder_free_thread(struct binder_thread *thread); static void binder_free_proc(struct binder_proc *proc); static void binder_inc_node_tmpref_ilocked(struct binder_node *node); +struct files_struct *binder_get_files_struct(struct binder_proc *proc) +{ + return get_files_struct(proc->tsk); +} + static int task_get_unused_fd_flags(struct binder_proc *proc, int flags) { - struct files_struct *files = proc->files; + struct files_struct *files; unsigned long rlim_cur; unsigned long irqs; + int ret; + files = binder_get_files_struct(proc); if (files == NULL) return -ESRCH; - if (!lock_task_sighand(proc->tsk, &irqs)) - return -EMFILE; + if (!lock_task_sighand(proc->tsk, &irqs)) { + ret = -EMFILE; + goto err; + } rlim_cur = task_rlimit(proc->tsk, RLIMIT_NOFILE); unlock_task_sighand(proc->tsk, &irqs); - return __alloc_fd(files, 0, rlim_cur, flags); + ret = __alloc_fd(files, 0, rlim_cur, flags); +err: + put_files_struct(files); + return ret; } /* @@ -969,8 +977,12 @@ static int task_get_unused_fd_flags(struct binder_proc *proc, int flags) static void task_fd_install( struct binder_proc *proc, unsigned int fd, struct file *file) { - if (proc->files) - __fd_install(proc->files, fd, file); + struct files_struct *files = binder_get_files_struct(proc); + + if (files) { + __fd_install(files, fd, file); + put_files_struct(files); + } } /* @@ -978,18 +990,20 @@ static void task_fd_install( */ static long task_close_fd(struct binder_proc *proc, unsigned int fd) { + struct files_struct *files = binder_get_files_struct(proc); int retval; - if (proc->files == NULL) + if (files == NULL) return -ESRCH; - retval = __close_fd(proc->files, fd); + retval = __close_fd(files, fd); /* can't restart close syscall because file table entry was cleared */ if (unlikely(retval == -ERESTARTSYS || retval == -ERESTARTNOINTR || retval == -ERESTARTNOHAND || retval == -ERESTART_RESTARTBLOCK)) retval = -EINTR; + put_files_struct(files); return retval; } @@ -4846,7 +4860,6 @@ static void binder_vma_close(struct vm_area_struct *vma) (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, (unsigned long)pgprot_val(vma->vm_page_prot)); binder_alloc_vma_close(&proc->alloc); - binder_defer_work(proc, BINDER_DEFERRED_PUT_FILES); } static int binder_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) @@ -4888,10 +4901,8 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma) vma->vm_private_data = proc; ret = binder_alloc_mmap_handler(&proc->alloc, vma); - if (ret) - return ret; - proc->files = get_files_struct(current); - return 0; + + return ret; err_bad_arg: pr_err("binder_mmap: %d %lx-%lx %s failed %d\n", @@ -5070,8 +5081,6 @@ static void binder_deferred_release(struct binder_proc *proc) struct rb_node *n; int threads, nodes, incoming_refs, outgoing_refs, active_transactions; - BUG_ON(proc->files); - mutex_lock(&binder_procs_lock); hlist_del(&proc->proc_node); mutex_unlock(&binder_procs_lock); @@ -5153,8 +5162,6 @@ static void binder_deferred_release(struct binder_proc *proc) static void binder_deferred_func(struct work_struct *work) { struct binder_proc *proc; - struct files_struct *files; - int defer; do { @@ -5171,21 +5178,11 @@ static void binder_deferred_func(struct work_struct *work) } mutex_unlock(&binder_deferred_lock); - files = NULL; - if (defer & BINDER_DEFERRED_PUT_FILES) { - files = proc->files; - if (files) - proc->files = NULL; - } - if (defer & BINDER_DEFERRED_FLUSH) binder_deferred_flush(proc); if (defer & BINDER_DEFERRED_RELEASE) binder_deferred_release(proc); /* frees proc */ - - if (files) - put_files_struct(files); } while (proc); } static DECLARE_WORK(binder_deferred_work, binder_deferred_func); From d44c905269622229bec8678cfc458456da01bc99 Mon Sep 17 00:00:00 2001 From: Bhalchandra Gajare Date: Tue, 25 Apr 2017 18:37:56 -0700 Subject: [PATCH 03/53] ASoC: msm-lsm-client: use kzalloc instead of kmalloc In the ioctl function, driver allocates memory to store data internally before calling copy_to_user to copy data to user-space. It is possible that kernel internal information can be leaked to user space through this if the allocated memory is not completely overwritten with valid data. Use kzalloc to fix this. CRs-fixed: 2026045 Bug: 73888283 Change-Id: I754ae2157034a135aaca4a15badf10d2567b7ed6 Signed-off-by: Bhalchandra Gajare --- sound/soc/msm/qdsp6v2/msm-lsm-client.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/msm/qdsp6v2/msm-lsm-client.c b/sound/soc/msm/qdsp6v2/msm-lsm-client.c index 2b0f0a47cc0..7a0d5d9ddc8 100644 --- a/sound/soc/msm/qdsp6v2/msm-lsm-client.c +++ b/sound/soc/msm/qdsp6v2/msm-lsm-client.c @@ -1146,7 +1146,7 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream, } size = sizeof(*user) + userarg32.payload_size; - user = kmalloc(size, GFP_KERNEL); + user = kzalloc(size, GFP_KERNEL); if (!user) { dev_err(rtd->dev, "%s: Allocation failed event status size %d\n", @@ -1167,7 +1167,7 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream, err = -EFAULT; } if (!err) { - user32 = kmalloc(size, GFP_KERNEL); + user32 = kzalloc(size, GFP_KERNEL); if (!user32) { dev_err(rtd->dev, "%s: Allocation event user status size %d\n", @@ -1581,7 +1581,7 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream, size = sizeof(struct snd_lsm_event_status) + userarg.payload_size; - user = kmalloc(size, GFP_KERNEL); + user = kzalloc(size, GFP_KERNEL); if (!user) { dev_err(rtd->dev, "%s: Allocation failed event status size %d\n", From 94970db92c2d803f245ba64da8dcb9e0c657398a Mon Sep 17 00:00:00 2001 From: annamraj Date: Wed, 11 Apr 2018 10:42:13 +0530 Subject: [PATCH 04/53] msm: camera: Fix for Possible information leak issue Fix for possible information leak issue because of unintialised variable Which can be accesed from userspace in camera fd driver Bug: 73889358 Signed-off-by: annamraj Change-Id: I4552c4829e9532d848e46fd123316b26105e310e --- drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c index 12c38795e78..1e99b671e2d 100644 --- a/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c +++ b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2016, 2018 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 @@ -440,7 +440,7 @@ static int msm_fd_open(struct file *file) } ctx->mem_pool.fd_device = ctx->fd_device; - ctx->stats = vmalloc(sizeof(*ctx->stats) * MSM_FD_MAX_RESULT_BUFS); + ctx->stats = vzalloc(sizeof(*ctx->stats) * MSM_FD_MAX_RESULT_BUFS); if (!ctx->stats) { dev_err(device->dev, "No memory for face statistics\n"); ret = -ENOMEM; From fe5ab2bd831490358c4d2d1145cacf733e518b59 Mon Sep 17 00:00:00 2001 From: Brahmaji K Date: Mon, 24 Oct 2016 20:28:18 +0530 Subject: [PATCH 05/53] crypto: ice: Fix NULL pointer exception in ice. While enabling ICE setup and on error conditions, the regulator is disabled. Before disabling the regulator, check if the regulator is up and able to access the registers of regulator. Bug: 78238455 Change-Id: I94dd2b3e25444818f7bdf2f791f4fa9efaefce15 Signed-off-by: Brahmaji K --- drivers/crypto/msm/ice.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/msm/ice.c b/drivers/crypto/msm/ice.c index fb7590b6c7a..9d9719fa2e5 100644 --- a/drivers/crypto/msm/ice.c +++ b/drivers/crypto/msm/ice.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-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 @@ -1601,7 +1601,18 @@ static int enable_ice_setup(struct ice_device *ice_dev) out_clocks: qcom_ice_enable_clocks(ice_dev, false); out_reg: - regulator_disable(ice_dev->reg); + if (ice_dev->is_regulator_available) { + if (qcom_ice_get_vreg(ice_dev)) { + pr_err("%s: Could not get regulator\n", __func__); + goto out; + } + ret = regulator_disable(ice_dev->reg); + if (ret) { + pr_err("%s:%pK: Could not disable regulator\n", + __func__, ice_dev); + goto out; + } + } out: return ret; } From 5a186c48d1ae23212bd900a194cc6783d79c7eb2 Mon Sep 17 00:00:00 2001 From: Mahesh Sivasubramanian Date: Wed, 7 Mar 2018 16:00:07 -0700 Subject: [PATCH 06/53] drivers: qcom: lpm-stats: Fix undefined access error In cleanup_stats(), a freed memory pointer pos might be accessed for list traversal. Switch to using _safe() variant of the list API to prevent undefined accesses. Bug: 79421260 Change-Id: I7d068cb7813ccb9bfdbcab4646b4ec890145828a Signed-off-by: Mahesh Sivasubramanian --- drivers/power/qcom/lpm-stats.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/power/qcom/lpm-stats.c b/drivers/power/qcom/lpm-stats.c index 7f1967d432b..4bbc3db9dcb 100644 --- a/drivers/power/qcom/lpm-stats.c +++ b/drivers/power/qcom/lpm-stats.c @@ -682,9 +682,10 @@ static void cleanup_stats(struct lpm_stats *stats) { struct list_head *centry = NULL; struct lpm_stats *pos = NULL; + struct lpm_stats *n = NULL; centry = &stats->child; - list_for_each_entry_reverse(pos, centry, sibling) { + list_for_each_entry_safe_reverse(pos, n, centry, sibling) { if (!list_empty(&pos->child)) cleanup_stats(pos); From 161ff70992b8a0ec53ea8aa4550fdb410de5fb2f Mon Sep 17 00:00:00 2001 From: Sreelakshmi Gownipalli Date: Tue, 23 Jan 2018 13:11:41 -0800 Subject: [PATCH 07/53] diag: Protect the decrement of number of diag clients In diagchar_open() protect the decrement of number of diag clients so that there will be no race conditions while reading the value from other functions. Bug: 79421261 Change-Id: I0e2fb5331eec9c7bba39e7d881b69559256833a3 Signed-off-by: Sreelakshmi Gownipalli --- drivers/char/diag/diagchar_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index 21799ab0703..4ebaff20e09 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -363,8 +363,8 @@ static int diagchar_open(struct inode *inode, struct file *file) return -ENOMEM; fail: - mutex_unlock(&driver->diagchar_mutex); driver->num_clients--; + mutex_unlock(&driver->diagchar_mutex); pr_err_ratelimited("diag: Insufficient memory for new client"); return -ENOMEM; } From 971db75c2bfc7780aa3268e1ea9bf603ef015359 Mon Sep 17 00:00:00 2001 From: Harsh Sahu Date: Fri, 23 Mar 2018 00:15:52 -0700 Subject: [PATCH 08/53] msm: mdss: check buffer size before writing to user buffer Check the number of bytes to copy against the size of the user buffer before copy to user to avoid buffer overflow. Bug: 79422277 Change-Id: Icdd3d4e755deca19fa431e903620bd9e4c701c89 Signed-off-by: Harsh Sahu Signed-off-by: Siqi Lin --- drivers/video/msm/mdss/mdss_debug_xlog.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/video/msm/mdss/mdss_debug_xlog.c b/drivers/video/msm/mdss/mdss_debug_xlog.c index 488f6ab053f..3406a5f3df3 100644 --- a/drivers/video/msm/mdss/mdss_debug_xlog.c +++ b/drivers/video/msm/mdss/mdss_debug_xlog.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2016, 2018, 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 @@ -683,6 +683,11 @@ static ssize_t mdss_xlog_dump_read(struct file *file, char __user *buff, if (__mdss_xlog_dump_calc_range()) { len = mdss_xlog_dump_entry(xlog_buf, MDSS_XLOG_BUF_MAX); + if (len < 0 || len > count) { + pr_err("len is more than the size of user buffer\n"); + return 0; + } + if (copy_to_user(buff, xlog_buf, len)) return -EFAULT; *ppos += len; From 248fe681ed612a084d0a40f11c5f0c54adf93f7e Mon Sep 17 00:00:00 2001 From: Rashi Bindra Date: Mon, 19 Mar 2018 14:07:27 +0530 Subject: [PATCH 09/53] msm: mdss: Fix for wrong length in copy_to_user The caller could have a small buf passed (less then < blen). Since, the length of count and blen is not checked, it can write beyond the end of buf. Bug: 79422409 Change-Id: I9138cd742b6166937f3cc1cbf1af36f280c94bdb Signed-off-by: Rashi Bindra --- drivers/video/msm/mdss/mdss_dsi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c index f8eff56e1b5..88d00cb014c 100644 --- a/drivers/video/msm/mdss/mdss_dsi.c +++ b/drivers/video/msm/mdss/mdss_dsi.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, 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 @@ -664,7 +664,7 @@ static ssize_t mdss_dsi_cmd_state_read(struct file *file, char __user *buf, if (blen < 0) return 0; - if (copy_to_user(buf, buffer, blen)) + if (copy_to_user(buf, buffer, min(count, (size_t)blen+1))) return -EFAULT; *ppos += blen; From ebc602ecc21c4e16320e7027a70b06f28396b7f7 Mon Sep 17 00:00:00 2001 From: Guillaume Nault Date: Fri, 31 Mar 2017 13:02:25 +0200 Subject: [PATCH 10/53] BACKPORT: l2tp: fix race in l2tp_recv_common() Taking a reference on sessions in l2tp_recv_common() is racy; this has to be done by the callers. To this end, a new function is required (l2tp_session_get()) to atomically lookup a session and take a reference on it. Callers then have to manually drop this reference. Change-Id: Ib48214a90805c6fa20229fdb37a9d3cbeb2aef3a Fixes: fd558d186df2 ("l2tp: Split pppol2tp patch into separate l2tp and ppp parts") Signed-off-by: Guillaume Nault Signed-off-by: David S. Miller Bug: 38159931 --- net/l2tp/l2tp_core.c | 73 ++++++++++++++++++++++++++++++++++++-------- net/l2tp/l2tp_core.h | 3 ++ net/l2tp/l2tp_ip.c | 17 ++++++++--- net/l2tp/l2tp_ip6.c | 18 ++++++++--- 4 files changed, 88 insertions(+), 23 deletions(-) diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index b5f3c175331..d0d68258afa 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -278,6 +278,55 @@ struct l2tp_session *l2tp_session_find(struct net *net, struct l2tp_tunnel *tunn } EXPORT_SYMBOL_GPL(l2tp_session_find); +/* Like l2tp_session_find() but takes a reference on the returned session. + * Optionally calls session->ref() too if do_ref is true. + */ +struct l2tp_session *l2tp_session_get(struct net *net, + struct l2tp_tunnel *tunnel, + u32 session_id, bool do_ref) +{ + struct hlist_head *session_list; + struct l2tp_session *session; + + if (!tunnel) { + struct l2tp_net *pn = l2tp_pernet(net); + + session_list = l2tp_session_id_hash_2(pn, session_id); + + rcu_read_lock_bh(); + hlist_for_each_entry_rcu(session, session_list, global_hlist) { + if (session->session_id == session_id) { + l2tp_session_inc_refcount(session); + if (do_ref && session->ref) + session->ref(session); + rcu_read_unlock_bh(); + + return session; + } + } + rcu_read_unlock_bh(); + + return NULL; + } + + session_list = l2tp_session_id_hash(tunnel, session_id); + read_lock_bh(&tunnel->hlist_lock); + hlist_for_each_entry(session, session_list, hlist) { + if (session->session_id == session_id) { + l2tp_session_inc_refcount(session); + if (do_ref && session->ref) + session->ref(session); + read_unlock_bh(&tunnel->hlist_lock); + + return session; + } + } + read_unlock_bh(&tunnel->hlist_lock); + + return NULL; +} +EXPORT_SYMBOL_GPL(l2tp_session_get); + struct l2tp_session *l2tp_session_find_nth(struct l2tp_tunnel *tunnel, int nth) { int hash; @@ -633,6 +682,9 @@ static int l2tp_recv_data_seq(struct l2tp_session *session, struct sk_buff *skb) * a data (not control) frame before coming here. Fields up to the * session-id have already been parsed and ptr points to the data * after the session-id. + * + * session->ref() must have been called prior to l2tp_recv_common(). + * session->deref() will be called automatically after skb is processed. */ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, unsigned char *ptr, unsigned char *optr, u16 hdrflags, @@ -642,14 +694,6 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, int offset; u32 ns, nr; - /* The ref count is increased since we now hold a pointer to - * the session. Take care to decrement the refcnt when exiting - * this function from now on... - */ - l2tp_session_inc_refcount(session); - if (session->ref) - (*session->ref)(session); - /* Parse and check optional cookie */ if (session->peer_cookie_len > 0) { if (memcmp(ptr, &session->peer_cookie[0], session->peer_cookie_len)) { @@ -802,8 +846,6 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, /* Try to dequeue as many skbs from reorder_q as we can. */ l2tp_recv_dequeue(session); - l2tp_session_dec_refcount(session); - return; discard: @@ -812,8 +854,6 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, if (session->deref) (*session->deref)(session); - - l2tp_session_dec_refcount(session); } EXPORT_SYMBOL(l2tp_recv_common); @@ -920,8 +960,14 @@ static int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb, } /* Find the session context */ - session = l2tp_session_find(tunnel->l2tp_net, tunnel, session_id); + session = l2tp_session_get(tunnel->l2tp_net, tunnel, session_id, true); if (!session || !session->recv_skb) { + if (session) { + if (session->deref) + session->deref(session); + l2tp_session_dec_refcount(session); + } + /* Not found? Pass to userspace to deal with */ l2tp_info(tunnel, L2TP_MSG_DATA, "%s: no session found (%u/%u). Passing up.\n", @@ -930,6 +976,7 @@ static int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb, } l2tp_recv_common(session, skb, ptr, optr, hdrflags, length, payload_hook); + l2tp_session_dec_refcount(session); return 0; diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h index 1c1a033a546..67cbbe58b4f 100644 --- a/net/l2tp/l2tp_core.h +++ b/net/l2tp/l2tp_core.h @@ -243,6 +243,9 @@ static inline struct l2tp_tunnel *l2tp_sock_to_tunnel(struct sock *sk) return tunnel; } +struct l2tp_session *l2tp_session_get(struct net *net, + struct l2tp_tunnel *tunnel, + u32 session_id, bool do_ref); struct l2tp_session *l2tp_session_find(struct net *net, struct l2tp_tunnel *tunnel, u32 session_id); diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c index 85285f46046..d30f5c03d72 100644 --- a/net/l2tp/l2tp_ip.c +++ b/net/l2tp/l2tp_ip.c @@ -142,19 +142,19 @@ static int l2tp_ip_recv(struct sk_buff *skb) } /* Ok, this is a data packet. Lookup the session. */ - session = l2tp_session_find(net, NULL, session_id); - if (session == NULL) + session = l2tp_session_get(net, NULL, session_id, true); + if (!session) goto discard; tunnel = session->tunnel; - if (tunnel == NULL) - goto discard; + if (!tunnel) + goto discard_sess; /* Trace packet contents, if enabled */ if (tunnel->debug & L2TP_MSG_DATA) { length = min(32u, skb->len); if (!pskb_may_pull(skb, length)) - goto discard; + goto discard_sess; /* Point to L2TP header */ optr = ptr = skb->data; @@ -164,6 +164,7 @@ static int l2tp_ip_recv(struct sk_buff *skb) } l2tp_recv_common(session, skb, ptr, optr, 0, skb->len, tunnel->recv_payload_hook); + l2tp_session_dec_refcount(session); return 0; @@ -199,6 +200,12 @@ static int l2tp_ip_recv(struct sk_buff *skb) return sk_receive_skb(sk, skb, 1); +discard_sess: + if (session->deref) + session->deref(session); + l2tp_session_dec_refcount(session); + goto discard; + discard_put: sock_put(sk); diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c index 0bd7b17f455..34deea1a875 100644 --- a/net/l2tp/l2tp_ip6.c +++ b/net/l2tp/l2tp_ip6.c @@ -153,19 +153,19 @@ static int l2tp_ip6_recv(struct sk_buff *skb) } /* Ok, this is a data packet. Lookup the session. */ - session = l2tp_session_find(&init_net, NULL, session_id); - if (session == NULL) + session = l2tp_session_get(&init_net, NULL, session_id, true); + if (!session) goto discard; tunnel = session->tunnel; - if (tunnel == NULL) - goto discard; + if (!tunnel) + goto discard_sess; /* Trace packet contents, if enabled */ if (tunnel->debug & L2TP_MSG_DATA) { length = min(32u, skb->len); if (!pskb_may_pull(skb, length)) - goto discard; + goto discard_sess; /* Point to L2TP header */ optr = ptr = skb->data; @@ -176,6 +176,8 @@ static int l2tp_ip6_recv(struct sk_buff *skb) l2tp_recv_common(session, skb, ptr, optr, 0, skb->len, tunnel->recv_payload_hook); + l2tp_session_dec_refcount(session); + return 0; pass_up: @@ -211,6 +213,12 @@ static int l2tp_ip6_recv(struct sk_buff *skb) return sk_receive_skb(sk, skb, 1); +discard_sess: + if (session->deref) + session->deref(session); + l2tp_session_dec_refcount(session); + goto discard; + discard_put: sock_put(sk); From 768347b3528576aa9b6ba83f6c59819e7e413913 Mon Sep 17 00:00:00 2001 From: Guillaume Nault Date: Fri, 31 Mar 2017 13:02:27 +0200 Subject: [PATCH 11/53] BACKPORT: l2tp: fix duplicate session creation l2tp_session_create() relies on its caller for checking for duplicate sessions. This is racy since a session can be concurrently inserted after the caller's verification. Fix this by letting l2tp_session_create() verify sessions uniqueness upon insertion. Callers need to be adapted to check for l2tp_session_create()'s return code instead of calling l2tp_session_find(). pppol2tp_connect() is a bit special because it has to work on existing sessions (if they're not connected) or to create a new session if none is found. When acting on a preexisting session, a reference must be held or it could go away on us. So we have to use l2tp_session_get() instead of l2tp_session_find() and drop the reference before exiting. Change-Id: I650f6ea597bef06a429f41e0f533c8d4fab5e325 Fixes: d9e31d17ceba ("l2tp: Add L2TP ethernet pseudowire support") Fixes: fd558d186df2 ("l2tp: Split pppol2tp patch into separate l2tp and ppp parts") Signed-off-by: Guillaume Nault Signed-off-by: David S. Miller Bug: 38159931 --- net/l2tp/l2tp_core.c | 70 +++++++++++++++++++++++++++++++++----------- net/l2tp/l2tp_eth.c | 10 ++----- net/l2tp/l2tp_ppp.c | 60 ++++++++++++++++++------------------- 3 files changed, 84 insertions(+), 56 deletions(-) diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index d0d68258afa..fcfaa43e3a1 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -374,6 +374,48 @@ struct l2tp_session *l2tp_session_find_by_ifname(struct net *net, char *ifname) } EXPORT_SYMBOL_GPL(l2tp_session_find_by_ifname); +static int l2tp_session_add_to_tunnel(struct l2tp_tunnel *tunnel, + struct l2tp_session *session) +{ + struct l2tp_session *session_walk; + struct hlist_head *g_head; + struct hlist_head *head; + struct l2tp_net *pn; + + head = l2tp_session_id_hash(tunnel, session->session_id); + + write_lock_bh(&tunnel->hlist_lock); + hlist_for_each_entry(session_walk, head, hlist) + if (session_walk->session_id == session->session_id) + goto exist; + + if (tunnel->version == L2TP_HDR_VER_3) { + pn = l2tp_pernet(tunnel->l2tp_net); + g_head = l2tp_session_id_hash_2(l2tp_pernet(tunnel->l2tp_net), + session->session_id); + + spin_lock_bh(&pn->l2tp_session_hlist_lock); + hlist_for_each_entry(session_walk, g_head, global_hlist) + if (session_walk->session_id == session->session_id) + goto exist_glob; + + hlist_add_head_rcu(&session->global_hlist, g_head); + spin_unlock_bh(&pn->l2tp_session_hlist_lock); + } + + hlist_add_head(&session->hlist, head); + write_unlock_bh(&tunnel->hlist_lock); + + return 0; + +exist_glob: + spin_unlock_bh(&pn->l2tp_session_hlist_lock); +exist: + write_unlock_bh(&tunnel->hlist_lock); + + return -EEXIST; +} + /* Lookup a tunnel by id */ struct l2tp_tunnel *l2tp_tunnel_find(struct net *net, u32 tunnel_id) @@ -1786,6 +1828,7 @@ EXPORT_SYMBOL_GPL(l2tp_session_set_header_len); struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg) { struct l2tp_session *session; + int err; session = kzalloc(sizeof(struct l2tp_session) + priv_size, GFP_KERNEL); if (session != NULL) { @@ -1841,6 +1884,13 @@ struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunn l2tp_session_set_header_len(session, tunnel->version); + err = l2tp_session_add_to_tunnel(tunnel, session); + if (err) { + kfree(session); + + return ERR_PTR(err); + } + /* Bump the reference count. The session context is deleted * only when this drops to zero. */ @@ -1850,28 +1900,14 @@ struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunn /* Ensure tunnel socket isn't deleted */ sock_hold(tunnel->sock); - /* Add session to the tunnel's hash list */ - write_lock_bh(&tunnel->hlist_lock); - hlist_add_head(&session->hlist, - l2tp_session_id_hash(tunnel, session_id)); - write_unlock_bh(&tunnel->hlist_lock); - - /* And to the global session list if L2TPv3 */ - if (tunnel->version != L2TP_HDR_VER_2) { - struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net); - - spin_lock_bh(&pn->l2tp_session_hlist_lock); - hlist_add_head_rcu(&session->global_hlist, - l2tp_session_id_hash_2(pn, session_id)); - spin_unlock_bh(&pn->l2tp_session_hlist_lock); - } - /* Ignore management session in session count value */ if (session->session_id != 0) atomic_inc(&l2tp_session_count); + + return session; } - return session; + return ERR_PTR(-ENOMEM); } EXPORT_SYMBOL_GPL(l2tp_session_create); diff --git a/net/l2tp/l2tp_eth.c b/net/l2tp/l2tp_eth.c index edb78e69efe..899df2ea35e 100644 --- a/net/l2tp/l2tp_eth.c +++ b/net/l2tp/l2tp_eth.c @@ -222,12 +222,6 @@ static int l2tp_eth_create(struct net *net, u32 tunnel_id, u32 session_id, u32 p goto out; } - session = l2tp_session_find(net, tunnel, session_id); - if (session) { - rc = -EEXIST; - goto out; - } - if (cfg->ifname) { dev = dev_get_by_name(net, cfg->ifname); if (dev) { @@ -241,8 +235,8 @@ static int l2tp_eth_create(struct net *net, u32 tunnel_id, u32 session_id, u32 p session = l2tp_session_create(sizeof(*spriv), tunnel, session_id, peer_session_id, cfg); - if (!session) { - rc = -ENOMEM; + if (IS_ERR(session)) { + rc = PTR_ERR(session); goto out; } diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c index 447843b24d7..ab86ccd13b2 100644 --- a/net/l2tp/l2tp_ppp.c +++ b/net/l2tp/l2tp_ppp.c @@ -602,6 +602,7 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr, int error = 0; u32 tunnel_id, peer_tunnel_id; u32 session_id, peer_session_id; + bool drop_refcnt = false; int ver = 2; int fd; @@ -703,36 +704,36 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr, if (tunnel->peer_tunnel_id == 0) tunnel->peer_tunnel_id = peer_tunnel_id; - /* Create session if it doesn't already exist. We handle the - * case where a session was previously created by the netlink - * interface by checking that the session doesn't already have - * a socket and its tunnel socket are what we expect. If any - * of those checks fail, return EEXIST to the caller. - */ - session = l2tp_session_find(sock_net(sk), tunnel, session_id); - if (session == NULL) { - /* Default MTU must allow space for UDP/L2TP/PPP - * headers. + session = l2tp_session_get(sock_net(sk), tunnel, session_id, false); + if (session) { + drop_refcnt = true; + ps = l2tp_session_priv(session); + + /* Using a pre-existing session is fine as long as it hasn't + * been connected yet. */ - cfg.mtu = cfg.mru = 1500 - PPPOL2TP_HEADER_OVERHEAD; + if (ps->sock) { + error = -EEXIST; + goto end; + } - /* Allocate and initialize a new session context. */ - session = l2tp_session_create(sizeof(struct pppol2tp_session), - tunnel, session_id, - peer_session_id, &cfg); - if (session == NULL) { - error = -ENOMEM; + /* consistency checks */ + if (ps->tunnel_sock != tunnel->sock) { + error = -EEXIST; goto end; } } else { - ps = l2tp_session_priv(session); - error = -EEXIST; - if (ps->sock != NULL) - goto end; + /* Default MTU must allow space for UDP/L2TP/PPP headers */ + cfg.mtu = 1500 - PPPOL2TP_HEADER_OVERHEAD; + cfg.mru = cfg.mtu; - /* consistency checks */ - if (ps->tunnel_sock != tunnel->sock) + session = l2tp_session_create(sizeof(struct pppol2tp_session), + tunnel, session_id, + peer_session_id, &cfg); + if (IS_ERR(session)) { + error = PTR_ERR(session); goto end; + } } /* Associate session with its PPPoL2TP socket */ @@ -797,6 +798,8 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr, session->name); end: + if (drop_refcnt) + l2tp_session_dec_refcount(session); release_sock(sk); return error; @@ -824,12 +827,6 @@ static int pppol2tp_session_create(struct net *net, u32 tunnel_id, u32 session_i if (tunnel->sock == NULL) goto out; - /* Check that this session doesn't already exist */ - error = -EEXIST; - session = l2tp_session_find(net, tunnel, session_id); - if (session != NULL) - goto out; - /* Default MTU values. */ if (cfg->mtu == 0) cfg->mtu = 1500 - PPPOL2TP_HEADER_OVERHEAD; @@ -837,12 +834,13 @@ static int pppol2tp_session_create(struct net *net, u32 tunnel_id, u32 session_i cfg->mru = cfg->mtu; /* Allocate and initialize a new session context. */ - error = -ENOMEM; session = l2tp_session_create(sizeof(struct pppol2tp_session), tunnel, session_id, peer_session_id, cfg); - if (session == NULL) + if (IS_ERR(session)) { + error = PTR_ERR(session); goto out; + } ps = l2tp_session_priv(session); ps->tunnel_sock = tunnel->sock; From 7a420e2f970526f97aa8f2b656bba9f692a4cda8 Mon Sep 17 00:00:00 2001 From: Guillaume Nault Date: Fri, 25 Aug 2017 16:22:17 +0200 Subject: [PATCH 12/53] BACKPORT: l2tp: initialise session's refcount before making it reachable Sessions must be fully initialised before calling l2tp_session_add_to_tunnel(). Otherwise, there's a short time frame where partially initialised sessions can be accessed by external users. Change-Id: I44a845037cdf6556aaec7b41103a33638bba1734 Fixes: dbdbc73b4478 ("l2tp: fix duplicate session creation") Signed-off-by: Guillaume Nault Signed-off-by: David S. Miller Bug: 38159931 --- net/l2tp/l2tp_core.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index fcfaa43e3a1..191e774ed9a 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -1884,6 +1884,8 @@ struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunn l2tp_session_set_header_len(session, tunnel->version); + l2tp_session_inc_refcount(session); + err = l2tp_session_add_to_tunnel(tunnel, session); if (err) { kfree(session); @@ -1891,10 +1893,6 @@ struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunn return ERR_PTR(err); } - /* Bump the reference count. The session context is deleted - * only when this drops to zero. - */ - l2tp_session_inc_refcount(session); l2tp_tunnel_inc_refcount(tunnel); /* Ensure tunnel socket isn't deleted */ From e43dd52476725455c1c64835484c14d605239e0f Mon Sep 17 00:00:00 2001 From: Guillaume Nault Date: Fri, 1 Sep 2017 17:58:48 +0200 Subject: [PATCH 13/53] BACKPORT: l2tp: prevent creation of sessions on terminated tunnels l2tp_tunnel_destruct() sets tunnel->sock to NULL, then removes the tunnel from the pernet list and finally closes all its sessions. Therefore, it's possible to add a session to a tunnel that is still reachable, but for which tunnel->sock has already been reset. This can make l2tp_session_create() dereference a NULL pointer when calling sock_hold(tunnel->sock). This patch adds the .acpt_newsess field to struct l2tp_tunnel, which is used by l2tp_tunnel_closeall() to prevent addition of new sessions to tunnels. Resetting tunnel->sock is done after l2tp_tunnel_closeall() returned, so that l2tp_session_add_to_tunnel() can safely take a reference on it when .acpt_newsess is true. The .acpt_newsess field is modified in l2tp_tunnel_closeall(), rather than in l2tp_tunnel_destruct(), so that it benefits all tunnel removal mechanisms. E.g. on UDP tunnels, a session could be added to a tunnel after l2tp_udp_encap_destroy() proceeded. This would prevent the tunnel from being removed because of the references held by this new session on the tunnel and its socket. Even though the session could be removed manually later on, this defeats the purpose of commit 9980d001cec8 ("l2tp: add udp encap socket destroy handler"). Change-Id: If74a32a9c65daa2ac513d59bd24339e9dcec1d16 Fixes: fd558d186df2 ("l2tp: Split pppol2tp patch into separate l2tp and ppp parts") Signed-off-by: Guillaume Nault Signed-off-by: David S. Miller Bug: 38159931 --- net/l2tp/l2tp_core.c | 41 ++++++++++++++++++++++++++++------------- net/l2tp/l2tp_core.h | 4 ++++ 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index 191e774ed9a..4a0e83fe2f3 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -381,13 +381,21 @@ static int l2tp_session_add_to_tunnel(struct l2tp_tunnel *tunnel, struct hlist_head *g_head; struct hlist_head *head; struct l2tp_net *pn; + int err; head = l2tp_session_id_hash(tunnel, session->session_id); write_lock_bh(&tunnel->hlist_lock); + if (!tunnel->acpt_newsess) { + err = -ENODEV; + goto err_tlock; + } + hlist_for_each_entry(session_walk, head, hlist) - if (session_walk->session_id == session->session_id) - goto exist; + if (session_walk->session_id == session->session_id) { + err = -EEXIST; + goto err_tlock; + } if (tunnel->version == L2TP_HDR_VER_3) { pn = l2tp_pernet(tunnel->l2tp_net); @@ -395,12 +403,21 @@ static int l2tp_session_add_to_tunnel(struct l2tp_tunnel *tunnel, session->session_id); spin_lock_bh(&pn->l2tp_session_hlist_lock); + hlist_for_each_entry(session_walk, g_head, global_hlist) - if (session_walk->session_id == session->session_id) - goto exist_glob; + if (session_walk->session_id == session->session_id) { + err = -EEXIST; + goto err_tlock_pnlock; + } + l2tp_tunnel_inc_refcount(tunnel); + sock_hold(tunnel->sock); hlist_add_head_rcu(&session->global_hlist, g_head); + spin_unlock_bh(&pn->l2tp_session_hlist_lock); + } else { + l2tp_tunnel_inc_refcount(tunnel); + sock_hold(tunnel->sock); } hlist_add_head(&session->hlist, head); @@ -408,12 +425,12 @@ static int l2tp_session_add_to_tunnel(struct l2tp_tunnel *tunnel, return 0; -exist_glob: +err_tlock_pnlock: spin_unlock_bh(&pn->l2tp_session_hlist_lock); -exist: +err_tlock: write_unlock_bh(&tunnel->hlist_lock); - return -EEXIST; + return err; } /* Lookup a tunnel by id @@ -1303,7 +1320,6 @@ static void l2tp_tunnel_destruct(struct sock *sk) /* Remove hooks into tunnel socket */ sk->sk_destruct = tunnel->old_sk_destruct; sk->sk_user_data = NULL; - tunnel->sock = NULL; /* Remove the tunnel struct from the tunnel list */ pn = l2tp_pernet(tunnel->l2tp_net); @@ -1313,6 +1329,8 @@ static void l2tp_tunnel_destruct(struct sock *sk) atomic_dec(&l2tp_tunnel_count); l2tp_tunnel_closeall(tunnel); + + tunnel->sock = NULL; l2tp_tunnel_dec_refcount(tunnel); /* Call the original destructor */ @@ -1337,6 +1355,7 @@ void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel) tunnel->name); write_lock_bh(&tunnel->hlist_lock); + tunnel->acpt_newsess = false; for (hash = 0; hash < L2TP_HASH_SIZE; hash++) { again: hlist_for_each_safe(walk, tmp, &tunnel->session_hlist[hash]) { @@ -1647,6 +1666,7 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32 tunnel->magic = L2TP_TUNNEL_MAGIC; sprintf(&tunnel->name[0], "tunl %u", tunnel_id); rwlock_init(&tunnel->hlist_lock); + tunnel->acpt_newsess = true; /* The net we belong to */ tunnel->l2tp_net = net; @@ -1893,11 +1913,6 @@ struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunn return ERR_PTR(err); } - l2tp_tunnel_inc_refcount(tunnel); - - /* Ensure tunnel socket isn't deleted */ - sock_hold(tunnel->sock); - /* Ignore management session in session count value */ if (session->session_id != 0) atomic_inc(&l2tp_session_count); diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h index 67cbbe58b4f..62934876b31 100644 --- a/net/l2tp/l2tp_core.h +++ b/net/l2tp/l2tp_core.h @@ -174,6 +174,10 @@ struct l2tp_tunnel { struct rcu_head rcu; rwlock_t hlist_lock; /* protect session_hlist */ + bool acpt_newsess; /* Indicates whether this + * tunnel accepts new sessions. + * Protected by hlist_lock. + */ struct hlist_head session_hlist[L2TP_HASH_SIZE]; /* hashed list of sessions, * hashed by id */ From 20457601e303c2dcd203c4949bf31ab7e4350892 Mon Sep 17 00:00:00 2001 From: Bala Venkatesh Date: Mon, 19 Feb 2018 15:31:00 +0530 Subject: [PATCH 14/53] qcacld-2.0: Fix UAF in the function wlan_hdd_execute_remain_on_channel In function wlan_hdd_execute_remain_on_channel after calling sme_remain_on_channel Buffer pointed by "pRemainChanCtx" may be freed in other thread "wlan_hdd_remain_on_channel_callback". UAF will happen on when accessing "pRemainChanCtx->rem_on_chan_request". Access pRemainChanCtx only when it is not NULL. Change-Id: I32696ca9d88bc55f7c9841c7d602f363c35ed49f CRs-Fixed: 2189054 Bug: 109741735 Signed-off-by: Srinivas Girigowda --- drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_p2p.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_p2p.c b/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_p2p.c index 874926ce991..26570446177 100644 --- a/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_p2p.c +++ b/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_p2p.c @@ -1145,12 +1145,18 @@ static int wlan_hdd_execute_remain_on_channel(hdd_adapter_t *pAdapter, return -EINVAL; } - if (REMAIN_ON_CHANNEL_REQUEST == pRemainChanCtx->rem_on_chan_request) { + mutex_lock(&cfgState->remain_on_chan_ctx_lock); + pRemainChanCtx = cfgState->remain_on_chan_ctx; + if ((pRemainChanCtx)&&(REMAIN_ON_CHANNEL_REQUEST == + pRemainChanCtx->rem_on_chan_request)) { + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); if (eHAL_STATUS_SUCCESS != sme_RegisterMgmtFrame( WLAN_HDD_GET_HAL_CTX(pAdapter), sessionId, (SIR_MAC_MGMT_FRAME << 2) | (SIR_MAC_MGMT_PROBE_REQ << 4), NULL, 0)) hddLog(LOGE, FL("sme_RegisterMgmtFrame returned failure")); + } else { + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); } } else if ( ( WLAN_HDD_SOFTAP== pAdapter->device_mode ) || From d121a707155cf1524fc541a03decca4691e016a7 Mon Sep 17 00:00:00 2001 From: Hanumanth Reddy Pothula Date: Tue, 3 Apr 2018 17:19:54 +0530 Subject: [PATCH 15/53] qcacld-2.0: Resolve possible OOB while posting SET PASSPOINT WMA event qcacld-3.0 to qcacld-2.0 propagation Presently, while processing SET_PASSPOINT_LIST vendor command HDD is not making sure realm string passed by upper-layer is NULL terminated, this may lead to buffer overflow as strlen is used to get realm string length to construct PASSPOINT WMA command. Make sure realm is NULL terminated before passing the same to down layers. Bug: 109741777 Change-Id: I417f2b89dc219664afe5deac00dc361cac4048d6 CRs-Fixed: 2217476 Signed-off-by: Kumar Anand --- .../CORE/HDD/src/wlan_hdd_cfg80211.c | 47 ++++++++++++------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_cfg80211.c b/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_cfg80211.c index af92a850515..f8c88184ab6 100644 --- a/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_cfg80211.c +++ b/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_cfg80211.c @@ -4820,6 +4820,13 @@ static int wlan_hdd_cfg80211_set_epno_list(struct wiphy *wiphy, return ret; } +#define PARAM_ID QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ID +#define PARAM_REALM QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_REALM +#define PARAM_ROAM_ID \ + QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_CNSRTM_ID +#define PARAM_ROAM_PLMN \ + QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_PLMN + /** * hdd_extscan_passpoint_fill_network_list() - passpoint fill network list * @hddctx: HDD context @@ -4838,7 +4845,8 @@ static int hdd_extscan_passpoint_fill_network_list( { struct nlattr *network[QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1]; struct nlattr *networks; - int rem1, len; + int rem1; + size_t len; uint8_t index; uint32_t expected_networks; @@ -4862,38 +4870,37 @@ static int hdd_extscan_passpoint_fill_network_list( } /* Parse and fetch identifier */ - if (!network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ID]) { + if (!network[PARAM_ID]) { hddLog(LOGE, FL("attr passpoint id failed")); return -EINVAL; } req_msg->networks[index].id = nla_get_u32( - network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ID]); + network[PARAM_ID]); hddLog(LOG1, FL("Id %u"), req_msg->networks[index].id); /* Parse and fetch realm */ - if (!network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_REALM]) { + if (!network[PARAM_REALM]) { hddLog(LOGE, FL("attr realm failed")); return -EINVAL; } - len = nla_len( - network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_REALM]); - if (len < 0 || len > SIR_PASSPOINT_REALM_LEN) { - hddLog(LOGE, FL("Invalid realm size %d"), len); + len = nla_strlcpy(req_msg->networks[index].realm, + network[PARAM_REALM], + SIR_PASSPOINT_REALM_LEN); + /* Don't send partial realm to firmware */ + if (len >= SIR_PASSPOINT_REALM_LEN) { + hddLog(LOGE, FL("user passed invalid realm, len:%zu"), + len); return -EINVAL; } - vos_mem_copy(req_msg->networks[index].realm, - nla_data(network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_REALM]), - len); - hddLog(LOG1, FL("realm len %d"), len); hddLog(LOG1, FL("realm: %s"), req_msg->networks[index].realm); - /* Parse and fetch roaming consortium ids */ - if (!network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_CNSRTM_ID]) { + /* Parse and fetch roaming consortium ids */ + if (!network[PARAM_ROAM_ID]) { hddLog(LOGE, FL("attr roaming consortium ids failed")); return -EINVAL; } nla_memcpy(&req_msg->networks[index].roaming_consortium_ids, - network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_CNSRTM_ID], + network[PARAM_ROAM_ID], sizeof(req_msg->networks[0].roaming_consortium_ids)); hddLog(LOG1, FL("roaming consortium ids")); VOS_TRACE_HEX_DUMP(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, @@ -4901,12 +4908,12 @@ static int hdd_extscan_passpoint_fill_network_list( sizeof(req_msg->networks[0].roaming_consortium_ids)); /* Parse and fetch plmn */ - if (!network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_PLMN]) { + if (!network[PARAM_ROAM_PLMN]) { hddLog(LOGE, FL("attr plmn failed")); return -EINVAL; } nla_memcpy(&req_msg->networks[index].plmn, - network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_PLMN], + network[PARAM_ROAM_PLMN], SIR_PASSPOINT_PLMN_LEN); hddLog(LOG1, FL("plmn %02x:%02x:%02x"), req_msg->networks[index].plmn[0], @@ -5142,6 +5149,12 @@ static int wlan_hdd_cfg80211_reset_passpoint_list(struct wiphy *wiphy, return ret; } + +#undef PARAM_ID +#undef PARAM_REALM +#undef PARAM_ROAM_ID +#undef PARAM_ROAM_PLMN + #endif /* FEATURE_WLAN_EXTSCAN */ /** From 44003f41dec93aa4276028ab2ff9892e8679c758 Mon Sep 17 00:00:00 2001 From: Aditya Bavanari Date: Fri, 6 Apr 2018 18:15:43 +0530 Subject: [PATCH 16/53] voice_svc: Avoid double free in voice_svc driver voice_svc_dev is allocated as a device managed resource and need not be freed since it is freed automatically. Remove the logic to free voice_svc_dev in probe failure and remove functions to avoid double free. CRs-Fixed: 2204285 Bug: 109741750 Change-Id: If4f9ca840b00448b987f5ce443f66b0923b01969 Signed-off-by: Aditya Bavanari --- drivers/soc/qcom/qdsp6v2/voice_svc.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/soc/qcom/qdsp6v2/voice_svc.c b/drivers/soc/qcom/qdsp6v2/voice_svc.c index dcb3c247791..8cd2ed6e2fa 100644 --- a/drivers/soc/qcom/qdsp6v2/voice_svc.c +++ b/drivers/soc/qcom/qdsp6v2/voice_svc.c @@ -742,7 +742,7 @@ static int voice_svc_probe(struct platform_device *pdev) if (ret) { pr_err("%s: Failed to alloc chrdev\n", __func__); ret = -ENODEV; - goto chrdev_err; + goto done; } voice_svc_dev->major = MAJOR(device_num); @@ -788,8 +788,6 @@ static int voice_svc_probe(struct platform_device *pdev) class_destroy(voice_svc_class); class_err: unregister_chrdev_region(0, MINOR_NUMBER); -chrdev_err: - kfree(voice_svc_dev); done: return ret; } @@ -803,7 +801,6 @@ static int voice_svc_remove(struct platform_device *pdev) device_destroy(voice_svc_class, device_num); class_destroy(voice_svc_class); unregister_chrdev_region(0, MINOR_NUMBER); - kfree(voice_svc_dev); return 0; } From 6568e2639e3481020fdfb4ee159b83d58ac84f87 Mon Sep 17 00:00:00 2001 From: Tharun Kumar Merugu Date: Mon, 2 Jul 2018 15:53:04 +0530 Subject: [PATCH 17/53] msm: ADSPRPC: Assign memory to VMID_SSC_Q6 Assign complete adsp_mem region to VMID_SSC_Q6 during device boot. Bug: 110817575 Change-Id: Ifcc306f59429a6391396e6c710e80be5b0ef716c Acked-by: Himateja Reddy Signed-off-by: Tharun Kumar Merugu --- .../bindings/qdsp/msm-mdsprpc-mem.txt | 24 ++++++++++ arch/arm/boot/dts/qcom/msm8996.dtsi | 7 ++- drivers/char/adsprpc.c | 47 ++++++++++++++++++- 3 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 Documentation/devicetree/bindings/qdsp/msm-mdsprpc-mem.txt diff --git a/Documentation/devicetree/bindings/qdsp/msm-mdsprpc-mem.txt b/Documentation/devicetree/bindings/qdsp/msm-mdsprpc-mem.txt new file mode 100644 index 00000000000..2a5fc0ff17d --- /dev/null +++ b/Documentation/devicetree/bindings/qdsp/msm-mdsprpc-mem.txt @@ -0,0 +1,24 @@ +Qualcomm Technologies, Inc. FastRPC MDSP CMA Heap + +The MSM MDSPRPC memory device allocates CMA memory, for sharing memory +of FastRPC buffers to remote processor(MDSP). + +Required properties: +-compatible: Must be "qcom,msm-mdsprpc-mem-region" +-memory-region: A phandle that points to a memory heap where the +heap memory is allocated + +Example: + qcom,mdsprpc-mem { + compatible = "qcom,msm-mdsprpc-mem-region"; + memory-region = <&mdsp_mem>; + }; + +Ion Heap: + +Ion heap allows for sharing of buffers between different processors +and between user space and kernel space. +(see Documentation/devicetree/bindings/arm/msm/msm_ion.txt). + +Required properties for Ion heap: +- compatible : "qcom,msm-ion" diff --git a/arch/arm/boot/dts/qcom/msm8996.dtsi b/arch/arm/boot/dts/qcom/msm8996.dtsi index acb7aad8eb8..cd4401c638d 100644 --- a/arch/arm/boot/dts/qcom/msm8996.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996.dtsi @@ -294,7 +294,7 @@ compatible = "shared-dma-pool"; alloc-ranges = <0 0x00000000 0 0xffffffff>; reusable; - alignment = <0 0x100000>; + alignment = <0 0x400000>; size = <0 0x400000>; }; @@ -3588,6 +3588,11 @@ memory-region = <&adsp_mem>; }; + qcom,msm-mdsprpc-mem { + compatible = "qcom,msm-mdsprpc-mem-region"; + memory-region = <&adsp_mem>; + }; + qcom,msm_fastrpc { compatible = "qcom,msm-fastrpc-adsp"; diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 9cb1a60b53a..7c8a8918b51 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -58,6 +58,7 @@ #define ADSP_MMAP_HEAP_ADDR 4 #define FASTRPC_ENOSUCH 39 #define VMID_SSC_Q6 5 +#define VMID_ADSP_Q6 6 #define RPC_TIMEOUT (5 * HZ) #define BALIGN 128 @@ -217,6 +218,7 @@ struct fastrpc_apps { spinlock_t hlock; struct ion_client *client; struct device *dev; + struct device *modem_cma_dev; bool glink; spinlock_t ctxlock; struct smq_invoke_ctx *ctxtable[FASTRPC_CTX_MAX]; @@ -270,7 +272,6 @@ static struct fastrpc_channel_ctx gcinfo[NUM_CHANNELS] = { .subsys = "dsps", .channel = SMD_APPS_DSPS, .edge = "dsps", - .vmid = VMID_SSC_Q6, }, }; @@ -2267,6 +2268,7 @@ static struct of_device_id fastrpc_match_table[] = { { .compatible = "qcom,msm-fastrpc-compute-cb", }, { .compatible = "qcom,msm-fastrpc-legacy-compute-cb", }, { .compatible = "qcom,msm-adsprpc-mem-region", }, + { .compatible = "qcom,msm-mdsprpc-mem-region", }, {} }; @@ -2419,6 +2421,11 @@ static int fastrpc_probe(struct platform_device *pdev) int err = 0; struct fastrpc_apps *me = &gfa; struct device *dev = &pdev->dev; + struct smq_phy_page range; + struct device_node *ion_node, *node; + struct platform_device *ion_pdev; + struct cma *cma; + uint32_t val; if (of_device_is_compatible(dev->of_node, "qcom,msm-fastrpc-compute-cb")) @@ -2440,6 +2447,44 @@ static int fastrpc_probe(struct platform_device *pdev) return 0; } + if (of_device_is_compatible(dev->of_node, + "qcom,msm-mdsprpc-mem-region")) { + me->modem_cma_dev = dev; + range.addr = 0; + ion_node = of_find_compatible_node(NULL, NULL, "qcom,msm-ion"); + if (ion_node) { + for_each_available_child_of_node(ion_node, node) { + if (of_property_read_u32(node, "reg", &val)) + continue; + if (val != ION_ADSP_HEAP_ID) + continue; + ion_pdev = of_find_device_by_node(node); + if (!ion_pdev) + break; + cma = dev_get_cma_area(&ion_pdev->dev); + if (cma) { + range.addr = cma_get_base(cma); + range.size = (size_t)cma_get_size(cma); + } + break; + } + } + if (range.addr) { + int srcVM[1] = {VMID_HLOS}; + int destVM[3] = {VMID_HLOS, VMID_SSC_Q6, + VMID_ADSP_Q6}; + int destVMperm[3] = {PERM_READ | PERM_WRITE | PERM_EXEC, + PERM_READ | PERM_WRITE | PERM_EXEC, + PERM_READ | PERM_WRITE | PERM_EXEC, + }; + VERIFY(err, !hyp_assign_phys(range.addr, range.size, + srcVM, 1, destVM, destVMperm, 3)); + if (err) + goto bail; + } + return 0; + } + me->glink = of_property_read_bool(dev->of_node, "qcom,fastrpc-glink"); pr_info("adsprpc: channel link type: %d\n", me->glink); From 45381214024b080b604136943e441d9f4b876a70 Mon Sep 17 00:00:00 2001 From: Meng Wang Date: Thu, 18 Jan 2018 00:41:48 -0800 Subject: [PATCH 18/53] ASoC: msm: qdspv2: add spin lock to protect ac ac could get freed during the execution of q6asm_callback. And kernel panic happens. Add spinlock to protect ac to avoid kernel panic. Bug: 77528410 Change-Id: Ie49c8a3979231552ba7d5f207aab0d95ffdc2a72 Signed-off-by: Meng Wang --- sound/soc/msm/qdsp6v2/q6asm.c | 141 ++++++++++++++++++++++++++-------- 1 file changed, 110 insertions(+), 31 deletions(-) diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c index a5a859c21d0..5bade05973f 100644 --- a/sound/soc/msm/qdsp6v2/q6asm.c +++ b/sound/soc/msm/qdsp6v2/q6asm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016, 2018 The Linux Foundation. All rights reserved. * Author: Brian Swetland * * This software is licensed under the terms of the GNU General Public @@ -69,8 +69,13 @@ struct asm_mmap { }; static struct asm_mmap this_mmap; + +struct audio_session { + struct audio_client *ac; + spinlock_t session_lock; +}; /* session id: 0 reserved */ -static struct audio_client *session[SESSION_MAX+1]; +static struct audio_session session[SESSION_MAX + 1]; struct asm_no_wait_node { struct list_head list; @@ -470,8 +475,8 @@ static int q6asm_session_alloc(struct audio_client *ac) { int n; for (n = 1; n <= SESSION_MAX; n++) { - if (!session[n]) { - session[n] = ac; + if (!session[n].ac) { + session[n].ac = ac; return n; } } @@ -479,36 +484,51 @@ static int q6asm_session_alloc(struct audio_client *ac) return -ENOMEM; } -static bool q6asm_is_valid_audio_client(struct audio_client *ac) +static unsigned int q6asm_get_session_id_from_audio_client( + struct audio_client *ac) { - int n; + unsigned int n; + for (n = 1; n <= SESSION_MAX; n++) { - if (session[n] == ac) - return 1; + if (session[n].ac == ac) + return n; } return 0; } +static bool q6asm_is_valid_audio_client(struct audio_client *ac) +{ + return q6asm_get_session_id_from_audio_client(ac) ? 1 : 0; +} + static void q6asm_session_free(struct audio_client *ac) { struct list_head *ptr, *next; struct asm_no_wait_node *node; unsigned long flags; + int session_id; pr_debug("%s: sessionid[%d]\n", __func__, ac->session); + session_id = ac->session; rtac_remove_popp_from_adm_devices(ac->session); - session[ac->session] = 0; + spin_lock_irqsave(&(session[session_id].session_lock), flags); + session[ac->session].ac = NULL; ac->session = 0; ac->perf_mode = LEGACY_PCM_MODE; ac->fptr_cache_ops = NULL; - spin_lock_irqsave(&ac->no_wait_que_spinlock, flags); + spin_lock(&ac->no_wait_que_spinlock); list_for_each_safe(ptr, next, &ac->no_wait_que) { node = list_entry(ptr, struct asm_no_wait_node, list); list_del(&node->list); kfree(node); } - spin_unlock_irqrestore(&ac->no_wait_que_spinlock, flags); + spin_unlock(&ac->no_wait_que_spinlock); + ac->cb = NULL; + ac->priv = NULL; + + kfree(ac); + spin_unlock_irqrestore(&(session[session_id].session_lock), flags); return; } @@ -1067,8 +1087,6 @@ void q6asm_audio_client_free(struct audio_client *ac) pr_debug("%s: APR De-Register\n", __func__); /*done:*/ - kfree(ac); - ac = NULL; mutex_unlock(&session_lock); return; @@ -1137,6 +1155,7 @@ struct audio_client *q6asm_audio_client_alloc(app_cb cb, void *priv) if (n <= 0) { pr_err("%s: ASM Session alloc fail n=%d\n", __func__, n); mutex_unlock(&session_lock); + kfree(ac); goto fail_session; } ac->session = n; @@ -1215,7 +1234,6 @@ struct audio_client *q6asm_audio_client_alloc(app_cb cb, void *priv) fail_apr1: q6asm_session_free(ac); fail_session: - kfree(ac); return NULL; } @@ -1230,11 +1248,11 @@ struct audio_client *q6asm_get_audio_client(int session_id) goto err; } - if (!session[session_id]) { + if (!(session[session_id].ac)) { pr_err("%s: session not active: %d\n", __func__, session_id); goto err; } - return session[session_id]; + return session[session_id].ac; err: return NULL; } @@ -1438,6 +1456,7 @@ static int32_t q6asm_srvc_callback(struct apr_client_data *data, void *priv) uint32_t i = IN; uint32_t *payload; unsigned long dsp_flags; + unsigned long flags; struct asm_buffer_node *buf_node = NULL; struct list_head *ptr, *next; @@ -1486,9 +1505,16 @@ static int32_t q6asm_srvc_callback(struct apr_client_data *data, void *priv) return 0; } sid = (data->token >> 8) & 0x0F; + if ((sid > 0 && sid <= SESSION_MAX)) + spin_lock_irqsave(&(session[sid].session_lock), flags); + ac = q6asm_get_audio_client(sid); if (!ac) { pr_debug("%s: session[%d] already freed\n", __func__, sid); + if ((sid > 0 && + sid <= SESSION_MAX)) + spin_unlock_irqrestore( + &(session[sid].session_lock), flags); return 0; } @@ -1538,6 +1564,10 @@ static int32_t q6asm_srvc_callback(struct apr_client_data *data, void *priv) __func__, payload[0]); break; } + if ((sid > 0 && + sid <= SESSION_MAX)) + spin_unlock_irqrestore( + &(session[sid].session_lock), flags); return 0; } @@ -1573,6 +1603,10 @@ static int32_t q6asm_srvc_callback(struct apr_client_data *data, void *priv) if (ac->cb) ac->cb(data->opcode, data->token, data->payload, ac->priv); + if ((sid > 0 && sid <= SESSION_MAX)) + spin_unlock_irqrestore( + &(session[sid].session_lock), flags); + return 0; } @@ -1651,7 +1685,8 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) uint32_t *payload; uint32_t wakeup_flag = 1; int32_t ret = 0; - + unsigned long flags; + int session_id; if (ac == NULL) { pr_err("%s: ac NULL\n", __func__); @@ -1661,15 +1696,21 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) pr_err("%s: data NULL\n", __func__); return -EINVAL; } - if (!q6asm_is_valid_audio_client(ac)) { - pr_err("%s: audio client pointer is invalid, ac = %pK\n", - __func__, ac); + + session_id = q6asm_get_session_id_from_audio_client(ac); + if (session_id <= 0) { + pr_err("%s: Session ID is invalid, session = %d\n", __func__, + session_id); return -EINVAL; } - if (ac->session <= 0 || ac->session > 8) { - pr_err("%s: Session ID is invalid, session = %d\n", __func__, - ac->session); + spin_lock_irqsave(&(session[session_id].session_lock), flags); + + if (!q6asm_is_valid_audio_client(ac)) { + pr_err("%s: audio client pointer is invalid, ac = %pK\n", + __func__, ac); + spin_unlock_irqrestore( + &(session[session_id].session_lock), flags); return -EINVAL; } @@ -1684,7 +1725,6 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) } if (data->opcode == RESET_EVENTS) { - mutex_lock(&ac->cmd_lock); atomic_set(&ac->reset, 1); if (ac->apr == NULL) ac->apr = ac->apr2; @@ -1700,7 +1740,8 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) atomic_set(&ac->cmd_state, 0); wake_up(&ac->time_wait); wake_up(&ac->cmd_wait); - mutex_unlock(&ac->cmd_lock); + spin_unlock_irqrestore( + &(session[session_id].session_lock), flags); return 0; } @@ -1711,9 +1752,16 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) data->dest_port); if ((data->opcode != ASM_DATA_EVENT_RENDERED_EOS) && (data->opcode != ASM_DATA_EVENT_EOS) && - (data->opcode != ASM_SESSION_EVENT_RX_UNDERFLOW)) + (data->opcode != ASM_SESSION_EVENT_RX_UNDERFLOW)) { + if (payload == NULL) { + pr_err("%s: payload is null\n", __func__); + spin_unlock_irqrestore( + &(session[session_id].session_lock), flags); + return -EINVAL; + } dev_vdbg(ac->dev, "%s: Payload = [0x%x] status[0x%x] opcode 0x%x\n", __func__, payload[0], payload[1], data->opcode); + } if (data->opcode == APR_BASIC_RSP_RESULT) { token = data->token; switch (payload[0]) { @@ -1735,6 +1783,8 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) ret = q6asm_is_valid_session(data, priv); if (ret != 0) { pr_err("%s: session invalid %d\n", __func__, ret); + spin_unlock_irqrestore( + &(session[session_id].session_lock), flags); return ret; } case ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2: @@ -1763,6 +1813,9 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) atomic_set(&ac->cmd_state, payload[1]); wake_up(&ac->cmd_wait); } + spin_unlock_irqrestore( + &(session[session_id].session_lock), + flags); return 0; } if (atomic_read(&ac->cmd_state) && wakeup_flag) { @@ -1783,6 +1836,9 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) atomic_set(&ac->mem_state, payload[1]); wake_up(&ac->mem_wait); } + spin_unlock_irqrestore( + &(session[session_id].session_lock), + flags); return 0; } if (atomic_read(&ac->mem_state) && wakeup_flag) { @@ -1819,6 +1875,9 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) __func__, payload[0]); break; } + + spin_unlock_irqrestore( + &(session[session_id].session_lock), flags); return 0; } @@ -1832,6 +1891,9 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) if (port->buf == NULL) { pr_err("%s: Unexpected Write Done\n", __func__); + spin_unlock_irqrestore( + &(session[session_id].session_lock), + flags); return -EINVAL; } spin_lock_irqsave(&port->dsp_lock, dsp_flags); @@ -1845,6 +1907,9 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) __func__, payload[0], payload[1]); spin_unlock_irqrestore(&port->dsp_lock, dsp_flags); + spin_unlock_irqrestore( + &(session[session_id].session_lock), + flags); return -EINVAL; } token = data->token; @@ -1916,6 +1981,9 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) if (ac->io_mode & SYNC_IO_MODE) { if (port->buf == NULL) { pr_err("%s: Unexpected Write Done\n", __func__); + spin_unlock_irqrestore( + &(session[session_id].session_lock), + flags); return -EINVAL; } spin_lock_irqsave(&port->dsp_lock, dsp_flags); @@ -2002,7 +2070,8 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) if (ac->cb) ac->cb(data->opcode, data->token, data->payload, ac->priv); - + spin_unlock_irqrestore( + &(session[session_id].session_lock), flags); return 0; } @@ -2144,11 +2213,16 @@ int q6asm_is_dsp_buf_avail(int dir, struct audio_client *ac) static void __q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr, uint32_t pkt_size, uint32_t cmd_flg, uint32_t stream_id) { + unsigned long flags; + dev_vdbg(ac->dev, "%s: pkt_size=%d cmd_flg=%d session=%d stream_id=%d\n", __func__, pkt_size, cmd_flg, ac->session, stream_id); mutex_lock(&ac->cmd_lock); + spin_lock_irqsave(&(session[ac->session].session_lock), flags); if (ac->apr == NULL) { pr_err("%s: AC APR handle NULL", __func__); + spin_unlock_irqrestore( + &(session[ac->session].session_lock), flags); mutex_unlock(&ac->cmd_lock); return; } @@ -2166,6 +2240,8 @@ static void __q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr, hdr->token = ac->session; } hdr->pkt_size = pkt_size; + spin_unlock_irqrestore( + &(session[ac->session].session_lock), flags); mutex_unlock(&ac->cmd_lock); return; } @@ -7649,7 +7725,7 @@ int q6asm_get_apr_service_id(int session_id) return -EINVAL; } - return ((struct apr_svc *)session[session_id]->apr)->id; + return ((struct apr_svc *)(session[session_id].ac)->apr)->id; } int q6asm_get_asm_topology(int session_id) @@ -7662,7 +7738,7 @@ int q6asm_get_asm_topology(int session_id) goto done; } - topology = session[session_id]->topology; + topology = (session[session_id].ac)->topology; done: return topology; } @@ -7677,7 +7753,7 @@ int q6asm_get_asm_app_type(int session_id) goto done; } - app_type = session[session_id]->app_type; + app_type = (session[session_id].ac)->app_type; done: return app_type; } @@ -8034,7 +8110,10 @@ static int __init q6asm_init(void) int lcnt, ret; pr_debug("%s:\n", __func__); - memset(session, 0, sizeof(session)); + memset(session, 0, sizeof(struct audio_session) * + (SESSION_MAX + 1)); + for (lcnt = 0; lcnt <= SESSION_MAX; lcnt++) + spin_lock_init(&(session[lcnt].session_lock)); set_custom_topology = 1; /*setup common client used for cal mem map */ From 0cf041b2af05f7f8565311c2489bd7dda211ff7c Mon Sep 17 00:00:00 2001 From: Vignesh Kulothungan Date: Tue, 19 Jun 2018 15:17:46 -0700 Subject: [PATCH 19/53] ASoC: msm: qdspv2: initialize variables before use Initialize 'flags' variables before use in spinlocks. Bug: 77528410 Change-Id: Ifeba2c103790147fd80a387345ecff6beaff1311 CRs-Fixed: 2257317 Signed-off-by: Vignesh Kulothungan --- sound/soc/msm/qdsp6v2/q6asm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c index 5bade05973f..b3614532d4e 100644 --- a/sound/soc/msm/qdsp6v2/q6asm.c +++ b/sound/soc/msm/qdsp6v2/q6asm.c @@ -1456,7 +1456,7 @@ static int32_t q6asm_srvc_callback(struct apr_client_data *data, void *priv) uint32_t i = IN; uint32_t *payload; unsigned long dsp_flags; - unsigned long flags; + unsigned long flags = 0; struct asm_buffer_node *buf_node = NULL; struct list_head *ptr, *next; @@ -1685,7 +1685,7 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) uint32_t *payload; uint32_t wakeup_flag = 1; int32_t ret = 0; - unsigned long flags; + unsigned long flags = 0; int session_id; if (ac == NULL) { @@ -2213,7 +2213,7 @@ int q6asm_is_dsp_buf_avail(int dir, struct audio_client *ac) static void __q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr, uint32_t pkt_size, uint32_t cmd_flg, uint32_t stream_id) { - unsigned long flags; + unsigned long flags = 0; dev_vdbg(ac->dev, "%s: pkt_size=%d cmd_flg=%d session=%d stream_id=%d\n", __func__, pkt_size, cmd_flg, ac->session, stream_id); From 0a7c30d52a9e2ee9741facce37ab6e4005a325fa Mon Sep 17 00:00:00 2001 From: jinweic chen Date: Tue, 13 Mar 2018 13:28:30 +0800 Subject: [PATCH 20/53] qcacld-2.0: Fix buffer overflow in ol_rx_in_order_indication_handler Propagation from cld3.0 to cld2.0. Currently variable "tid" is from message, which is used directly as array size which causes buffer over-write. To address this issue, add check for the array size. Bug: 109741886 Change-Id: Idb6bd8ceaa217620a60bc04f2e84a551113e6edb CRs-Fixed: 2204463 Signed-off-by: Ecco Park --- drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_rx.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_rx.c b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_rx.c index c0780c91295..accb8cc799d 100644 --- a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_rx.c +++ b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_rx.c @@ -1195,6 +1195,13 @@ ol_rx_in_order_indication_handler( int status; adf_nbuf_t head_msdu, tail_msdu = NULL; + if (tid >= OL_TXRX_NUM_EXT_TIDS) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: invalid tid, %u\n", __FUNCTION__, tid); + WARN_ON(1); + return; + } + if (pdev) { peer = ol_txrx_peer_find_by_id(pdev, peer_id); if (VOS_MONITOR_MODE == vos_get_conparam()) From 0847da4e3023961d002d33626b1833e9695e9f3a Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Mon, 12 Mar 2018 15:57:54 -0700 Subject: [PATCH 21/53] ANDROID: HID: debug: check length in hid_debug_events_read() before copy_to_user() If our length is greater than the size of the buffer, we overflow the buffer Bug: 71361580 Change-Id: I113a1955a2bac83c83084d5cd28d886175673219 Signed-off-by: Daniel Rosenberg --- drivers/hid/hid-debug.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c index 8bf61d295ff..7192fa1d278 100644 --- a/drivers/hid/hid-debug.c +++ b/drivers/hid/hid-debug.c @@ -1150,6 +1150,8 @@ static ssize_t hid_debug_events_read(struct file *file, char __user *buffer, goto out; if (list->tail > list->head) { len = list->tail - list->head; + if (len > count) + len = count; if (copy_to_user(buffer + ret, &list->hid_debug_buf[list->head], len)) { ret = -EFAULT; @@ -1159,6 +1161,8 @@ static ssize_t hid_debug_events_read(struct file *file, char __user *buffer, list->head += len; } else { len = HID_DEBUG_BUFSIZE - list->head; + if (len > count) + len = count; if (copy_to_user(buffer, &list->hid_debug_buf[list->head], len)) { ret = -EFAULT; @@ -1166,7 +1170,9 @@ static ssize_t hid_debug_events_read(struct file *file, char __user *buffer, } list->head = 0; ret += len; - goto copy_rest; + count -= len; + if (count > 0) + goto copy_rest; } } From b4a4504f5775781e596460185967c77a191134b5 Mon Sep 17 00:00:00 2001 From: Sean Callanan Date: Tue, 3 Apr 2018 20:40:12 -0700 Subject: [PATCH 22/53] FROMLIST: diag: Synchronize msg mask read and write on a peripheral The patch synchronizes msg mask read and write on a peripheral by proper protection of mask_info and msg_mask_table_count. There is also a possibility of accessing freed mdlog session info and it's attributes after closing the session. The patch adds protection while accessing mdlog session info for preventing use-after-free issue. CRs Fixed: 2133028 2042362 2055291 Signed-off-by: Manoj Prabhu B Signed-off-by: Hardik Arya (cherry-picked from https://source.codeaurora.org/quic/la/kernel/msm-3.18 commit 6f7210fd2eeda94896ea88e5432746d7c8fae569) (cherry-picked from https://source.codeaurora.org/quic/la/kernel/msm-3.18 commit df4e06a84050896bc139b2a189c78ec5bfad8970) Bug: 63528466 Change-Id: If90945bb446894904a09b269ca6d74b5b48de4e5 Signed-off-by: Sean Callanan Signed-off-by: Siqi Lin --- drivers/char/diag/diag_masks.c | 324 +++++++++++++++++++------ drivers/char/diag/diag_masks.h | 5 +- drivers/char/diag/diag_memorydevice.c | 15 +- drivers/char/diag/diag_usb.c | 4 +- drivers/char/diag/diagchar.h | 4 +- drivers/char/diag/diagchar_core.c | 169 +++++++++---- drivers/char/diag/diagfwd.c | 77 +++--- drivers/char/diag/diagfwd.h | 11 +- drivers/char/diag/diagfwd_peripheral.c | 5 +- 9 files changed, 439 insertions(+), 175 deletions(-) diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c index 64d5b431aa1..e8f5bceaaa4 100644 --- a/drivers/char/diag/diag_masks.c +++ b/drivers/char/diag/diag_masks.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2018, 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 @@ -288,6 +288,7 @@ static void diag_send_msg_mask_update(uint8_t peripheral, int first, int last) struct diag_mask_info *mask_info = NULL; struct diag_msg_mask_t *mask = NULL; struct diag_ctrl_msg_mask header; + uint8_t msg_mask_tbl_count_local; if (peripheral >= NUM_PERIPHERALS) return; @@ -315,6 +316,8 @@ static void diag_send_msg_mask_update(uint8_t peripheral, int first, int last) return; } buf = mask_info->update_buf; + msg_mask_tbl_count_local = driver->msg_mask_tbl_count; + mutex_unlock(&driver->msg_mask_lock); mutex_lock(&mask_info->lock); switch (mask_info->status) { case DIAG_CTRL_MASK_ALL_DISABLED: @@ -331,9 +334,11 @@ static void diag_send_msg_mask_update(uint8_t peripheral, int first, int last) goto err; } - for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { - if (((first < mask->ssid_first) || - (last > mask->ssid_last_tools)) && first != ALL_SSID) { + for (i = 0; i < msg_mask_tbl_count_local; i++, mask++) { + mutex_lock(&driver->msg_mask_lock); + if (((mask->ssid_first > first) || + (mask->ssid_last_tools < last)) && first != ALL_SSID) { + mutex_unlock(&driver->msg_mask_lock); continue; } @@ -374,19 +379,19 @@ static void diag_send_msg_mask_update(uint8_t peripheral, int first, int last) if (mask_size > 0) memcpy(buf + header_len, mask->ptr, mask_size); mutex_unlock(&mask->lock); + mutex_unlock(&driver->msg_mask_lock); err = diagfwd_write(peripheral, TYPE_CNTL, buf, header_len + mask_size); if (err && err != -ENODEV) - pr_err_ratelimited("diag: Unable to send msg masks to peripheral %d\n", - peripheral); + pr_err_ratelimited("diag: Unable to send msg masks to peripheral %d, error = %d\n", + peripheral, err); if (first != ALL_SSID) break; } err: mutex_unlock(&mask_info->lock); - mutex_unlock(&driver->msg_mask_lock); } static void diag_send_time_sync_update(uint8_t peripheral) @@ -477,8 +482,7 @@ static void diag_send_feature_mask_update(uint8_t peripheral) } static int diag_cmd_get_ssid_range(unsigned char *src_buf, int src_len, - unsigned char *dest_buf, int dest_len, - struct diag_md_session_t *info) + unsigned char *dest_buf, int dest_len, int pid) { int i; int write_len = 0; @@ -486,19 +490,30 @@ static int diag_cmd_get_ssid_range(unsigned char *src_buf, int src_len, struct diag_msg_ssid_query_t rsp; struct diag_ssid_range_t ssid_range; struct diag_mask_info *mask_info = NULL; + struct diag_md_session_t *info = NULL; + mutex_lock(&driver->md_session_lock); + info = diag_md_session_get_pid(pid); mask_info = (!info) ? &msg_mask : info->msg_mask; if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 || !mask_info) { pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n", __func__, src_buf, src_len, dest_buf, dest_len, mask_info); + mutex_unlock(&driver->md_session_lock); + return -EINVAL; + } + if (!mask_info->ptr) { + pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n", + __func__, mask_info->ptr); + mutex_unlock(&driver->md_session_lock); return -EINVAL; } - if (!diag_apps_responds()) + if (!diag_apps_responds()) { + mutex_unlock(&driver->md_session_lock); return 0; - + } mutex_lock(&driver->msg_mask_lock); rsp.cmd_code = DIAG_CMD_MSG_CONFIG; rsp.sub_cmd = DIAG_CMD_OP_GET_SSID_RANGE; @@ -520,13 +535,12 @@ static int diag_cmd_get_ssid_range(unsigned char *src_buf, int src_len, write_len += sizeof(ssid_range); } mutex_unlock(&driver->msg_mask_lock); - + mutex_unlock(&driver->md_session_lock); return write_len; } static int diag_cmd_get_build_mask(unsigned char *src_buf, int src_len, - unsigned char *dest_buf, int dest_len, - struct diag_md_session_t *info) + unsigned char *dest_buf, int dest_len, int pid) { int i = 0; int write_len = 0; @@ -581,8 +595,7 @@ static int diag_cmd_get_build_mask(unsigned char *src_buf, int src_len, } static int diag_cmd_get_msg_mask(unsigned char *src_buf, int src_len, - unsigned char *dest_buf, int dest_len, - struct diag_md_session_t *info) + unsigned char *dest_buf, int dest_len, int pid) { int i; int write_len = 0; @@ -591,6 +604,10 @@ static int diag_cmd_get_msg_mask(unsigned char *src_buf, int src_len, struct diag_build_mask_req_t *req = NULL; struct diag_msg_build_mask_t rsp; struct diag_mask_info *mask_info = NULL; + struct diag_md_session_t *info = NULL; + + mutex_lock(&driver->md_session_lock); + info = diag_md_session_get_pid(pid); mask_info = (!info) ? &msg_mask : info->msg_mask; if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 || @@ -598,11 +615,19 @@ static int diag_cmd_get_msg_mask(unsigned char *src_buf, int src_len, pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n", __func__, src_buf, src_len, dest_buf, dest_len, mask_info); + mutex_unlock(&driver->md_session_lock); return -EINVAL; } - - if (!diag_apps_responds()) + if (!mask_info->ptr) { + pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n", + __func__, mask_info->ptr); + mutex_unlock(&driver->md_session_lock); + return -EINVAL; + } + if (!diag_apps_responds()) { + mutex_unlock(&driver->md_session_lock); return 0; + } mutex_lock(&driver->msg_mask_lock); req = (struct diag_build_mask_req_t *)src_buf; @@ -613,6 +638,13 @@ static int diag_cmd_get_msg_mask(unsigned char *src_buf, int src_len, rsp.status = MSG_STATUS_FAIL; rsp.padding = 0; mask = (struct diag_msg_mask_t *)mask_info->ptr; + if (!mask->ptr) { + pr_err("diag: Invalid input in %s, mask->ptr: %pK\n", + __func__, mask->ptr); + mutex_unlock(&driver->msg_mask_lock); + mutex_unlock(&driver->md_session_lock); + return -EINVAL; + } for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { if ((req->ssid_first < mask->ssid_first) || (req->ssid_first > mask->ssid_last_tools)) { @@ -630,13 +662,12 @@ static int diag_cmd_get_msg_mask(unsigned char *src_buf, int src_len, memcpy(dest_buf, &rsp, sizeof(rsp)); write_len += sizeof(rsp); mutex_unlock(&driver->msg_mask_lock); - + mutex_unlock(&driver->md_session_lock); return write_len; } static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len, - unsigned char *dest_buf, int dest_len, - struct diag_md_session_t *info) + unsigned char *dest_buf, int dest_len, int pid) { int i; int write_len = 0; @@ -650,6 +681,10 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len, struct diag_mask_info *mask_info = NULL; struct diag_msg_mask_t *mask_next = NULL; uint32_t *temp = NULL; + struct diag_md_session_t *info = NULL; + + mutex_lock(&driver->md_session_lock); + info = diag_md_session_get_pid(pid); mask_info = (!info) ? &msg_mask : info->msg_mask; if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 || @@ -657,13 +692,28 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len, pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n", __func__, src_buf, src_len, dest_buf, dest_len, mask_info); + mutex_unlock(&driver->md_session_lock); + return -EINVAL; + } + if (!mask_info->ptr) { + pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n", + __func__, mask_info->ptr); + mutex_unlock(&driver->md_session_lock); return -EINVAL; } req = (struct diag_msg_build_mask_t *)src_buf; - mutex_lock(&driver->msg_mask_lock); mutex_lock(&mask_info->lock); + mutex_lock(&driver->msg_mask_lock); mask = (struct diag_msg_mask_t *)mask_info->ptr; + if (!mask->ptr) { + pr_err("diag: Invalid input in %s, mask->ptr: %pK\n", + __func__, mask->ptr); + mutex_unlock(&driver->msg_mask_lock); + mutex_unlock(&mask_info->lock); + mutex_unlock(&driver->md_session_lock); + return -EINVAL; + } for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { if (i < (driver->msg_mask_tbl_count - 1)) { mask_next = mask; @@ -702,6 +752,9 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len, pr_err_ratelimited("diag: In %s, unable to allocate memory for msg mask ptr, mask_size: %d\n", __func__, mask_size); mutex_unlock(&mask->lock); + mutex_unlock(&driver->msg_mask_lock); + mutex_unlock(&mask_info->lock); + mutex_unlock(&driver->md_session_lock); return -ENOMEM; } mask->ptr = temp; @@ -720,9 +773,9 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len, mask_info->status = DIAG_CTRL_MASK_VALID; break; } - mutex_unlock(&mask_info->lock); mutex_unlock(&driver->msg_mask_lock); - + mutex_unlock(&mask_info->lock); + mutex_unlock(&driver->md_session_lock); if (diag_check_update(APPS_DATA)) diag_update_userspace_clients(MSG_MASKS_TYPE); @@ -754,8 +807,7 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len, } static int diag_cmd_set_all_msg_mask(unsigned char *src_buf, int src_len, - unsigned char *dest_buf, int dest_len, - struct diag_md_session_t *info) + unsigned char *dest_buf, int dest_len, int pid) { int i; int write_len = 0; @@ -764,6 +816,10 @@ static int diag_cmd_set_all_msg_mask(unsigned char *src_buf, int src_len, struct diag_msg_config_rsp_t *req = NULL; struct diag_msg_mask_t *mask = NULL; struct diag_mask_info *mask_info = NULL; + struct diag_md_session_t *info = NULL; + + mutex_lock(&driver->md_session_lock); + info = diag_md_session_get_pid(pid); mask_info = (!info) ? &msg_mask : info->msg_mask; if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 || @@ -771,14 +827,30 @@ static int diag_cmd_set_all_msg_mask(unsigned char *src_buf, int src_len, pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n", __func__, src_buf, src_len, dest_buf, dest_len, mask_info); + mutex_unlock(&driver->md_session_lock); + return -EINVAL; + } + if (!mask_info->ptr) { + pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n", + __func__, mask_info->ptr); + mutex_unlock(&driver->md_session_lock); return -EINVAL; } req = (struct diag_msg_config_rsp_t *)src_buf; + mutex_lock(&mask_info->lock); mutex_lock(&driver->msg_mask_lock); + mask = (struct diag_msg_mask_t *)mask_info->ptr; - mutex_lock(&mask_info->lock); + if (!mask->ptr) { + pr_err("diag: Invalid input in %s, mask->ptr: %pK\n", + __func__, mask->ptr); + mutex_unlock(&driver->msg_mask_lock); + mutex_unlock(&mask_info->lock); + mutex_unlock(&driver->md_session_lock); + return -EINVAL; + } mask_info->status = (req->rt_mask) ? DIAG_CTRL_MASK_ALL_ENABLED : DIAG_CTRL_MASK_ALL_DISABLED; for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { @@ -787,9 +859,9 @@ static int diag_cmd_set_all_msg_mask(unsigned char *src_buf, int src_len, mask->range * sizeof(uint32_t)); mutex_unlock(&mask->lock); } - mutex_unlock(&mask_info->lock); mutex_unlock(&driver->msg_mask_lock); - + mutex_unlock(&mask_info->lock); + mutex_unlock(&driver->md_session_lock); if (diag_check_update(APPS_DATA)) diag_update_userspace_clients(MSG_MASKS_TYPE); @@ -815,8 +887,7 @@ static int diag_cmd_set_all_msg_mask(unsigned char *src_buf, int src_len, } static int diag_cmd_get_event_mask(unsigned char *src_buf, int src_len, - unsigned char *dest_buf, int dest_len, - struct diag_md_session_t *info) + unsigned char *dest_buf, int dest_len, int pid) { int write_len = 0; uint32_t mask_size; @@ -851,8 +922,7 @@ static int diag_cmd_get_event_mask(unsigned char *src_buf, int src_len, } static int diag_cmd_update_event_mask(unsigned char *src_buf, int src_len, - unsigned char *dest_buf, int dest_len, - struct diag_md_session_t *info) + unsigned char *dest_buf, int dest_len, int pid) { int i; int write_len = 0; @@ -861,21 +931,31 @@ static int diag_cmd_update_event_mask(unsigned char *src_buf, int src_len, struct diag_event_mask_config_t rsp; struct diag_event_mask_config_t *req; struct diag_mask_info *mask_info = NULL; + struct diag_md_session_t *info = NULL; + mutex_lock(&driver->md_session_lock); + info = diag_md_session_get_pid(pid); mask_info = (!info) ? &event_mask : info->event_mask; if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 || !mask_info) { pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n", __func__, src_buf, src_len, dest_buf, dest_len, mask_info); + mutex_unlock(&driver->md_session_lock); + return -EINVAL; + } + if (!mask_info->ptr) { + pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n", + __func__, mask_info->ptr); + mutex_unlock(&driver->md_session_lock); return -EINVAL; } - req = (struct diag_event_mask_config_t *)src_buf; mask_len = EVENT_COUNT_TO_BYTES(req->num_bits); if (mask_len <= 0 || mask_len > event_mask.mask_len) { pr_err("diag: In %s, invalid event mask len: %d\n", __func__, mask_len); + mutex_unlock(&driver->md_session_lock); return -EIO; } @@ -883,6 +963,7 @@ static int diag_cmd_update_event_mask(unsigned char *src_buf, int src_len, memcpy(mask_info->ptr, src_buf + header_len, mask_len); mask_info->status = DIAG_CTRL_MASK_VALID; mutex_unlock(&mask_info->lock); + mutex_unlock(&driver->md_session_lock); if (diag_check_update(APPS_DATA)) diag_update_userspace_clients(EVENT_MASKS_TYPE); @@ -909,21 +990,30 @@ static int diag_cmd_update_event_mask(unsigned char *src_buf, int src_len, } static int diag_cmd_toggle_events(unsigned char *src_buf, int src_len, - unsigned char *dest_buf, int dest_len, - struct diag_md_session_t *info) + unsigned char *dest_buf, int dest_len, int pid) { int i; int write_len = 0; uint8_t toggle = 0; struct diag_event_report_t header; struct diag_mask_info *mask_info = NULL; + struct diag_md_session_t *info = NULL; + mutex_lock(&driver->md_session_lock); + info = diag_md_session_get_pid(pid); mask_info = (!info) ? &event_mask : info->event_mask; if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 || !mask_info) { pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n", __func__, src_buf, src_len, dest_buf, dest_len, mask_info); + mutex_unlock(&driver->md_session_lock); + return -EINVAL; + } + if (!mask_info->ptr) { + pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n", + __func__, mask_info->ptr); + mutex_unlock(&driver->md_session_lock); return -EINVAL; } @@ -937,6 +1027,7 @@ static int diag_cmd_toggle_events(unsigned char *src_buf, int src_len, memset(mask_info->ptr, 0, mask_info->mask_len); } mutex_unlock(&mask_info->lock); + mutex_unlock(&driver->md_session_lock); if (diag_check_update(APPS_DATA)) diag_update_userspace_clients(EVENT_MASKS_TYPE); @@ -958,8 +1049,7 @@ static int diag_cmd_toggle_events(unsigned char *src_buf, int src_len, } static int diag_cmd_get_log_mask(unsigned char *src_buf, int src_len, - unsigned char *dest_buf, int dest_len, - struct diag_md_session_t *info) + unsigned char *dest_buf, int dest_len, int pid) { int i; int status = LOG_STATUS_INVALID; @@ -972,6 +1062,10 @@ static int diag_cmd_get_log_mask(unsigned char *src_buf, int src_len, struct diag_log_config_req_t *req; struct diag_log_config_rsp_t rsp; struct diag_mask_info *mask_info = NULL; + struct diag_md_session_t *info = NULL; + + mutex_lock(&driver->md_session_lock); + info = diag_md_session_get_pid(pid); mask_info = (!info) ? &log_mask : info->log_mask; if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 || @@ -979,11 +1073,20 @@ static int diag_cmd_get_log_mask(unsigned char *src_buf, int src_len, pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n", __func__, src_buf, src_len, dest_buf, dest_len, mask_info); + mutex_unlock(&driver->md_session_lock); + return -EINVAL; + } + if (!mask_info->ptr) { + pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n", + __func__, mask_info->ptr); + mutex_unlock(&driver->md_session_lock); return -EINVAL; } - if (!diag_apps_responds()) + if (!diag_apps_responds()) { + mutex_unlock(&driver->md_session_lock); return 0; + } req = (struct diag_log_config_req_t *)src_buf; read_len += req_header_len; @@ -1000,6 +1103,12 @@ static int diag_cmd_get_log_mask(unsigned char *src_buf, int src_len, write_len += rsp_header_len; log_item = (struct diag_log_mask_t *)mask_info->ptr; + if (!log_item->ptr) { + pr_err("diag: Invalid input in %s, mask: %pK\n", + __func__, log_item); + mutex_unlock(&driver->md_session_lock); + return -EINVAL; + } for (i = 0; i < MAX_EQUIP_ID; i++, log_item++) { if (log_item->equip_id != req->equip_id) continue; @@ -1039,28 +1148,27 @@ static int diag_cmd_get_log_mask(unsigned char *src_buf, int src_len, rsp.status = status; memcpy(dest_buf, &rsp, rsp_header_len); + mutex_unlock(&driver->md_session_lock); return write_len; } static int diag_cmd_get_log_range(unsigned char *src_buf, int src_len, - unsigned char *dest_buf, int dest_len, - struct diag_md_session_t *info) + unsigned char *dest_buf, int dest_len, int pid) { int i; int write_len = 0; struct diag_log_config_rsp_t rsp; - struct diag_mask_info *mask_info = NULL; struct diag_log_mask_t *mask = (struct diag_log_mask_t *)log_mask.ptr; + if (!mask) + return -EINVAL; + if (!diag_apps_responds()) return 0; - mask_info = (!info) ? &log_mask : info->log_mask; - if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 || - !mask_info) { - pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n", - __func__, src_buf, src_len, dest_buf, dest_len, - mask_info); + if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0) { + pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d\n", + __func__, src_buf, src_len, dest_buf, dest_len); return -EINVAL; } @@ -1083,7 +1191,7 @@ static int diag_cmd_get_log_range(unsigned char *src_buf, int src_len, static int diag_cmd_set_log_mask(unsigned char *src_buf, int src_len, unsigned char *dest_buf, int dest_len, - struct diag_md_session_t *info) + int pid) { int i; int write_len = 0; @@ -1098,6 +1206,10 @@ static int diag_cmd_set_log_mask(unsigned char *src_buf, int src_len, struct diag_log_mask_t *mask = NULL; unsigned char *temp_buf = NULL; struct diag_mask_info *mask_info = NULL; + struct diag_md_session_t *info = NULL; + + mutex_lock(&driver->md_session_lock); + info = diag_md_session_get_pid(pid); mask_info = (!info) ? &log_mask : info->log_mask; if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 || @@ -1105,13 +1217,25 @@ static int diag_cmd_set_log_mask(unsigned char *src_buf, int src_len, pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n", __func__, src_buf, src_len, dest_buf, dest_len, mask_info); + mutex_unlock(&driver->md_session_lock); + return -EINVAL; + } + if (!mask_info->ptr) { + pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n", + __func__, mask_info->ptr); + mutex_unlock(&driver->md_session_lock); return -EINVAL; } req = (struct diag_log_config_req_t *)src_buf; read_len += req_header_len; mask = (struct diag_log_mask_t *)mask_info->ptr; - + if (!mask->ptr) { + pr_err("diag: Invalid input in %s, mask->ptr: %pK\n", + __func__, mask->ptr); + mutex_unlock(&driver->md_session_lock); + return -EINVAL; + } if (req->equip_id >= MAX_EQUIP_ID) { pr_err("diag: In %s, Invalid logging mask request, equip_id: %d\n", __func__, req->equip_id); @@ -1172,6 +1296,7 @@ static int diag_cmd_set_log_mask(unsigned char *src_buf, int src_len, break; } mutex_unlock(&mask_info->lock); + mutex_unlock(&driver->md_session_lock); if (diag_check_update(APPS_DATA)) diag_update_userspace_clients(LOG_MASKS_TYPE); @@ -1210,14 +1335,17 @@ static int diag_cmd_set_log_mask(unsigned char *src_buf, int src_len, } static int diag_cmd_disable_log_mask(unsigned char *src_buf, int src_len, - unsigned char *dest_buf, int dest_len, - struct diag_md_session_t *info) + unsigned char *dest_buf, int dest_len, int pid) { struct diag_mask_info *mask_info = NULL; struct diag_log_mask_t *mask = NULL; struct diag_log_config_rsp_t header; int write_len = 0; int i; + struct diag_md_session_t *info = NULL; + + mutex_lock(&driver->md_session_lock); + info = diag_md_session_get_pid(pid); mask_info = (!info) ? &log_mask : info->log_mask; if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 || @@ -1225,17 +1353,29 @@ static int diag_cmd_disable_log_mask(unsigned char *src_buf, int src_len, pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n", __func__, src_buf, src_len, dest_buf, dest_len, mask_info); + mutex_unlock(&driver->md_session_lock); + return -EINVAL; + } + if (!mask_info->ptr) { + pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n", + __func__, mask_info->ptr); + mutex_unlock(&driver->md_session_lock); return -EINVAL; } - mask = (struct diag_log_mask_t *)mask_info->ptr; - + if (!mask->ptr) { + pr_err("diag: Invalid input in %s, mask->ptr: %pK\n", + __func__, mask->ptr); + mutex_unlock(&driver->md_session_lock); + return -EINVAL; + } for (i = 0; i < MAX_EQUIP_ID; i++, mask++) { mutex_lock(&mask->lock); memset(mask->ptr, 0, mask->range); mutex_unlock(&mask->lock); } mask_info->status = DIAG_CTRL_MASK_ALL_DISABLED; + mutex_unlock(&driver->md_session_lock); if (diag_check_update(APPS_DATA)) diag_update_userspace_clients(LOG_MASKS_TYPE); @@ -1292,8 +1432,8 @@ static int diag_create_msg_mask_table(void) struct diag_msg_mask_t *mask = (struct diag_msg_mask_t *)msg_mask.ptr; struct diag_ssid_range_t range; - mutex_lock(&driver->msg_mask_lock); mutex_lock(&msg_mask.lock); + mutex_lock(&driver->msg_mask_lock); driver->msg_mask_tbl_count = MSG_MASK_TBL_CNT; for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { range.ssid_first = msg_mask_tbl[i].ssid_first; @@ -1302,9 +1442,8 @@ static int diag_create_msg_mask_table(void) if (err) break; } - mutex_unlock(&msg_mask.lock); mutex_unlock(&driver->msg_mask_lock); - + mutex_unlock(&msg_mask.lock); return err; } @@ -1317,8 +1456,8 @@ static int diag_create_build_time_mask(void) struct diag_msg_mask_t *build_mask = NULL; struct diag_ssid_range_t range; - mutex_lock(&driver->msg_mask_lock); mutex_lock(&msg_bt_mask.lock); + mutex_lock(&driver->msg_mask_lock); driver->bt_msg_mask_tbl_count = MSG_MASK_TBL_CNT; build_mask = (struct diag_msg_mask_t *)msg_bt_mask.ptr; for (i = 0; i < driver->bt_msg_mask_tbl_count; i++, build_mask++) { @@ -1431,9 +1570,8 @@ static int diag_create_build_time_mask(void) } memcpy(build_mask->ptr, tbl, tbl_size); } - mutex_unlock(&msg_bt_mask.lock); mutex_unlock(&driver->msg_mask_lock); - + mutex_unlock(&msg_bt_mask.lock); return err; } @@ -1495,7 +1633,7 @@ static int __diag_mask_init(struct diag_mask_info *mask_info, int mask_len, static void __diag_mask_exit(struct diag_mask_info *mask_info) { - if (!mask_info) + if (!mask_info || !mask_info->ptr) return; mutex_lock(&mask_info->lock); @@ -1552,11 +1690,17 @@ void diag_log_mask_free(struct diag_mask_info *mask_info) int i; struct diag_log_mask_t *mask = NULL; - if (!mask_info) + if (!mask_info || !mask_info->ptr) return; mutex_lock(&mask_info->lock); mask = (struct diag_log_mask_t *)mask_info->ptr; + if (!mask->ptr) { + pr_err("diag: Invalid input in %s, mask->ptr: %pK\n", + __func__, mask->ptr); + mutex_unlock(&mask_info->lock); + return; + } for (i = 0; i < MAX_EQUIP_ID; i++, mask++) { kfree(mask->ptr); mask->ptr = NULL; @@ -1603,8 +1747,8 @@ int diag_msg_mask_copy(struct diag_mask_info *dest, struct diag_mask_info *src) err = __diag_mask_init(dest, MSG_MASK_SIZE, APPS_BUF_SIZE); if (err) return err; - mutex_lock(&driver->msg_mask_lock); mutex_lock(&dest->lock); + mutex_lock(&driver->msg_mask_lock); src_mask = (struct diag_msg_mask_t *)src->ptr; dest_mask = (struct diag_msg_mask_t *)dest->ptr; @@ -1621,9 +1765,8 @@ int diag_msg_mask_copy(struct diag_mask_info *dest, struct diag_mask_info *src) src_mask++; dest_mask++; } - mutex_unlock(&dest->lock); mutex_unlock(&driver->msg_mask_lock); - + mutex_unlock(&dest->lock); return err; } @@ -1632,17 +1775,24 @@ void diag_msg_mask_free(struct diag_mask_info *mask_info) int i; struct diag_msg_mask_t *mask = NULL; - if (!mask_info) + if (!mask_info || !mask_info->ptr) return; - mutex_lock(&driver->msg_mask_lock); mutex_lock(&mask_info->lock); + mutex_lock(&driver->msg_mask_lock); mask = (struct diag_msg_mask_t *)mask_info->ptr; + if (!mask->ptr) { + pr_err("diag: Invalid input in %s, mask->ptr: %pK\n", + __func__, mask->ptr); + mutex_unlock(&driver->msg_mask_lock); + mutex_unlock(&mask_info->lock); + return; + } for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { kfree(mask->ptr); mask->ptr = NULL; } - mutex_unlock(&mask_info->lock); mutex_unlock(&driver->msg_mask_lock); + mutex_unlock(&mask_info->lock); __diag_mask_exit(mask_info); } @@ -1803,6 +1953,11 @@ int diag_copy_to_user_msg_mask(char __user *buf, size_t count, if (!mask_info) return -EIO; + if (!mask_info->ptr || !mask_info->update_buf) { + pr_err("diag: In %s, invalid input mask_info->ptr: %pK, mask_info->update_buf: %pK\n", + __func__, mask_info->ptr, mask_info->update_buf); + return -EINVAL; + } mutex_lock(&driver->diag_maskclear_mutex); if (driver->mask_clear) { DIAG_LOG(DIAG_DEBUG_PERIPHERALS, @@ -1811,9 +1966,17 @@ int diag_copy_to_user_msg_mask(char __user *buf, size_t count, return -EIO; } mutex_unlock(&driver->diag_maskclear_mutex); - mutex_lock(&driver->msg_mask_lock); mutex_lock(&mask_info->lock); + mutex_lock(&driver->msg_mask_lock); + mask = (struct diag_msg_mask_t *)(mask_info->ptr); + if (!mask->ptr) { + pr_err("diag: Invalid input in %s, mask->ptr: %pK\n", + __func__, mask->ptr); + mutex_unlock(&driver->msg_mask_lock); + mutex_unlock(&mask_info->lock); + return -EINVAL; + } for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { ptr = mask_info->update_buf; len = 0; @@ -1849,9 +2012,8 @@ int diag_copy_to_user_msg_mask(char __user *buf, size_t count, } total_len += len; } - mutex_unlock(&mask_info->lock); mutex_unlock(&driver->msg_mask_lock); - + mutex_unlock(&mask_info->lock); return err ? err : total_len; } @@ -1875,8 +2037,20 @@ int diag_copy_to_user_log_mask(char __user *buf, size_t count, if (!mask_info) return -EIO; + if (!mask_info->ptr || !mask_info->update_buf) { + pr_err("diag: In %s, invalid input mask_info->ptr: %pK, mask_info->update_buf: %pK\n", + __func__, mask_info->ptr, mask_info->update_buf); + return -EINVAL; + } + mutex_lock(&mask_info->lock); mask = (struct diag_log_mask_t *)(mask_info->ptr); + if (!mask->ptr) { + pr_err("diag: Invalid input in %s, mask->ptr: %pK\n", + __func__, mask->ptr); + mutex_unlock(&mask_info->lock); + return -EINVAL; + } for (i = 0; i < MAX_EQUIP_ID; i++, mask++) { ptr = mask_info->update_buf; len = 0; @@ -1929,14 +2103,12 @@ void diag_send_updates_peripheral(uint8_t peripheral) &driver->buffering_mode[peripheral]); } -int diag_process_apps_masks(unsigned char *buf, int len, - struct diag_md_session_t *info) +int diag_process_apps_masks(unsigned char *buf, int len, int pid) { int size = 0; int sub_cmd = 0; int (*hdlr)(unsigned char *src_buf, int src_len, - unsigned char *dest_buf, int dest_len, - struct diag_md_session_t *info) = NULL; + unsigned char *dest_buf, int dest_len, int pid) = NULL; if (!buf || len <= 0) return -EINVAL; @@ -1986,7 +2158,7 @@ int diag_process_apps_masks(unsigned char *buf, int len, if (hdlr) size = hdlr(buf, len, driver->apps_rsp_buf, - DIAG_MAX_RSP_SIZE, info); + DIAG_MAX_RSP_SIZE, pid); return (size > 0) ? size : 0; } diff --git a/drivers/char/diag/diag_masks.h b/drivers/char/diag/diag_masks.h index 1a52f946bb0..6edeee954d7 100644 --- a/drivers/char/diag/diag_masks.h +++ b/drivers/char/diag/diag_masks.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2015, 2018 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 @@ -167,8 +167,7 @@ int diag_event_mask_copy(struct diag_mask_info *dest, void diag_log_mask_free(struct diag_mask_info *mask_info); void diag_msg_mask_free(struct diag_mask_info *mask_info); void diag_event_mask_free(struct diag_mask_info *mask_info); -int diag_process_apps_masks(unsigned char *buf, int len, - struct diag_md_session_t *info); +int diag_process_apps_masks(unsigned char *buf, int len, int pid); void diag_send_updates_peripheral(uint8_t peripheral); extern int diag_create_msg_mask_table_entry(struct diag_msg_mask_t *msg_mask, diff --git a/drivers/char/diag/diag_memorydevice.c b/drivers/char/diag/diag_memorydevice.c index b4153c19618..aebeba83682 100644 --- a/drivers/char/diag/diag_memorydevice.c +++ b/drivers/char/diag/diag_memorydevice.c @@ -1,4 +1,5 @@ -/* Copyright (c) 2014-2015, 2016 The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2015, 2016, 2018 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 @@ -130,7 +131,7 @@ void diag_md_close_all() int diag_md_write(int id, unsigned char *buf, int len, int ctx) { - int i; + int i, pid = 0; uint8_t found = 0; unsigned long flags; struct diag_md_info *ch = NULL; @@ -147,9 +148,14 @@ int diag_md_write(int id, unsigned char *buf, int len, int ctx) if (peripheral > NUM_PERIPHERALS) return -EINVAL; + mutex_lock(&driver->md_session_lock); session_info = diag_md_session_get_peripheral(peripheral); - if (!session_info) + if (!session_info) { + mutex_unlock(&driver->md_session_lock); return -EIO; + } + pid = session_info->pid; + mutex_unlock(&driver->md_session_lock); ch = &diag_md[id]; @@ -187,8 +193,7 @@ int diag_md_write(int id, unsigned char *buf, int len, int ctx) found = 0; for (i = 0; i < driver->num_clients && !found; i++) { - if ((driver->client_map[i].pid != - session_info->pid) || + if ((driver->client_map[i].pid != pid) || (driver->client_map[i].pid == 0)) continue; diff --git a/drivers/char/diag/diag_usb.c b/drivers/char/diag/diag_usb.c index ca54b24ec60..562727ae7c7 100644 --- a/drivers/char/diag/diag_usb.c +++ b/drivers/char/diag/diag_usb.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2016, 2018 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 @@ -219,7 +219,7 @@ static void usb_disconnect(struct diag_usb_info *ch) return; if (!atomic_read(&ch->connected) && driver->usb_connected) - diag_clear_masks(NULL); + diag_clear_masks(0); if (ch && ch->ops && ch->ops->close) ch->ops->close(ch->ctxt, DIAG_USB_MODE); diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h index 0e74a855eb1..10ec0e9fe8b 100644 --- a/drivers/char/diag/diagchar.h +++ b/drivers/char/diag/diagchar.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2018, 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 @@ -627,7 +627,7 @@ void diag_cmd_remove_reg(struct diag_cmd_reg_entry_t *entry, uint8_t proc); void diag_cmd_remove_reg_by_pid(int pid); void diag_cmd_remove_reg_by_proc(int proc); int diag_cmd_chk_polling(struct diag_cmd_reg_entry_t *entry); -void diag_clear_masks(struct diag_md_session_t *info); +void diag_clear_masks(int pid); void diag_record_stats(int type, int flag); diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index 4ebaff20e09..7129e6b1064 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2018, 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 @@ -161,7 +161,7 @@ uint16_t diag_debug_mask; void *diag_ipc_log; #endif -static void diag_md_session_close(struct diag_md_session_t *session_info); +static void diag_md_session_close(int pid); /* * Returns the next delayed rsp id. If wrapping is enabled, @@ -200,6 +200,16 @@ do { \ ret += length; \ } while (0) +#define COPY_USER_SPACE_OR_ERR(buf, data, length) \ +do { \ + if ((count < ret+length) || (copy_to_user(buf, \ + (void *)&data, length))) { \ + ret = -EFAULT; \ + break; \ + } \ + ret += length; \ +} while (0) + static void drain_timer_func(unsigned long data) { queue_work(driver->diag_wq , &(driver->diag_drain_work)); @@ -238,12 +248,13 @@ void diag_drain_work_fn(struct work_struct *work) timer_in_progress = 0; mutex_lock(&apps_data_mutex); + mutex_lock(&driver->md_session_lock); session_info = diag_md_session_get_peripheral(APPS_DATA); if (session_info) hdlc_disabled = session_info->hdlc_disabled; else hdlc_disabled = driver->hdlc_disabled; - + mutex_unlock(&driver->md_session_lock); if (!hdlc_disabled) diag_drain_apps_data(&hdlc_data); else @@ -387,7 +398,7 @@ static uint32_t diag_translate_kernel_to_user_mask(uint32_t peripheral_mask) return ret; } -void diag_clear_masks(struct diag_md_session_t *info) +void diag_clear_masks(int pid) { int ret; char cmd_disable_log_mask[] = { 0x73, 0, 0, 0, 0, 0, 0, 0}; @@ -396,14 +407,14 @@ void diag_clear_masks(struct diag_md_session_t *info) DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "diag: %s: masks clear request upon %s\n", __func__, - ((info) ? "ODL exit" : "USB Disconnection")); + ((pid) ? "ODL exit" : "USB Disconnection")); ret = diag_process_apps_masks(cmd_disable_log_mask, - sizeof(cmd_disable_log_mask), info); + sizeof(cmd_disable_log_mask), pid); ret = diag_process_apps_masks(cmd_disable_msg_mask, - sizeof(cmd_disable_msg_mask), info); + sizeof(cmd_disable_msg_mask), pid); ret = diag_process_apps_masks(cmd_disable_event_mask, - sizeof(cmd_disable_event_mask), info); + sizeof(cmd_disable_event_mask), pid); DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "diag:%s: masks cleared successfully\n", __func__); } @@ -415,18 +426,22 @@ static void diag_close_logging_process(const int pid) struct diag_md_session_t *session_info = NULL; struct diag_logging_mode_param_t params; + mutex_lock(&driver->md_session_lock); session_info = diag_md_session_get_pid(pid); - if (!session_info) + if (!session_info) { + mutex_unlock(&driver->md_session_lock); return; + } + session_peripheral_mask = session_info->peripheral_mask; + mutex_unlock(&driver->md_session_lock); - diag_clear_masks(session_info); + diag_clear_masks(pid); mutex_lock(&driver->diag_maskclear_mutex); driver->mask_clear = 1; mutex_unlock(&driver->diag_maskclear_mutex); - session_peripheral_mask = session_info->peripheral_mask; - diag_md_session_close(session_info); + mutex_lock(&driver->diagchar_mutex); for (i = 0; i < NUM_MD_SESSIONS; i++) if (MD_PERIPHERAL_MASK(i) & session_peripheral_mask) diag_mux_close_peripheral(DIAG_LOCAL_PROC, i); @@ -435,7 +450,10 @@ static void diag_close_logging_process(const int pid) params.mode_param = 0; params.peripheral_mask = diag_translate_kernel_to_user_mask(session_peripheral_mask); - mutex_lock(&driver->diagchar_mutex); + + mutex_lock(&driver->md_session_lock); + diag_md_session_close(pid); + mutex_unlock(&driver->md_session_lock); diag_switch_logging(¶ms); mutex_unlock(&driver->diagchar_mutex); } @@ -946,11 +964,13 @@ static int diag_send_raw_data_remote(int proc, void *buf, int len, if (driver->hdlc_encode_buf_len != 0) return -EAGAIN; + mutex_lock(&driver->md_session_lock); session_info = diag_md_session_get_peripheral(APPS_DATA); if (session_info) hdlc_disabled = session_info->hdlc_disabled; else hdlc_disabled = driver->hdlc_disabled; + mutex_unlock(&driver->md_session_lock); if (hdlc_disabled) { payload = *(uint16_t *)(buf + 2); driver->hdlc_encode_buf_len = payload; @@ -1295,15 +1315,16 @@ int diag_md_session_create(int mode, int peripheral_mask, int proc) return err; } -static void diag_md_session_close(struct diag_md_session_t *session_info) +static void diag_md_session_close(int pid) { int i; uint8_t found = 0; + struct diag_md_session_t *session_info = NULL; + session_info = diag_md_session_get_pid(pid); if (!session_info) return; - mutex_lock(&driver->md_session_lock); for (i = 0; i < NUM_MD_SESSIONS; i++) { if (driver->md_session_map[i] != session_info) continue; @@ -1329,7 +1350,6 @@ static void diag_md_session_close(struct diag_md_session_t *session_info) driver->md_session_mode = (found) ? DIAG_MD_PERIPHERAL : DIAG_MD_NONE; kfree(session_info); session_info = NULL; - mutex_unlock(&driver->md_session_lock); DIAG_LOG(DIAG_DEBUG_USERSPACE, "cleared up session\n"); } @@ -1337,6 +1357,8 @@ struct diag_md_session_t *diag_md_session_get_pid(int pid) { int i; + if (pid <= 0) + return NULL; for (i = 0; i < NUM_MD_SESSIONS; i++) { if (driver->md_session_map[i] && driver->md_session_map[i]->pid == pid) @@ -1352,10 +1374,12 @@ struct diag_md_session_t *diag_md_session_get_peripheral(uint8_t peripheral) return driver->md_session_map[peripheral]; } -static int diag_md_peripheral_switch(struct diag_md_session_t *session_info, +static int diag_md_peripheral_switch(int pid, int peripheral_mask, int req_mode) { int i, bit = 0; + struct diag_md_session_t *session_info = NULL; + session_info = diag_md_session_get_pid(pid); if (!session_info) return -EINVAL; if (req_mode != DIAG_USB_MODE || req_mode != DIAG_MEMORY_DEVICE_MODE) @@ -1365,25 +1389,20 @@ static int diag_md_peripheral_switch(struct diag_md_session_t *session_info, * check that md_session_map for i == session_info, * if not then race condition occurred and bail */ - mutex_lock(&driver->md_session_lock); for (i = 0; i < NUM_MD_SESSIONS; i++) { bit = MD_PERIPHERAL_MASK(i) & peripheral_mask; if (!bit) continue; if (req_mode == DIAG_USB_MODE) { - if (driver->md_session_map[i] != session_info) { - mutex_unlock(&driver->md_session_lock); + if (driver->md_session_map[i] != session_info) return -EINVAL; - } driver->md_session_map[i] = NULL; driver->md_session_mask &= ~bit; session_info->peripheral_mask &= ~bit; } else { - if (driver->md_session_map[i] != NULL) { - mutex_unlock(&driver->md_session_lock); + if (driver->md_session_map[i] != NULL) return -EINVAL; - } driver->md_session_map[i] = session_info; driver->md_session_mask |= bit; session_info->peripheral_mask |= bit; @@ -1392,7 +1411,6 @@ static int diag_md_peripheral_switch(struct diag_md_session_t *session_info, } driver->md_session_mode = DIAG_MD_PERIPHERAL; - mutex_unlock(&driver->md_session_lock); DIAG_LOG(DIAG_DEBUG_USERSPACE, "Changed Peripherals:0x%x to mode:%d\n", peripheral_mask, req_mode); } @@ -1401,7 +1419,7 @@ static int diag_md_session_check(int curr_mode, int req_mode, const struct diag_logging_mode_param_t *param, uint8_t *change_mode) { - int i, bit = 0, err = 0; + int i, bit = 0, err = 0, peripheral_mask = 0; int change_mask = 0; struct diag_md_session_t *session_info = NULL; @@ -1425,12 +1443,13 @@ static int diag_md_session_check(int curr_mode, int req_mode, if (req_mode == DIAG_USB_MODE) { if (curr_mode == DIAG_USB_MODE) return 0; + mutex_lock(&driver->md_session_lock); if (driver->md_session_mode == DIAG_MD_NONE && driver->md_session_mask == 0 && driver->logging_mask) { *change_mode = 1; + mutex_unlock(&driver->md_session_lock); return 0; } - /* * curr_mode is either DIAG_MULTI_MODE or DIAG_MD_MODE * Check if requested peripherals are already in usb mode @@ -1442,8 +1461,10 @@ static int diag_md_session_check(int curr_mode, int req_mode, if (bit & driver->logging_mask) change_mask |= bit; } - if (!change_mask) + if (!change_mask) { + mutex_unlock(&driver->md_session_lock); return 0; + } /* * Change is needed. Check if this md_session has set all the @@ -1455,23 +1476,26 @@ static int diag_md_session_check(int curr_mode, int req_mode, session_info = diag_md_session_get_pid(current->tgid); if (!session_info) { *change_mode = 1; + mutex_unlock(&driver->md_session_lock); return 0; } - if ((change_mask & session_info->peripheral_mask) + peripheral_mask = session_info->peripheral_mask; + if ((change_mask & peripheral_mask) != change_mask) { DIAG_LOG(DIAG_DEBUG_USERSPACE, "Another MD Session owns a requested peripheral\n"); + mutex_unlock(&driver->md_session_lock); return -EINVAL; } *change_mode = 1; /* If all peripherals are being set to USB Mode, call close */ - if (~change_mask & session_info->peripheral_mask) { - err = diag_md_peripheral_switch(session_info, + if (~change_mask & peripheral_mask) { + err = diag_md_peripheral_switch(current->tgid, change_mask, DIAG_USB_MODE); } else - diag_md_session_close(session_info); - + diag_md_session_close(current->tgid); + mutex_unlock(&driver->md_session_lock); return err; } else if (req_mode == DIAG_MEMORY_DEVICE_MODE) { @@ -1480,6 +1504,7 @@ static int diag_md_session_check(int curr_mode, int req_mode, * been set. Check that requested peripherals already set are * owned by this md session */ + mutex_lock(&driver->md_session_lock); change_mask = driver->md_session_mask & param->peripheral_mask; session_info = diag_md_session_get_pid(current->tgid); @@ -1488,11 +1513,14 @@ static int diag_md_session_check(int curr_mode, int req_mode, != change_mask) { DIAG_LOG(DIAG_DEBUG_USERSPACE, "Another MD Session owns a requested peripheral\n"); + mutex_unlock(&driver->md_session_lock); return -EINVAL; } - err = diag_md_peripheral_switch(session_info, + err = diag_md_peripheral_switch(current->tgid, change_mask, DIAG_USB_MODE); + mutex_unlock(&driver->md_session_lock); } else { + mutex_unlock(&driver->md_session_lock); if (change_mask) { DIAG_LOG(DIAG_DEBUG_USERSPACE, "Another MD Session owns a requested peripheral\n"); @@ -1870,17 +1898,17 @@ static int diag_ioctl_hdlc_toggle(unsigned long ioarg) uint8_t hdlc_support; struct diag_md_session_t *session_info = NULL; - session_info = diag_md_session_get_pid(current->tgid); if (copy_from_user(&hdlc_support, (void __user *)ioarg, sizeof(uint8_t))) return -EFAULT; mutex_lock(&driver->hdlc_disable_mutex); - if (session_info) { - mutex_lock(&driver->md_session_lock); + mutex_lock(&driver->md_session_lock); + session_info = diag_md_session_get_pid(current->tgid); + if (session_info) session_info->hdlc_disabled = hdlc_support; - mutex_unlock(&driver->md_session_lock); - } else + else driver->hdlc_disabled = hdlc_support; + mutex_unlock(&driver->md_session_lock); mutex_unlock(&driver->hdlc_disable_mutex); diag_update_md_clients(HDLC_SUPPORT_TYPE); @@ -2531,7 +2559,6 @@ static int diag_user_process_raw_data(const char __user *buf, int len) int remote_proc = 0; const int mempool = POOL_TYPE_COPY; unsigned char *user_space_data = NULL; - struct diag_md_session_t *info = NULL; if (!buf || len <= 0 || len > CALLBACK_BUF_SIZE) { pr_err_ratelimited("diag: In %s, invalid buf %pK len: %d\n", @@ -2582,8 +2609,8 @@ static int diag_user_process_raw_data(const char __user *buf, int len) } else { wait_event_interruptible(driver->wait_q, (driver->in_busy_pktdata == 0)); - info = diag_md_session_get_pid(current->tgid); - ret = diag_process_apps_pkt(user_space_data, len, info); + ret = diag_process_apps_pkt(user_space_data, len, + current->tgid); if (ret == 1) diag_send_error_rsp((void *)(user_space_data), len); } @@ -2649,24 +2676,27 @@ static int diag_user_process_userspace_data(const char __user *buf, int len) /* send masks to local processor now */ if (!remote_proc) { + mutex_lock(&driver->md_session_lock); session_info = diag_md_session_get_pid(current->tgid); if (!session_info) { pr_err("diag:In %s request came from invalid md session pid:%d", __func__, current->tgid); + mutex_unlock(&driver->md_session_lock); return -EINVAL; } if (session_info) hdlc_disabled = session_info->hdlc_disabled; else hdlc_disabled = driver->hdlc_disabled; + mutex_unlock(&driver->md_session_lock); if (!hdlc_disabled) diag_process_hdlc_pkt((void *) (driver->user_space_data_buf), - len, session_info); + len, current->tgid); else diag_process_non_hdlc_pkt((char *) (driver->user_space_data_buf), - len, session_info); + len, current->tgid); return 0; } @@ -2743,11 +2773,13 @@ static int diag_user_process_apps_data(const char __user *buf, int len, mutex_lock(&apps_data_mutex); mutex_lock(&driver->hdlc_disable_mutex); + mutex_lock(&driver->md_session_lock); session_info = diag_md_session_get_peripheral(APPS_DATA); if (session_info) hdlc_disabled = session_info->hdlc_disabled; else hdlc_disabled = driver->hdlc_disabled; + mutex_unlock(&driver->md_session_lock); if (hdlc_disabled) ret = diag_process_apps_data_non_hdlc(user_space_data, len, pkt_type); @@ -2810,9 +2842,11 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, COPY_USER_SPACE_OR_EXIT(buf, data_type, sizeof(int)); /* place holder for number of data field */ ret += sizeof(int); + mutex_lock(&driver->md_session_lock); session_info = diag_md_session_get_pid(current->tgid); exit_stat = diag_md_copy_to_user(buf, &ret, count, session_info); + mutex_unlock(&driver->md_session_lock); goto exit; } else if (driver->data_ready[index] & USER_SPACE_DATA_TYPE) { /* In case, the thread wakes up and the logging mode is @@ -2824,11 +2858,18 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, data_type = driver->data_ready[index] & HDLC_SUPPORT_TYPE; driver->data_ready[index] ^= HDLC_SUPPORT_TYPE; COPY_USER_SPACE_OR_EXIT(buf, data_type, sizeof(int)); + mutex_lock(&driver->md_session_lock); session_info = diag_md_session_get_pid(current->tgid); - if (session_info) - COPY_USER_SPACE_OR_EXIT(buf+4, + if (session_info) { + COPY_USER_SPACE_OR_ERR(buf+4, session_info->hdlc_disabled, sizeof(uint8_t)); + if (ret == -EFAULT) { + mutex_unlock(&driver->md_session_lock); + goto exit; + } + } + mutex_unlock(&driver->md_session_lock); goto exit; } @@ -2845,10 +2886,16 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, if (driver->data_ready[index] & MSG_MASKS_TYPE) { /*Copy the type of data being passed*/ data_type = driver->data_ready[index] & MSG_MASKS_TYPE; + mutex_lock(&driver->md_session_lock); session_info = diag_md_session_get_peripheral(APPS_DATA); - COPY_USER_SPACE_OR_EXIT(buf, data_type, sizeof(int)); + COPY_USER_SPACE_OR_ERR(buf, data_type, sizeof(int)); + if (ret == -EFAULT) { + mutex_unlock(&driver->md_session_lock); + goto exit; + } write_len = diag_copy_to_user_msg_mask(buf + ret, count, session_info); + mutex_unlock(&driver->md_session_lock); if (write_len > 0) ret += write_len; driver->data_ready[index] ^= MSG_MASKS_TYPE; @@ -2858,18 +2905,32 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, if (driver->data_ready[index] & EVENT_MASKS_TYPE) { /*Copy the type of data being passed*/ data_type = driver->data_ready[index] & EVENT_MASKS_TYPE; + mutex_lock(&driver->md_session_lock); session_info = diag_md_session_get_peripheral(APPS_DATA); - COPY_USER_SPACE_OR_EXIT(buf, data_type, 4); + COPY_USER_SPACE_OR_ERR(buf, data_type, 4); + if (ret == -EFAULT) { + mutex_unlock(&driver->md_session_lock); + goto exit; + } if (session_info && session_info->event_mask && session_info->event_mask->ptr) { - COPY_USER_SPACE_OR_EXIT(buf + sizeof(int), + COPY_USER_SPACE_OR_ERR(buf + sizeof(int), *(session_info->event_mask->ptr), session_info->event_mask->mask_len); + if (ret == -EFAULT) { + mutex_unlock(&driver->md_session_lock); + goto exit; + } } else { - COPY_USER_SPACE_OR_EXIT(buf + sizeof(int), + COPY_USER_SPACE_OR_ERR(buf + sizeof(int), *(event_mask.ptr), event_mask.mask_len); + if (ret == -EFAULT) { + mutex_unlock(&driver->md_session_lock); + goto exit; + } } + mutex_unlock(&driver->md_session_lock); driver->data_ready[index] ^= EVENT_MASKS_TYPE; goto exit; } @@ -2877,10 +2938,16 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, if (driver->data_ready[index] & LOG_MASKS_TYPE) { /*Copy the type of data being passed*/ data_type = driver->data_ready[index] & LOG_MASKS_TYPE; + mutex_lock(&driver->md_session_lock); session_info = diag_md_session_get_peripheral(APPS_DATA); - COPY_USER_SPACE_OR_EXIT(buf, data_type, sizeof(int)); + COPY_USER_SPACE_OR_ERR(buf, data_type, sizeof(int)); + if (ret == -EFAULT) { + mutex_unlock(&driver->md_session_lock); + goto exit; + } write_len = diag_copy_to_user_log_mask(buf + ret, count, session_info); + mutex_unlock(&driver->md_session_lock); if (write_len > 0) ret += write_len; driver->data_ready[index] ^= LOG_MASKS_TYPE; diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c index 60d126acae9..e5fd8aeab1c 100644 --- a/drivers/char/diag/diagfwd.c +++ b/drivers/char/diag/diagfwd.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2018, 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 @@ -281,8 +281,11 @@ static void pack_rsp_and_send(unsigned char *buf, int len) * draining responses when we are in Memory Device Mode. */ if (driver->logging_mode == DIAG_MEMORY_DEVICE_MODE || - driver->logging_mode == DIAG_MULTI_MODE) + driver->logging_mode == DIAG_MULTI_MODE) { + mutex_lock(&driver->md_session_lock); chk_logging_wakeup(); + mutex_unlock(&driver->md_session_lock); + } } if (driver->rsp_buf_busy) { pr_err("diag: unable to get hold of response buffer\n"); @@ -350,8 +353,11 @@ static void encode_rsp_and_send(unsigned char *buf, int len) * draining responses when we are in Memory Device Mode. */ if (driver->logging_mode == DIAG_MEMORY_DEVICE_MODE || - driver->logging_mode == DIAG_MULTI_MODE) + driver->logging_mode == DIAG_MULTI_MODE) { + mutex_lock(&driver->md_session_lock); chk_logging_wakeup(); + mutex_unlock(&driver->md_session_lock); + } } if (driver->rsp_buf_busy) { @@ -387,12 +393,13 @@ void diag_send_rsp(unsigned char *buf, int len) struct diag_md_session_t *session_info = NULL; uint8_t hdlc_disabled; + mutex_lock(&driver->md_session_lock); session_info = diag_md_session_get_peripheral(APPS_DATA); if (session_info) hdlc_disabled = session_info->hdlc_disabled; else hdlc_disabled = driver->hdlc_disabled; - + mutex_unlock(&driver->md_session_lock); if (hdlc_disabled) pack_rsp_and_send(buf, len); else @@ -460,6 +467,7 @@ void diag_update_md_clients(unsigned int type) int i, j; mutex_lock(&driver->diagchar_mutex); + mutex_lock(&driver->md_session_lock); for (i = 0; i < NUM_MD_SESSIONS; i++) { if (driver->md_session_map[i] != NULL) for (j = 0; j < driver->num_clients; j++) { @@ -471,6 +479,7 @@ void diag_update_md_clients(unsigned int type) } } } + mutex_unlock(&driver->md_session_lock); wake_up_interruptible(&driver->wait_q); mutex_unlock(&driver->diagchar_mutex); } @@ -871,22 +880,22 @@ void diag_send_error_rsp(unsigned char *buf, int len) diag_send_rsp(driver->apps_rsp_buf, len + 1); } -int diag_process_apps_pkt(unsigned char *buf, int len, - struct diag_md_session_t *info) +int diag_process_apps_pkt(unsigned char *buf, int len, int pid) { - int i; + int i, p_mask = 0; int mask_ret; int write_len = 0; unsigned char *temp = NULL; struct diag_cmd_reg_entry_t entry; struct diag_cmd_reg_entry_t *temp_entry = NULL; struct diag_cmd_reg_t *reg_item = NULL; + struct diag_md_session_t *info = NULL; if (!buf) return -EIO; /* Check if the command is a supported mask command */ - mask_ret = diag_process_apps_masks(buf, len, info); + mask_ret = diag_process_apps_masks(buf, len, pid); if (mask_ret > 0) { diag_send_rsp(driver->apps_rsp_buf, mask_ret); return 0; @@ -919,11 +928,15 @@ int diag_process_apps_pkt(unsigned char *buf, int len, if (temp_entry) { reg_item = container_of(temp_entry, struct diag_cmd_reg_t, entry); + mutex_lock(&driver->md_session_lock); + info = diag_md_session_get_pid(pid); if (info) { - if (MD_PERIPHERAL_MASK(reg_item->proc) & - info->peripheral_mask) + p_mask = info->peripheral_mask; + mutex_unlock(&driver->md_session_lock); + if (MD_PERIPHERAL_MASK(reg_item->proc) & p_mask) write_len = diag_send_data(reg_item, buf, len); } else { + mutex_unlock(&driver->md_session_lock); if (MD_PERIPHERAL_MASK(reg_item->proc) & driver->logging_mask) diag_send_error_rsp(buf, len); @@ -1088,10 +1101,13 @@ int diag_process_apps_pkt(unsigned char *buf, int len, */ pr_debug("diag: In %s, disabling HDLC encoding\n", __func__); + mutex_lock(&driver->md_session_lock); + info = diag_md_session_get_pid(pid); if (info) info->hdlc_disabled = 1; else driver->hdlc_disabled = 1; + mutex_unlock(&driver->md_session_lock); diag_update_md_clients(HDLC_SUPPORT_TYPE); mutex_unlock(&driver->hdlc_disable_mutex); return 0; @@ -1105,8 +1121,7 @@ int diag_process_apps_pkt(unsigned char *buf, int len, return 0; } -void diag_process_hdlc_pkt(void *data, unsigned len, - struct diag_md_session_t *info) +void diag_process_hdlc_pkt(void *data, unsigned len, int pid) { int err = 0; int ret = 0; @@ -1166,7 +1181,7 @@ void diag_process_hdlc_pkt(void *data, unsigned len, } err = diag_process_apps_pkt(driver->hdlc_buf, - driver->hdlc_buf_len, info); + driver->hdlc_buf_len, pid); if (err < 0) goto fail; } else { @@ -1266,8 +1281,12 @@ static int diagfwd_mux_close(int id, int mode) static uint8_t hdlc_reset; -static void hdlc_reset_timer_start(struct diag_md_session_t *info) +static void hdlc_reset_timer_start(int pid) { + struct diag_md_session_t *info = NULL; + + mutex_lock(&driver->md_session_lock); + info = diag_md_session_get_pid(pid); if (!hdlc_timer_in_progress) { hdlc_timer_in_progress = 1; if (info) @@ -1277,6 +1296,7 @@ static void hdlc_reset_timer_start(struct diag_md_session_t *info) mod_timer(&driver->hdlc_reset_timer, jiffies + msecs_to_jiffies(200)); } + mutex_unlock(&driver->md_session_lock); } static void hdlc_reset_timer_func(unsigned long data) @@ -1308,15 +1328,16 @@ void diag_md_hdlc_reset_timer_func(unsigned long pid) } static void diag_hdlc_start_recovery(unsigned char *buf, int len, - struct diag_md_session_t *info) + int pid) { int i; static uint32_t bad_byte_counter; unsigned char *start_ptr = NULL; struct diag_pkt_frame_t *actual_pkt = NULL; + struct diag_md_session_t *info = NULL; hdlc_reset = 1; - hdlc_reset_timer_start(info); + hdlc_reset_timer_start(pid); actual_pkt = (struct diag_pkt_frame_t *)buf; for (i = 0; i < len; i++) { @@ -1335,10 +1356,13 @@ static void diag_hdlc_start_recovery(unsigned char *buf, int len, pr_err("diag: In %s, re-enabling HDLC encoding\n", __func__); mutex_lock(&driver->hdlc_disable_mutex); + mutex_lock(&driver->md_session_lock); + info = diag_md_session_get_pid(pid); if (info) info->hdlc_disabled = 0; else driver->hdlc_disabled = 0; + mutex_unlock(&driver->md_session_lock); mutex_unlock(&driver->hdlc_disable_mutex); diag_update_md_clients(HDLC_SUPPORT_TYPE); @@ -1351,12 +1375,11 @@ static void diag_hdlc_start_recovery(unsigned char *buf, int len, mutex_lock(&driver->hdlc_recovery_mutex); driver->incoming_pkt.processing = 0; mutex_unlock(&driver->hdlc_recovery_mutex); - diag_process_non_hdlc_pkt(start_ptr, len - i, info); + diag_process_non_hdlc_pkt(start_ptr, len - i, pid); } } -void diag_process_non_hdlc_pkt(unsigned char *buf, int len, - struct diag_md_session_t *info) +void diag_process_non_hdlc_pkt(unsigned char *buf, int len, int pid) { int err = 0; uint16_t pkt_len = 0; @@ -1412,11 +1435,11 @@ void diag_process_non_hdlc_pkt(unsigned char *buf, int len, if (*(uint8_t *)(data_ptr + actual_pkt->length) != CONTROL_CHAR) { mutex_unlock(&driver->hdlc_recovery_mutex); - diag_hdlc_start_recovery(buf, len, info); + diag_hdlc_start_recovery(buf, len, pid); mutex_lock(&driver->hdlc_recovery_mutex); } err = diag_process_apps_pkt(data_ptr, - actual_pkt->length, info); + actual_pkt->length, pid); if (err) { pr_err("diag: In %s, unable to process incoming data packet, err: %d\n", __func__, err); @@ -1438,7 +1461,7 @@ void diag_process_non_hdlc_pkt(unsigned char *buf, int len, pkt_len = actual_pkt->length; if (actual_pkt->start != CONTROL_CHAR) { - diag_hdlc_start_recovery(buf, len, info); + diag_hdlc_start_recovery(buf, len, pid); diag_send_error_rsp(buf, len); goto end; } @@ -1447,7 +1470,7 @@ void diag_process_non_hdlc_pkt(unsigned char *buf, int len, pr_err("diag: In %s, incoming data is too large for the request buffer %d\n", __func__, pkt_len); mutex_unlock(&driver->hdlc_recovery_mutex); - diag_hdlc_start_recovery(buf, len, info); + diag_hdlc_start_recovery(buf, len, pid); break; } if ((pkt_len + header_len) > (len - read_bytes)) { @@ -1464,13 +1487,13 @@ void diag_process_non_hdlc_pkt(unsigned char *buf, int len, if (*(uint8_t *)(data_ptr + actual_pkt->length) != CONTROL_CHAR) { mutex_unlock(&driver->hdlc_recovery_mutex); - diag_hdlc_start_recovery(buf, len, info); + diag_hdlc_start_recovery(buf, len, pid); mutex_lock(&driver->hdlc_recovery_mutex); } else hdlc_reset = 0; err = diag_process_apps_pkt(data_ptr, - actual_pkt->length, info); + actual_pkt->length, pid); if (err) { mutex_unlock(&driver->hdlc_recovery_mutex); break; @@ -1489,9 +1512,9 @@ static int diagfwd_mux_read_done(unsigned char *buf, int len, int ctxt) return -EINVAL; if (!driver->hdlc_disabled) - diag_process_hdlc_pkt(buf, len, NULL); + diag_process_hdlc_pkt(buf, len, 0); else - diag_process_non_hdlc_pkt(buf, len, NULL); + diag_process_non_hdlc_pkt(buf, len, 0); diag_mux_queue_read(ctxt); return 0; diff --git a/drivers/char/diag/diagfwd.h b/drivers/char/diag/diagfwd.h index 0023e0638aa..0f98df19cdd 100644 --- a/drivers/char/diag/diagfwd.h +++ b/drivers/char/diag/diagfwd.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2015, 2018 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 @@ -28,10 +28,8 @@ int diagfwd_init(void); void diagfwd_exit(void); -void diag_process_hdlc_pkt(void *data, unsigned len, - struct diag_md_session_t *info); -void diag_process_non_hdlc_pkt(unsigned char *data, int len, - struct diag_md_session_t *info); +void diag_process_hdlc_pkt(void *data, unsigned int len, int pid); +void diag_process_non_hdlc_pkt(unsigned char *data, int len, int pid); int chk_config_get_id(void); int chk_apps_only(void); int chk_apps_master(void); @@ -43,8 +41,7 @@ int diag_cmd_get_mobile_id(unsigned char *src_buf, int src_len, int diag_check_common_cmd(struct diag_pkt_header_t *header); void diag_update_userspace_clients(unsigned int type); void diag_update_sleeping_process(int process_id, int data_type); -int diag_process_apps_pkt(unsigned char *buf, int len, - struct diag_md_session_t *info); +int diag_process_apps_pkt(unsigned char *buf, int len, int pid); void diag_send_error_rsp(unsigned char *buf, int len); void diag_update_pkt_buffer(unsigned char *buf, uint32_t len, int type); int diag_process_stm_cmd(unsigned char *buf, unsigned char *dest_buf); diff --git a/drivers/char/diag/diagfwd_peripheral.c b/drivers/char/diag/diagfwd_peripheral.c index f353ad18f11..c798bf05b2f 100644 --- a/drivers/char/diag/diagfwd_peripheral.c +++ b/drivers/char/diag/diagfwd_peripheral.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, 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 @@ -240,12 +240,13 @@ static void diagfwd_data_read_done(struct diagfwd_info *fwd_info, mutex_lock(&driver->hdlc_disable_mutex); mutex_lock(&fwd_info->data_mutex); + mutex_lock(&driver->md_session_lock); session_info = diag_md_session_get_peripheral(fwd_info->peripheral); if (session_info) hdlc_disabled = session_info->hdlc_disabled; else hdlc_disabled = driver->hdlc_disabled; - + mutex_unlock(&driver->md_session_lock); if (!driver->feature[fwd_info->peripheral].encode_hdlc) { if (fwd_info->buf_1 && fwd_info->buf_1->data == buf) { temp_buf = fwd_info->buf_1; From 7cf39fd94687f50c3f4265da111b80e9566c6a8f Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 14 Feb 2018 15:45:07 -0800 Subject: [PATCH 23/53] NFC: llcp: Limit size of SDP URI [ Upstream commit fe9c842695e26d8116b61b80bfb905356f07834b ] The tlv_len is u8, so we need to limit the size of the SDP URI. Enforce this both in the NLA policy and in the code that performs the allocation and copy, to avoid writing past the end of the allocated buffer. Fixes: d9b8d8e19b073 ("NFC: llcp: Service Name Lookup netlink interface") Bug: 73083945 Signed-off-by: Kees Cook Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman Change-Id: I2eb83f2f1bfe83ff4828d70dddc77a42f1039d54 --- net/nfc/llcp_commands.c | 4 ++++ net/nfc/netlink.c | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/net/nfc/llcp_commands.c b/net/nfc/llcp_commands.c index a3ad69a4c64..1e7245792fc 100644 --- a/net/nfc/llcp_commands.c +++ b/net/nfc/llcp_commands.c @@ -149,6 +149,10 @@ struct nfc_llcp_sdp_tlv *nfc_llcp_build_sdreq_tlv(u8 tid, char *uri, pr_debug("uri: %s, len: %zu\n", uri, uri_len); + /* sdreq->tlv_len is u8, takes uri_len, + 3 for header, + 1 for NULL */ + if (WARN_ON_ONCE(uri_len > U8_MAX - 4)) + return NULL; + sdreq = kzalloc(sizeof(struct nfc_llcp_sdp_tlv), GFP_KERNEL); if (sdreq == NULL) return NULL; diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c index c4dc3132752..982db48693a 100644 --- a/net/nfc/netlink.c +++ b/net/nfc/netlink.c @@ -60,7 +60,8 @@ static const struct nla_policy nfc_genl_policy[NFC_ATTR_MAX + 1] = { }; static const struct nla_policy nfc_sdp_genl_policy[NFC_SDP_ATTR_MAX + 1] = { - [NFC_SDP_ATTR_URI] = { .type = NLA_STRING }, + [NFC_SDP_ATTR_URI] = { .type = NLA_STRING, + .len = U8_MAX - 4 }, [NFC_SDP_ATTR_SAP] = { .type = NLA_U8 }, }; From a3a130c45817bfeca266a1456ee27735c5a4504b Mon Sep 17 00:00:00 2001 From: Rohit Gupta Date: Wed, 3 Aug 2016 12:04:51 -0700 Subject: [PATCH 24/53] PM / devfreq: memlat: Remove kfree() on probe fails Memory allocated with devm_kzalloc() is automatically freed if the probe function fails and returns an error code. So there is no need to free cpu_grp explicitly for the failure cases that might come up after it is allocated. Additionally calls to devm_kzalloc() must be accompanied by devm_kfree() if memory deallocation is necessary. For these reasons remove the kfree(cpu_grp) from the probe function. Bug: 109741853 Change-Id: Ic4838fd58d40d283ac301facc64b06813eb3bd7d Signed-off-by: Rohit Gupta --- drivers/devfreq/arm-memlat-mon.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/devfreq/arm-memlat-mon.c b/drivers/devfreq/arm-memlat-mon.c index 370d7d95042..4fb0a5ffda5 100644 --- a/drivers/devfreq/arm-memlat-mon.c +++ b/drivers/devfreq/arm-memlat-mon.c @@ -311,19 +311,19 @@ static int arm_memlat_mon_driver_probe(struct platform_device *pdev) hw->of_node = of_parse_phandle(dev->of_node, "qcom,target-dev", 0); if (!hw->of_node) { dev_err(dev, "Couldn't find a target device\n"); - goto err_out; + return -ENODEV; } if (get_mask_from_dev_handle(pdev, &cpu_grp->cpus)) { dev_err(dev, "CPU list is empty\n"); - goto err_out; + return -ENODEV; } hw->num_cores = cpumask_weight(&cpu_grp->cpus); hw->core_stats = devm_kzalloc(dev, hw->num_cores * sizeof(*(hw->core_stats)), GFP_KERNEL); if (!hw->core_stats) - goto err_out; + return -ENOMEM; for_each_cpu(cpu, &cpu_grp->cpus) hw->core_stats[cpu - cpumask_first(&cpu_grp->cpus)].id = cpu; @@ -335,14 +335,10 @@ static int arm_memlat_mon_driver_probe(struct platform_device *pdev) ret = register_memlat(dev, hw); if (ret) { pr_err("Mem Latency Gov registration failed\n"); - goto err_out; + return ret; } return 0; - -err_out: - kfree(cpu_grp); - return -EINVAL; } static struct of_device_id match_table[] = { From 2895d3721aff533cb4fa680efaf87f7de70e5677 Mon Sep 17 00:00:00 2001 From: Min Liu Date: Wed, 28 Mar 2018 13:20:13 +0800 Subject: [PATCH 25/53] qcacld-2.0: Fix UAF in WLAN HDD UAF issue is in function hdd_open_adapter: pAdapter is freed by calling free_netdev(pAdapter->dev), but pAdapter->macAddressCurrent.bytes is referenced afterwards. Fix the issue by swapping these two statements. Bug: 65423852 Change-Id: I6910a56f9a204fdd8eaad54d8443867ee6a37fdb CRs-Fixed: 2213280 Signed-off-by: Ecco Park --- drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_main.c b/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_main.c index bd1ef68b170..3d36b009454 100644 --- a/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_main.c +++ b/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_main.c @@ -11296,9 +11296,9 @@ hdd_adapter_t* hdd_open_adapter( hdd_context_t *pHddCtx, tANI_U8 session_type, return pAdapter; err_free_netdev: - free_netdev(pAdapter->dev); wlan_hdd_release_intf_addr( pHddCtx, - pAdapter->macAddressCurrent.bytes ); + pAdapter->macAddressCurrent.bytes); + free_netdev(pAdapter->dev); resume_bmps: //If bmps disabled enable it From f0896368ae8009e8ec4ea45465b6a1239a41b7fd Mon Sep 17 00:00:00 2001 From: tinlin Date: Mon, 26 Mar 2018 19:51:19 +0800 Subject: [PATCH 26/53] qcacld-2.0: Fix OOB write in wma_passpoint_match_event_handler Propagation from cld3.0 to cld2.0. In the function wma_passpoint_match_event_handler, fixed param event data from firmware is filled in the destination buffer and indication is sent to upper layers. The buffer allocation is done for the size (wmi_passpoint_event_hdr*) + event->ie_length + event->anqp_length. The maximum firmware event message size is WMI_SVC_MSG_MAX_SIZE. If either, ie_length and anqp_length combined is greater than WMI_SVC_MSG_MAX_SIZE or either of the two exceeds WMI_SVC_MSG_MAC_SIZE, an OOB write will occur in wma_passpoint_match_event_handler. Add check to ensure either of the values ie_length or anqp_lenth or (ie_length + anqp_length) doesnt exceed the WMI_SVC_MAX_SIZE. Return failure if it exceeds. Bug: 109741911 Change-Id: I21f473ca0b99ebb8488f2cca3c0774817ea97c3a CRs-Fixed: 2212696 Signed-off-by: Ecco Park --- .../qcacld-2.0/CORE/SERVICES/WMA/wma.c | 36 +++++++++++++------ 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c index d48e37bdd7b..12fc20ad045 100644 --- a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c +++ b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c @@ -4539,7 +4539,8 @@ static int wma_passpoint_match_event_handler(void *handle, struct wifi_passpoint_match *dest_match; tSirWifiScanResult *dest_ap; uint8_t *buf_ptr; - + uint32_t buf_len = 0; + bool excess_data = false; tpAniSirGlobal pMac = (tpAniSirGlobal )vos_get_context( VOS_MODULE_ID_PE, wma->vos_context); if (!pMac) { @@ -4558,14 +4559,28 @@ static int wma_passpoint_match_event_handler(void *handle, event = param_buf->fixed_param; buf_ptr = (uint8_t *)param_buf->fixed_param; - /* - * All the below lengths are UINT32 and summing up and checking - * against a constant should not be an issue. - */ - if ((sizeof(*event) + event->ie_length + event->anqp_length) > - WMA_SVC_MSG_MAX_SIZE) { - WMA_LOGE("IE Length: %d or ANQP Length: %d is huge", - event->ie_length, event->anqp_length); + do { + if (event->ie_length > (WMA_SVC_MSG_MAX_SIZE)) { + excess_data = true; + break; + } else { + buf_len = event->ie_length; + } + + if (event->anqp_length > (WMA_SVC_MSG_MAX_SIZE)) { + excess_data = true; + break; + } else { + buf_len += event->anqp_length; + } + } while (0); + + if (excess_data || buf_len > (WMA_SVC_MSG_MAX_SIZE - sizeof(*event)) || + buf_len > (WMA_SVC_MSG_MAX_SIZE - sizeof(*dest_match)) || + (event->ie_length + event->anqp_length) > param_buf->num_bufp) { + WMA_LOGE("IE Length: %d or ANQP Length: %d is huge, num_bufp %d", + event->ie_length, event->anqp_length, + param_buf->num_bufp); return -EINVAL; } if (event->ssid.ssid_len > SIR_MAC_MAX_SSID_LENGTH) { @@ -4573,8 +4588,7 @@ static int wma_passpoint_match_event_handler(void *handle, __func__, event->ssid.ssid_len); event->ssid.ssid_len = SIR_MAC_MAX_SSID_LENGTH; } - dest_match = vos_mem_malloc(sizeof(*dest_match) + - event->ie_length + event->anqp_length); + dest_match = vos_mem_malloc(sizeof(*dest_match) + buf_len); if (!dest_match) { WMA_LOGE("%s: vos_mem_malloc failed", __func__); return -EINVAL; From de15da29831ea635a98615ee90caa72563bb9052 Mon Sep 17 00:00:00 2001 From: Arun Kumar Neelakantam Date: Thu, 29 Mar 2018 20:10:02 +0530 Subject: [PATCH 27/53] net: ipc_router: Fix buffer overflow during memcpy The increment logic of u64 pointer in skb_copy_to_log_buf() leads to buffer overflow. Modify the proto type of skb_copy_to_log_buf() function to accept only unsigned char pointer. CRs-Fixed: 2212592 Bug: 109741922 Change-Id: I8affff1316656c1060ec57f2fb10b46f85314358 Signed-off-by: Arun Kumar Neelakantam --- net/ipc_router/ipc_router_core.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/net/ipc_router/ipc_router_core.c b/net/ipc_router/ipc_router_core.c index c327bea03b1..12775763761 100644 --- a/net/ipc_router/ipc_router_core.c +++ b/net/ipc_router/ipc_router_core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2016, 2018, 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 @@ -269,7 +269,7 @@ static uint32_t ipc_router_calc_checksum(union rr_control_msg *msg) */ static void skb_copy_to_log_buf(struct sk_buff_head *skb_head, unsigned int pl_len, unsigned int hdr_offset, - uint64_t *log_buf) + unsigned char *log_buf) { struct sk_buff *temp_skb; unsigned int copied_len = 0, copy_len = 0; @@ -349,7 +349,8 @@ static void ipc_router_log_msg(void *log_ctx, uint32_t xchng_type, else if (hdr->version == IPC_ROUTER_V2) hdr_offset = sizeof(struct rr_header_v2); } - skb_copy_to_log_buf(skb_head, buf_len, hdr_offset, &pl_buf); + skb_copy_to_log_buf(skb_head, buf_len, hdr_offset, + (unsigned char *)&pl_buf); if (port_ptr && rport_ptr && (port_ptr->type == CLIENT_PORT) && (rport_ptr->server != NULL)) { From 09ec05ace0cd6dba97d9b3abedc1d680819a827c Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Tue, 28 Jun 2016 18:07:30 +0100 Subject: [PATCH 28/53] arm64: errata: Calling enable functions for CPU errata too Currently we call the (optional) enable function for CPU _features_ only. As CPU _errata_ descriptions share the same data structure and having an enable function is useful for errata as well (for instance to set bits in SCTLR), lets call it when enumerating erratas too. Bug: 79422410 Change-Id: If9eff7dd87d7ebcf8ee44ae0cc326f91e2c16af8 Signed-off-by: Andre Przywara Reviewed-by: Suzuki K Poulose Signed-off-by: Catalin Marinas Git-commit: 8e2318521bf5837dae093413f81292b59d49d030 Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux [neeraju@codeaurora.org: resolve trivial merge conflicts] Signed-off-by: Neeraj Upadhyay Signed-off-by: Shiraz Hashim --- arch/arm64/include/asm/cpufeature.h | 2 ++ arch/arm64/kernel/cpu_errata.c | 5 +++++ arch/arm64/kernel/cpufeature.c | 4 ++-- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index ba6983e901d..81e39e9e1f0 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -162,7 +162,9 @@ void __init setup_cpu_features(void); void update_cpu_capabilities(const struct arm64_cpu_capabilities *caps, const char *info); +void enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps); void check_local_cpu_errata(void); +void __init enable_errata_workarounds(void); #ifdef CONFIG_HOTPLUG_CPU void verify_local_cpu_capabilities(void); diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index 807d1c1de9d..efcf303b047 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -97,3 +97,8 @@ void check_local_cpu_errata(void) { update_cpu_capabilities(arm64_errata, "enabling workaround for"); } + +void __init enable_errata_workarounds(void) +{ + enable_cpu_capabilities(arm64_errata); +} diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index ec7e68c2c73..a51301773ef 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -799,8 +799,7 @@ void update_cpu_capabilities(const struct arm64_cpu_capabilities *caps, * Run through the enabled capabilities and enable() it on all active * CPUs */ -static void __init -enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps) +void __init enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps) { int i; @@ -954,6 +953,7 @@ void __init setup_cpu_features(void) /* Set the CPU feature capabilies */ setup_feature_capabilities(); setup_cpu_hwcaps(); + enable_errata_workarounds(); /* Advertise that we have computed the system capabilities */ set_sys_caps_initialised(); From c1a59ea9c2d227f5ee09d40d3741f8d0459c5ea8 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 2 Jan 2018 21:37:25 +0000 Subject: [PATCH 29/53] arm64: cpufeature: Pass capability structure to ->enable callback In order to invoke the CPU capability ->matches callback from the ->enable callback for applying local-CPU workarounds, we need a handle on the capability structure. This patch passes a pointer to the capability structure to the ->enable callback. Bug: 79422410 Change-Id: I5f83f1002dd35a4a8f77abe8d0204cef96c37398 Signed-off-by: Will Deacon Git-commit: 0a0d111d40fd1dc588cc590fab6b55d86ddc71d3 Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux [neeraju@codeaurora.org: resolve trivial merge conflicts] Signed-off-by: Neeraj Upadhyay Signed-off-by: Shiraz Hashim --- arch/arm64/kernel/cpufeature.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index a51301773ef..ddd84dfd406 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -805,7 +805,7 @@ void __init enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps) for (i = 0; caps[i].matches; i++) if (caps[i].enable && cpus_have_cap(caps[i].capability)) - on_each_cpu(caps[i].enable, NULL, true); + on_each_cpu(caps[i].enable, (void *)&(caps[i]), true); } #ifdef CONFIG_HOTPLUG_CPU @@ -920,7 +920,7 @@ void verify_local_cpu_capabilities(void) if (!feature_matches(__raw_read_system_reg(caps[i].sys_reg), &caps[i])) fail_incapable_cpu("arm64_features", &caps[i]); if (caps[i].enable) - caps[i].enable(NULL); + caps[i].enable((void *)&(caps[i])); } for (i = 0, caps = arm64_hwcaps; caps[i].matches; i++) { From 116af8e87eeb73ad395c05a6f0296dfc60f1ec80 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Wed, 3 Jan 2018 11:17:58 +0000 Subject: [PATCH 30/53] arm64: Add skeleton to harden the branch predictor against aliasing attacks Aliasing attacks against CPU branch predictors can allow an attacker to redirect speculative control flow on some CPUs and potentially divulge information from one context to another. This patch adds initial skeleton code behind a new Kconfig option to enable implementation-specific mitigations against these attacks for CPUs that are affected. Bug: 79422410 Change-Id: I778641a6a2658cded427204a8c2b01dc6b6b9579 Co-developed-by: Marc Zyngier Signed-off-by: Will Deacon Git-commit: 0f15adbb2861ce6f75ccfc5a92b19eae0ef327d0 Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux [neeraju@codeaurora.org: Fix merge conflicts and build failures due to missing includes and api changes in new kernels] Signed-off-by: Neeraj Upadhyay Signed-off-by: Shiraz Hashim --- arch/arm64/Kconfig | 17 +++++++ arch/arm64/include/asm/cpufeature.h | 1 + arch/arm64/include/asm/mmu.h | 42 ++++++++++++++++ arch/arm64/include/asm/sysreg.h | 1 + arch/arm64/kernel/Makefile | 4 ++ arch/arm64/kernel/cpu_errata.c | 76 +++++++++++++++++++++++++++++ arch/arm64/kernel/cpufeature.c | 1 + arch/arm64/kernel/entry.S | 8 +-- arch/arm64/mm/context.c | 1 + arch/arm64/mm/fault.c | 16 ++++++ 10 files changed, 164 insertions(+), 3 deletions(-) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index c5052bbe744..7f463b6eca5 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -796,6 +796,23 @@ config UNMAP_KERNEL_AT_EL0 If unsure, say Y. +config HARDEN_BRANCH_PREDICTOR + bool "Harden the branch predictor against aliasing attacks" if EXPERT + default y + help + Speculation attacks against some high-performance processors rely on + being able to manipulate the branch predictor for a victim context by + executing aliasing branches in the attacker context. Such attacks + can be partially mitigated against by clearing internal branch + predictor state and limiting the prediction logic in some situations. + + This config option will take CPU-specific actions to harden the + branch predictor against aliasing attacks and may rely on specific + instruction sequences or control bits being set by the system + firmware. + + If unsure, say Y. + menuconfig ARMV8_DEPRECATED bool "Emulate deprecated/obsolete ARMv8 instructions" depends on COMPAT diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index 81e39e9e1f0..cacf6c74c7f 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -29,6 +29,7 @@ #define ARM64_HAS_PAN 4 #define ARM64_HAS_UAO 5 #define ARM64_ALT_PAN_NOT_UAO 6 +#define ARM64_HARDEN_BRANCH_PREDICTOR 7 #define ARM64_UNMAP_KERNEL_AT_EL0 23 #define ARM64_NCAPS 24 diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h index e3ffa74e555..6b0dd551a6c 100644 --- a/arch/arm64/include/asm/mmu.h +++ b/arch/arm64/include/asm/mmu.h @@ -21,6 +21,11 @@ #ifndef __ASSEMBLY__ +#include + +#include +#include + typedef struct { atomic64_t id; void *vdso; @@ -39,6 +44,43 @@ static inline bool arm64_kernel_unmapped_at_el0(void) cpus_have_cap(ARM64_UNMAP_KERNEL_AT_EL0); } +typedef void (*bp_hardening_cb_t)(void); + +struct bp_hardening_data { + int hyp_vectors_slot; + bp_hardening_cb_t fn; +}; + +#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR +extern char __bp_harden_hyp_vecs_start[], __bp_harden_hyp_vecs_end[]; + +DECLARE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data); + +static inline struct bp_hardening_data *arm64_get_bp_hardening_data(void) +{ + return this_cpu_ptr(&bp_hardening_data); +} + +static inline void arm64_apply_bp_hardening(void) +{ + struct bp_hardening_data *d; + + if (!cpus_have_cap(ARM64_HARDEN_BRANCH_PREDICTOR)) + return; + + d = arm64_get_bp_hardening_data(); + if (d->fn) + d->fn(); +} +#else +static inline struct bp_hardening_data *arm64_get_bp_hardening_data(void) +{ + return NULL; +} + +static inline void arm64_apply_bp_hardening(void) { } +#endif /* CONFIG_HARDEN_BRANCH_PREDICTOR */ + extern void paging_init(void); extern void __iomem *early_io_map(phys_addr_t phys, unsigned long virt); extern void init_mem_pgprot(void); diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h index 0cc436bf726..3e4294cb3c5 100644 --- a/arch/arm64/include/asm/sysreg.h +++ b/arch/arm64/include/asm/sysreg.h @@ -101,6 +101,7 @@ #define ID_AA64ISAR0_AES_SHIFT 4 /* id_aa64pfr0 */ +#define ID_AA64PFR0_CSV2_SHIFT 56 #define ID_AA64PFR0_GIC_SHIFT 24 #define ID_AA64PFR0_ASIMD_SHIFT 20 #define ID_AA64PFR0_FP_SHIFT 16 diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 848a5b232ed..e56a0d13bff 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -47,6 +47,10 @@ arm64-obj-$(CONFIG_ARMV8_DEPRECATED) += armv8_deprecated.o arm64-obj-$(CONFIG_MSM_APP_API) += app_api.o arm64-obj-$(CONFIG_MSM_APP_SETTINGS) += app_setting.o +ifeq ($(CONFIG_KVM),y) +arm64-obj-$(CONFIG_HARDEN_BRANCH_PREDICTOR) += bpi.o +endif + obj-y += $(arm64-obj-y) vdso/ obj-$(CONFIG_VDSO32) += vdso32/ obj-m += $(arm64-obj-m) diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index efcf303b047..499a67de185 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -41,6 +41,82 @@ is_affected_midr_range(const struct arm64_cpu_capabilities *entry) return (midr >= entry->midr_range_min && midr <= entry->midr_range_max); } +#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR +#include +#include + +DEFINE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data); + +#ifdef CONFIG_KVM +static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start, + const char *hyp_vecs_end) +{ + void *dst = lm_alias(__bp_harden_hyp_vecs_start + slot * SZ_2K); + int i; + + for (i = 0; i < SZ_2K; i += 0x80) + memcpy(dst + i, hyp_vecs_start, hyp_vecs_end - hyp_vecs_start); + + flush_icache_range((uintptr_t)dst, (uintptr_t)dst + SZ_2K); +} + +static void __install_bp_hardening_cb(bp_hardening_cb_t fn, + const char *hyp_vecs_start, + const char *hyp_vecs_end) +{ + static int last_slot = -1; + static DEFINE_SPINLOCK(bp_lock); + int cpu, slot = -1; + + spin_lock(&bp_lock); + for_each_possible_cpu(cpu) { + if (per_cpu(bp_hardening_data.fn, cpu) == fn) { + slot = per_cpu(bp_hardening_data.hyp_vectors_slot, cpu); + break; + } + } + + if (slot == -1) { + last_slot++; + BUG_ON(((__bp_harden_hyp_vecs_end - __bp_harden_hyp_vecs_start) + / SZ_2K) <= last_slot); + slot = last_slot; + __copy_hyp_vect_bpi(slot, hyp_vecs_start, hyp_vecs_end); + } + + __this_cpu_write(bp_hardening_data.hyp_vectors_slot, slot); + __this_cpu_write(bp_hardening_data.fn, fn); + spin_unlock(&bp_lock); +} +#else +static void __maybe_unused +__install_bp_hardening_cb(bp_hardening_cb_t fn, + const char *hyp_vecs_start, + const char *hyp_vecs_end) +{ + __this_cpu_write(bp_hardening_data.fn, fn); +} +#endif /* CONFIG_KVM */ + +static void __maybe_unused +install_bp_hardening_cb(const struct arm64_cpu_capabilities *entry, + bp_hardening_cb_t fn, + const char *hyp_vecs_start, + const char *hyp_vecs_end) +{ + u64 pfr0; + + if (!entry->matches(entry)) + return; + + pfr0 = read_cpuid(SYS_ID_AA64PFR0_EL1); + if (cpuid_feature_extract_unsigned_field(pfr0, ID_AA64PFR0_CSV2_SHIFT)) + return; + + __install_bp_hardening_cb(fn, hyp_vecs_start, hyp_vecs_end); +} +#endif /* CONFIG_HARDEN_BRANCH_PREDICTOR */ + #define MIDR_RANGE(model, min, max) \ .matches = is_affected_midr_range, \ .midr_model = model, \ diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index ddd84dfd406..52c8f3cb8e3 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -87,6 +87,7 @@ static struct arm64_ftr_bits ftr_id_aa64isar0[] = { static struct arm64_ftr_bits ftr_id_aa64pfr0[] = { ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 32, 32, 0), ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 28, 4, 0), + ARM64_FTR_BITS(FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_CSV2_SHIFT, 4, 0), ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64PFR0_GIC_SHIFT, 4, 0), ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_ASIMD_SHIFT, 4, ID_AA64PFR0_ASIMD_NI), ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_FP_SHIFT, 4, ID_AA64PFR0_FP_NI), diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index 3c0d34dda83..3369f6b72a0 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -632,13 +632,15 @@ el0_ia: * Instruction abort handling */ mrs x26, far_el1 - // enable interrupts before calling the main handler - enable_dbg_and_irq + enable_dbg +#ifdef CONFIG_TRACE_IRQFLAGS + bl trace_hardirqs_off +#endif ct_user_exit mov x0, x26 mov x1, x25 mov x2, sp - bl do_mem_abort + bl do_el0_ia_bp_hardening b ret_to_user el0_fpsimd_acc: /* diff --git a/arch/arm64/mm/context.c b/arch/arm64/mm/context.c index cc3664b088d..9758b3d3e0a 100644 --- a/arch/arm64/mm/context.c +++ b/arch/arm64/mm/context.c @@ -202,6 +202,7 @@ void check_and_switch_context(struct mm_struct *mm, unsigned int cpu) /* Errata workaround post TTBRx_EL1 update. */ asmlinkage void post_ttbr_update_workaround(void) { + arm64_apply_bp_hardening(); } static int asids_init(void) diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index bfce642eb1c..ad6c276b81b 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -529,6 +529,22 @@ asmlinkage void __exception do_mem_abort(unsigned long addr, unsigned int esr, arm64_notify_die("", regs, &info, esr); } +asmlinkage void __exception do_el0_ia_bp_hardening(unsigned long addr, + unsigned int esr, + struct pt_regs *regs) +{ + /* + * We've taken an instruction abort from userspace and not yet + * re-enabled IRQs. If the address is a kernel address, apply + * BP hardening prior to enabling IRQs and pre-emption. + */ + if (addr > TASK_SIZE) + arm64_apply_bp_hardening(); + + local_irq_enable(); + do_mem_abort(addr, esr, regs); +} + /* * Handle stack alignment exceptions. */ From 118e7e0a13be3285f1456ab3741ecd148d24e4ab Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 1 Feb 2017 14:38:46 +0000 Subject: [PATCH 31/53] arm64: cpu_errata: Allow an erratum to be match for all revisions of a core Some minor erratum may not be fixed in further revisions of a core, leading to a situation where the workaround needs to be updated each time an updated core is released. Introduce a MIDR_ALL_VERSIONS match helper that will work for all versions of that MIDR, once and for all. Bug: 79422410 Change-Id: I5e7a8bfea94ad5984d605ca244eb447182928a07 Acked-by: Thomas Gleixner Acked-by: Mark Rutland Acked-by: Daniel Lezcano Reviewed-by: Suzuki K Poulose Signed-off-by: Marc Zyngier Git-commit: 06f1494f837da8997d670a1ba87add7963b08922 Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux Signed-off-by: Neeraj Upadhyay Signed-off-by: Shiraz Hashim --- arch/arm64/kernel/cpu_errata.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index 499a67de185..561faa3d2e6 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -123,6 +123,12 @@ install_bp_hardening_cb(const struct arm64_cpu_capabilities *entry, .midr_range_min = min, \ .midr_range_max = max +#define MIDR_ALL_VERSIONS(model) \ + .matches = is_affected_midr_range, \ + .midr_model = model, \ + .midr_range_min = 0, \ + .midr_range_max = (MIDR_VARIANT_MASK | MIDR_REVISION_MASK) + const struct arm64_cpu_capabilities arm64_errata[] = { #if defined(CONFIG_ARM64_ERRATUM_826319) || \ defined(CONFIG_ARM64_ERRATUM_827319) || \ From dde04deca9687fcb4dd32943ea5d7bff94832787 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 2 Jan 2018 21:45:41 +0000 Subject: [PATCH 32/53] drivers/firmware: Expose psci_get_version through psci_ops structure Entry into recent versions of ARM Trusted Firmware will invalidate the CPU branch predictor state in order to protect against aliasing attacks. This patch exposes the PSCI "VERSION" function via psci_ops, so that it can be invoked outside of the PSCI driver where necessary. Bug: 79422410 Change-Id: Ibe7995e9a311eb7da441d3c65dfdf71e9de3b33c Acked-by: Lorenzo Pieralisi Signed-off-by: Will Deacon Git-commit: d68e3ba5303f7e1099f51fdcd155f5263da8569b Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux [neeraju@codeaurora.org: resolve merge conflicts due to missing files] Signed-off-by: Neeraj Upadhyay Signed-off-by: Shiraz Hashim --- arch/arm64/include/asm/psci.h | 20 ++++++++++++++++++++ arch/arm64/kernel/psci.c | 22 ++++------------------ 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/arch/arm64/include/asm/psci.h b/arch/arm64/include/asm/psci.h index e5312ea0ec1..fabf1084372 100644 --- a/arch/arm64/include/asm/psci.h +++ b/arch/arm64/include/asm/psci.h @@ -16,4 +16,24 @@ int psci_init(void); +struct psci_power_state { + u16 id; + u8 type; + u8 affinity_level; +}; + +struct psci_operations { + int (*get_version)(void); + int (*cpu_suspend)(unsigned long state_id, + unsigned long entry_point); + int (*cpu_off)(struct psci_power_state state); + int (*cpu_on)(unsigned long cpuid, unsigned long entry_point); + int (*migrate)(unsigned long cpuid); + int (*affinity_info)(unsigned long target_affinity, + unsigned long lowest_affinity_level); + int (*migrate_info_type)(void); +}; + +extern struct psci_operations psci_ops; + #endif /* __ASM_PSCI_H */ diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c index d8fd766b86e..e2333060489 100644 --- a/arch/arm64/kernel/psci.c +++ b/arch/arm64/kernel/psci.c @@ -43,24 +43,7 @@ #define PSCI_POWER_STATE_BIT BIT(30) -struct psci_power_state { - u16 id; - u8 type; - u8 affinity_level; -}; - -struct psci_operations { - int (*cpu_suspend)(unsigned long state_id, - unsigned long entry_point); - int (*cpu_off)(struct psci_power_state state); - int (*cpu_on)(unsigned long cpuid, unsigned long entry_point); - int (*migrate)(unsigned long cpuid); - int (*affinity_info)(unsigned long target_affinity, - unsigned long lowest_affinity_level); - int (*migrate_info_type)(void); -}; - -static struct psci_operations psci_ops; +struct psci_operations psci_ops; static int (*invoke_psci_fn)(u64, u64, u64, u64); typedef int (*psci_initcall_t)(const struct device_node *); @@ -325,6 +308,7 @@ static int __init psci_1_0_init(struct device_node *np) } pr_info("Using standard PSCI v0.2 function IDs\n"); + psci_ops.get_version = psci_get_version; psci_function_id[PSCI_FN_CPU_SUSPEND] = PSCI_0_2_FN64_CPU_SUSPEND; psci_ops.cpu_suspend = psci_cpu_suspend; @@ -378,6 +362,7 @@ static int __init psci_0_2_init(struct device_node *np) } pr_info("Using standard PSCI v0.2 function IDs\n"); + psci_ops.get_version = psci_get_version; psci_function_id[PSCI_FN_CPU_SUSPEND] = PSCI_0_2_FN64_CPU_SUSPEND; psci_ops.cpu_suspend = psci_cpu_suspend; @@ -420,6 +405,7 @@ static int __init psci_0_1_init(struct device_node *np) goto out_put_node; pr_info("Using PSCI v0.1 Function IDs from DT\n"); + psci_ops.get_version = psci_get_version; if (!of_property_read_u32(np, "cpu_suspend", &id)) { psci_function_id[PSCI_FN_CPU_SUSPEND] = id; From 1fc04374acc23198d1309a8e3f7adfbdb3a26010 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Wed, 3 Jan 2018 12:46:21 +0000 Subject: [PATCH 33/53] arm64: Implement branch predictor hardening for affected Cortex-A CPUs Cortex-A57, A72, A73 and A75 are susceptible to branch predictor aliasing and can theoretically be attacked by malicious code. This patch implements a PSCI-based mitigation for these CPUs when available. The call into firmware will invalidate the branch predictor state, preventing any malicious entries from affecting other victim contexts. Bug: 79422410 Change-Id: I08acb4a1436709aee7e57ad5e14b37f1a8738038 Co-developed-by: Marc Zyngier Signed-off-by: Will Deacon Git-commit: aa6acde65e03186b5add8151e1ffe36c3c62639b Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux [neeraju@codeaurora.org: resolve merge conflicts. Implement PSCI-based mitigation only for Cortex-A57] Signed-off-by: Neeraj Upadhyay Signed-off-by: Shiraz Hashim --- arch/arm64/kernel/cpu_errata.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index 561faa3d2e6..834af5d6478 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -48,6 +48,8 @@ is_affected_midr_range(const struct arm64_cpu_capabilities *entry) DEFINE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data); #ifdef CONFIG_KVM +extern char __psci_hyp_bp_inval_start[], __psci_hyp_bp_inval_end[]; + static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start, const char *hyp_vecs_end) { @@ -89,10 +91,12 @@ static void __install_bp_hardening_cb(bp_hardening_cb_t fn, spin_unlock(&bp_lock); } #else -static void __maybe_unused -__install_bp_hardening_cb(bp_hardening_cb_t fn, - const char *hyp_vecs_start, - const char *hyp_vecs_end) +#define __psci_hyp_bp_inval_start NULL +#define __psci_hyp_bp_inval_end NULL + +static void __install_bp_hardening_cb(bp_hardening_cb_t fn, + const char *hyp_vecs_start, + const char *hyp_vecs_end) { __this_cpu_write(bp_hardening_data.fn, fn); } @@ -115,6 +119,20 @@ install_bp_hardening_cb(const struct arm64_cpu_capabilities *entry, __install_bp_hardening_cb(fn, hyp_vecs_start, hyp_vecs_end); } + +#include + +static void enable_psci_bp_hardening(void *data) +{ + const struct arm64_cpu_capabilities *entry = data; + + if (psci_ops.get_version) + install_bp_hardening_cb(entry, + (bp_hardening_cb_t)psci_ops.get_version, + __psci_hyp_bp_inval_start, + __psci_hyp_bp_inval_end); + +} #endif /* CONFIG_HARDEN_BRANCH_PREDICTOR */ #define MIDR_RANGE(model, min, max) \ @@ -170,6 +188,13 @@ const struct arm64_cpu_capabilities arm64_errata[] = { .capability = ARM64_WORKAROUND_845719, MIDR_RANGE(MIDR_KRYO2XX_SILVER, 0xA00004, 0xA00004), }, +#endif +#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR + { + .capability = ARM64_HARDEN_BRANCH_PREDICTOR, + MIDR_ALL_VERSIONS(MIDR_CORTEX_A57), + .enable = enable_psci_bp_hardening, + }, #endif { } From 57d5741eddccc5cd7e9130498e06eef239fdf12f Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 13 Dec 2017 14:19:37 -0800 Subject: [PATCH 34/53] arm64: cpu_errata: Add Kryo to Falkor 1003 errata The Kryo CPUs are also affected by the Falkor 1003 errata, so we need to do the same workaround on Kryo CPUs. The MIDR is slightly more complicated here, where the PART number is not always the same when looking at all the bits from 15 to 4. Drop the lower 8 bits and just look at the top 4 to see if it's '2' and then consider those as Kryo CPUs. This covers all the combinations without having to list them all out. Bug: 79422410 Change-Id: I076e583462e6b71172e9d7dc282703eb8a52499d Fixes: 38fd94b0275c ("arm64: Work around Falkor erratum 1003") Acked-by: Will Deacon Signed-off-by: Stephen Boyd Signed-off-by: Catalin Marinas Git-commit: bb48711800e6d7aedbf4dfd3367e0ab1270a6bea Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux [neeraju@codeaurora.org: resolve merge conflicts. Take only the Kryo MIDR definition part.] Signed-off-by: Neeraj Upadhyay Signed-off-by: Shiraz Hashim --- arch/arm64/include/asm/cputype.h | 1 + arch/arm64/kernel/cpu_errata.c | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h index d0edb7774b6..6b3982df94e 100644 --- a/arch/arm64/include/asm/cputype.h +++ b/arch/arm64/include/asm/cputype.h @@ -71,6 +71,7 @@ #define ARM_CPU_PART_CORTEX_A72 0xD08 #define ARM_CPU_PART_KRYO2XX_GOLD 0x800 #define ARM_CPU_PART_KRYO2XX_SILVER 0x801 +#define QCOM_CPU_PART_KRYO 0x200 #define APM_CPU_PART_POTENZA 0x000 diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index 834af5d6478..2ffdac0b342 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -24,6 +24,7 @@ #define MIDR_CORTEX_A53 MIDR_CPU_PART(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A53) #define MIDR_CORTEX_A57 MIDR_CPU_PART(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A57) #define MIDR_KRYO2XX_SILVER MIDR_CPU_PART(ARM_CPU_IMP_QCOM, ARM_CPU_PART_KRYO2XX_SILVER) +#define MIDR_QCOM_KRYO MIDR_CPU_PART(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO) #define CPU_MODEL_MASK (MIDR_IMPLEMENTOR_MASK | MIDR_PARTNUM_MASK | \ MIDR_ARCHITECTURE_MASK) @@ -41,6 +42,18 @@ is_affected_midr_range(const struct arm64_cpu_capabilities *entry) return (midr >= entry->midr_range_min && midr <= entry->midr_range_max); } +static bool __maybe_unused +is_kryo_midr(const struct arm64_cpu_capabilities *entry) +{ + u32 model; + + model = read_cpuid_id(); + model &= MIDR_IMPLEMENTOR_MASK | (0xf00 << MIDR_PARTNUM_SHIFT) | + MIDR_ARCHITECTURE_MASK; + + return model == entry->midr_model; +} + #ifdef CONFIG_HARDEN_BRANCH_PREDICTOR #include #include From 99db809d28b8993cc6b1a6ae61cc760ff245a317 Mon Sep 17 00:00:00 2001 From: Shanker Donthineni Date: Fri, 5 Jan 2018 14:28:59 -0600 Subject: [PATCH 35/53] arm64: Implement branch predictor hardening for Falkor Falkor is susceptible to branch predictor aliasing and can theoretically be attacked by malicious code. This patch implements a mitigation for these attacks, preventing any malicious entries from affecting other victim contexts. Bug: 79422410 Change-Id: Ieb49196c23582c3174f778891ff2ab7cdc96be54 Signed-off-by: Shanker Donthineni [will: fix label name when !CONFIG_KVM and remove references to MIDR_FALKOR] Signed-off-by: Will Deacon Git-commit: ec82b567a74fbdffdf418d4bb381d55f6a9096af Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux [neeraju@codeaurora.org: resolve merge conflicts. Take only qcom_link_stack_sanitization() definition] Signed-off-by: Neeraj Upadhyay Signed-off-by: Shiraz Hashim --- arch/arm64/kernel/cpu_errata.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index 2ffdac0b342..db1a5cd2328 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -146,6 +146,19 @@ static void enable_psci_bp_hardening(void *data) __psci_hyp_bp_inval_end); } + +static void __maybe_unused qcom_link_stack_sanitization(void) +{ + u64 tmp; + + asm volatile("mov %0, x30 \n" + ".rept 16 \n" + "bl . + 4 \n" + ".endr \n" + "mov x30, %0 \n" + : "=&r" (tmp)); +} + #endif /* CONFIG_HARDEN_BRANCH_PREDICTOR */ #define MIDR_RANGE(model, min, max) \ From 4b532ed831b2cf2bf079412c45e6350007985c8f Mon Sep 17 00:00:00 2001 From: Neeraj Upadhyay Date: Mon, 8 Jan 2018 19:58:29 +0530 Subject: [PATCH 36/53] arm64: Add BTAC/LinkStack sanitizations for Kryo Kryo cores are exposed to two vulnerabilities due to subroutine return (called LINK-STACK) and branch target predictors. These two issues can be mitigated through software workarounds. Kernel: - Apply LINK-STACK mitigation which is issue 16 nested BL instructions on process context switch 'cpu_do_switch_mm()' where ASID changes. - Apply psci based branch predictor invalidation. Bug: 79422410 Change-Id: I983a12dabcd45e3ec757732a44fc567c12228d8b Signed-off-by: Neeraj Upadhyay Signed-off-by: Shiraz Hashim --- arch/arm64/kernel/cpu_errata.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index db1a5cd2328..37e278e4fd9 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -147,7 +147,7 @@ static void enable_psci_bp_hardening(void *data) } -static void __maybe_unused qcom_link_stack_sanitization(void) +static void qcom_link_stack_sanitization(void) { u64 tmp; @@ -159,6 +159,22 @@ static void __maybe_unused qcom_link_stack_sanitization(void) : "=&r" (tmp)); } +static void qcom_bp_hardening(void) +{ + qcom_link_stack_sanitization(); + if (psci_ops.get_version) + psci_ops.get_version(); +} + +static void enable_qcom_bp_hardening(void *data) +{ + const struct arm64_cpu_capabilities *entry = data; + + install_bp_hardening_cb(entry, + (bp_hardening_cb_t)qcom_bp_hardening, + __psci_hyp_bp_inval_start, + __psci_hyp_bp_inval_end); +} #endif /* CONFIG_HARDEN_BRANCH_PREDICTOR */ #define MIDR_RANGE(model, min, max) \ @@ -221,6 +237,12 @@ const struct arm64_cpu_capabilities arm64_errata[] = { MIDR_ALL_VERSIONS(MIDR_CORTEX_A57), .enable = enable_psci_bp_hardening, }, + { + .capability = ARM64_HARDEN_BRANCH_PREDICTOR, + .midr_model = MIDR_QCOM_KRYO, + .matches = is_kryo_midr, + .enable = enable_qcom_bp_hardening, + }, #endif { } From bc6d069fdc883bcc99290c00cd511c7d3efa69ac Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Wed, 3 Jan 2018 11:19:34 +0000 Subject: [PATCH 37/53] arm64: cputype: Add missing MIDR values for Cortex-A72 and Cortex-A75 Hook up MIDR values for the Cortex-A72 and Cortex-A75 CPUs, since they will soon need MIDR matches for hardening the branch predictor. Bug: 79422410 Change-Id: Ifc80c173aa3f0966dd1e99e27e17304a0ad9ca18 Signed-off-by: Will Deacon Git-commit: f0be3364335d47267aa1f7c5ed5faaa59c70db13 Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux [neeraju@codeaurora.org: resolve trivial merge conflicts] Signed-off-by: Neeraj Upadhyay Signed-off-by: Shiraz Hashim --- arch/arm64/include/asm/cputype.h | 1 + arch/arm64/kernel/cpu_errata.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h index 6b3982df94e..389c9210758 100644 --- a/arch/arm64/include/asm/cputype.h +++ b/arch/arm64/include/asm/cputype.h @@ -69,6 +69,7 @@ #define ARM_CPU_PART_CORTEX_A57 0xD07 #define ARM_CPU_PART_CORTEX_A53 0xD03 #define ARM_CPU_PART_CORTEX_A72 0xD08 +#define ARM_CPU_PART_CORTEX_A75 0xD0A #define ARM_CPU_PART_KRYO2XX_GOLD 0x800 #define ARM_CPU_PART_KRYO2XX_SILVER 0x801 #define QCOM_CPU_PART_KRYO 0x200 diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index 37e278e4fd9..bf2887df55b 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -25,6 +25,8 @@ #define MIDR_CORTEX_A57 MIDR_CPU_PART(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A57) #define MIDR_KRYO2XX_SILVER MIDR_CPU_PART(ARM_CPU_IMP_QCOM, ARM_CPU_PART_KRYO2XX_SILVER) #define MIDR_QCOM_KRYO MIDR_CPU_PART(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO) +#define MIDR_CORTEX_A72 MIDR_CPU_PART(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A72) +#define MIDR_CORTEX_A75 MIDR_CPU_PART(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A75) #define CPU_MODEL_MASK (MIDR_IMPLEMENTOR_MASK | MIDR_PARTNUM_MASK | \ MIDR_ARCHITECTURE_MASK) From d592ac35b0eea59562e4358ab197c6ea91fa1a8b Mon Sep 17 00:00:00 2001 From: Mohammed Javid Date: Tue, 20 Feb 2018 16:01:26 +0530 Subject: [PATCH 38/53] msm: ipa: Fix to handle NULL pointer dereference Header entry deleted but same entry pointer using in routing table not updated. Added checks to confirm header entry present or not before using it to avoid null pointer dereference. Bug: 109741734 Change-Id: Id1d844c60b2dcb0cc7cf18352b78d62fe5a89347 Acked-by: Ashok Vuyyuru Signed-off-by: Mohammed Javid --- drivers/platform/msm/ipa/ipa_v2/ipa_rt.c | 65 ++++++++++++++++++++++++ drivers/platform/msm/ipa/ipa_v3/ipa_rt.c | 65 +++++++++++++++++++++++- 2 files changed, 129 insertions(+), 1 deletion(-) diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c index a339900f205..b626ba02e19 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c @@ -51,6 +51,7 @@ int __ipa_generate_rt_hw_rule_v2(enum ipa_ip_type ip, u32 tmp[IPA_RT_FLT_HW_RULE_BUF_SIZE/4]; u8 *start; int pipe_idx; + struct ipa_hdr_entry *hdr_entry; if (buf == NULL) { memset(tmp, 0, IPA_RT_FLT_HW_RULE_BUF_SIZE); @@ -74,6 +75,18 @@ int __ipa_generate_rt_hw_rule_v2(enum ipa_ip_type ip, } rule_hdr->u.hdr.pipe_dest_idx = pipe_idx; rule_hdr->u.hdr.system = !ipa_ctx->hdr_tbl_lcl; + + /* Adding check to confirm still + * header entry present in header table or not + */ + + if (entry->hdr) { + hdr_entry = ipa_id_find(entry->rule.hdr_hdl); + if (!hdr_entry || hdr_entry->cookie != IPA_HDR_COOKIE) { + IPAERR("Header entry already deleted\n"); + return -EPERM; + } + } if (entry->hdr) { rule_hdr->u.hdr.hdr_offset = entry->hdr->offset_entry->offset >> 2; @@ -133,6 +146,8 @@ int __ipa_generate_rt_hw_rule_v2_5(enum ipa_ip_type ip, u32 tmp[IPA_RT_FLT_HW_RULE_BUF_SIZE/4]; u8 *start; int pipe_idx; + struct ipa_hdr_entry *hdr_entry; + struct ipa_hdr_proc_ctx_entry *hdr_proc_entry; if (buf == NULL) { memset(tmp, 0, IPA_RT_FLT_HW_RULE_BUF_SIZE); @@ -155,6 +170,24 @@ int __ipa_generate_rt_hw_rule_v2_5(enum ipa_ip_type ip, return -EPERM; } rule_hdr->u.hdr_v2_5.pipe_dest_idx = pipe_idx; + /* Adding check to confirm still + * header entry present in header table or not + */ + + if (entry->hdr) { + hdr_entry = ipa_id_find(entry->rule.hdr_hdl); + if (!hdr_entry || hdr_entry->cookie != IPA_HDR_COOKIE) { + IPAERR("Header entry already deleted\n"); + return -EPERM; + } + } else if (entry->proc_ctx) { + hdr_proc_entry = ipa_id_find(entry->rule.hdr_proc_ctx_hdl); + if (!hdr_proc_entry || + hdr_proc_entry->cookie != IPA_PROC_HDR_COOKIE) { + IPAERR("Proc header entry already deleted\n"); + return -EPERM; + } + } if (entry->proc_ctx || (entry->hdr && entry->hdr->is_hdr_proc_ctx)) { struct ipa_hdr_proc_ctx_entry *proc_ctx; @@ -1113,6 +1146,8 @@ int __ipa_del_rt_rule(u32 rule_hdl) { struct ipa_rt_entry *entry; int id; + struct ipa_hdr_entry *hdr_entry; + struct ipa_hdr_proc_ctx_entry *hdr_proc_entry; entry = ipa_id_find(rule_hdl); @@ -1125,6 +1160,24 @@ int __ipa_del_rt_rule(u32 rule_hdl) IPAERR("bad params\n"); return -EINVAL; } + /* Adding check to confirm still + * header entry present in header table or not + */ + + if (entry->hdr) { + hdr_entry = ipa_id_find(entry->rule.hdr_hdl); + if (!hdr_entry || hdr_entry->cookie != IPA_HDR_COOKIE) { + IPAERR("Header entry already deleted\n"); + return -EINVAL; + } + } else if (entry->proc_ctx) { + hdr_proc_entry = ipa_id_find(entry->rule.hdr_proc_ctx_hdl); + if (!hdr_proc_entry || + hdr_proc_entry->cookie != IPA_PROC_HDR_COOKIE) { + IPAERR("Proc header entry already deleted\n"); + return -EINVAL; + } + } if (entry->hdr) __ipa_release_hdr(entry->hdr->id); @@ -1437,6 +1490,7 @@ static int __ipa_mdfy_rt_rule(struct ipa_rt_rule_mdfy *rtrule) { struct ipa_rt_entry *entry; struct ipa_hdr_entry *hdr = NULL; + struct ipa_hdr_entry *hdr_entry; if (rtrule->rule.hdr_hdl) { hdr = ipa_id_find(rtrule->rule.hdr_hdl); @@ -1457,6 +1511,17 @@ static int __ipa_mdfy_rt_rule(struct ipa_rt_rule_mdfy *rtrule) goto error; } + /* Adding check to confirm still + * header entry present in header table or not + */ + + if (entry->hdr) { + hdr_entry = ipa_id_find(entry->rule.hdr_hdl); + if (!hdr_entry || hdr_entry->cookie != IPA_HDR_COOKIE) { + IPAERR("Header entry already deleted\n"); + return -EPERM; + } + } if (entry->hdr) entry->hdr->ref_cnt--; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c index 25d72396010..ae058d2b1c0 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c @@ -54,6 +54,8 @@ int __ipa_generate_rt_hw_rule_v3_0(enum ipa_ip_type ip, u32 tmp[IPA_RT_FLT_HW_RULE_BUF_SIZE/4]; u8 *start; int pipe_idx; + struct ipa3_hdr_entry *hdr_entry; + struct ipa3_hdr_proc_ctx_entry *hdr_proc_entry; if (buf == NULL) { memset(tmp, 0, IPA_RT_FLT_HW_RULE_BUF_SIZE); @@ -80,6 +82,26 @@ int __ipa_generate_rt_hw_rule_v3_0(enum ipa_ip_type ip, return -EPERM; } rule_hdr->u.hdr.pipe_dest_idx = pipe_idx; + /* Adding check to confirm still + * header entry present in header table or not + */ + + if (entry->hdr) { + hdr_entry = ipa3_id_find(entry->rule.hdr_hdl); + if (!hdr_entry || hdr_entry->cookie != IPA_HDR_COOKIE) { + IPAERR("Header entry already deleted\n"); + return -EINVAL; + } + } else if (entry->proc_ctx) { + hdr_proc_entry = ipa3_id_find(entry->rule.hdr_proc_ctx_hdl); + if (!hdr_proc_entry || + hdr_proc_entry->cookie != IPA_PROC_HDR_COOKIE) { + IPAERR("Proc header entry already deleted\n"); + return -EINVAL; + } + } + + if (entry->proc_ctx || (entry->hdr && entry->hdr->is_hdr_proc_ctx)) { struct ipa3_hdr_proc_ctx_entry *proc_ctx; proc_ctx = (entry->proc_ctx) ? : entry->hdr->proc_ctx; @@ -1370,6 +1392,8 @@ int __ipa3_del_rt_rule(u32 rule_hdl) { struct ipa3_rt_entry *entry; int id; + struct ipa3_hdr_entry *hdr_entry; + struct ipa3_hdr_proc_ctx_entry *hdr_proc_entry; entry = ipa3_id_find(rule_hdl); @@ -1383,6 +1407,25 @@ int __ipa3_del_rt_rule(u32 rule_hdl) return -EINVAL; } + /* Adding check to confirm still + * header entry present in header table or not + */ + + if (entry->hdr) { + hdr_entry = ipa3_id_find(entry->rule.hdr_hdl); + if (!hdr_entry || hdr_entry->cookie != IPA_HDR_COOKIE) { + IPAERR("Header entry already deleted\n"); + return -EINVAL; + } + } else if (entry->proc_ctx) { + hdr_proc_entry = ipa3_id_find(entry->rule.hdr_proc_ctx_hdl); + if (!hdr_proc_entry || + hdr_proc_entry->cookie != IPA_PROC_HDR_COOKIE) { + IPAERR("Proc header entry already deleted\n"); + return -EINVAL; + } + } + if (entry->hdr) __ipa3_release_hdr(entry->hdr->id); else if (entry->proc_ctx) @@ -1696,7 +1739,8 @@ static int __ipa_mdfy_rt_rule(struct ipa_rt_rule_mdfy *rtrule) struct ipa3_rt_entry *entry; struct ipa3_hdr_entry *hdr = NULL; struct ipa3_hdr_proc_ctx_entry *proc_ctx = NULL; - + struct ipa3_hdr_entry *hdr_entry; + struct ipa3_hdr_proc_ctx_entry *hdr_proc_entry; if (rtrule->rule.hdr_hdl) { hdr = ipa3_id_find(rtrule->rule.hdr_hdl); if ((hdr == NULL) || (hdr->cookie != IPA_HDR_COOKIE)) { @@ -1723,6 +1767,25 @@ static int __ipa_mdfy_rt_rule(struct ipa_rt_rule_mdfy *rtrule) goto error; } + /* Adding check to confirm still + * header entry present in header table or not + */ + + if (entry->hdr) { + hdr_entry = ipa3_id_find(entry->rule.hdr_hdl); + if (!hdr_entry || hdr_entry->cookie != IPA_HDR_COOKIE) { + IPAERR("Header entry already deleted\n"); + return -EPERM; + } + } else if (entry->proc_ctx) { + hdr_proc_entry = ipa3_id_find(entry->rule.hdr_proc_ctx_hdl); + if (!hdr_proc_entry || + hdr_proc_entry->cookie != IPA_PROC_HDR_COOKIE) { + IPAERR("Proc header entry already deleted\n"); + return -EPERM; + } + } + if (entry->hdr) entry->hdr->ref_cnt--; if (entry->proc_ctx) From a4102336dfaafed26340bddc134efc3f43b05ddb Mon Sep 17 00:00:00 2001 From: Alok Kumar Date: Sat, 2 Jun 2018 17:50:45 +0530 Subject: [PATCH 39/53] qcacld-2.0: Fix information leak issue during memcpy The buffer allocated with lenth "ATH6KL_FWLOG_PAYLOAD_SIZE " is not initialized, this may lead to information leak during memcpy when len < ATH6KL_FWLOG_PAYLOAD_SIZE. To resolve this issue, memset the buffer for length (ATH6KL_FWLOG_PAYLOAD_SIZE - len) to 0 Bug: 73885536 Change-Id: If4a49347d674ad2af0438b408a4a4b9308c61026 CRs-Fixed: 2253103 Signed-off-by: Ecco Park --- drivers/staging/qcacld-2.0/CORE/UTILS/FWLOG/dbglog_host.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/staging/qcacld-2.0/CORE/UTILS/FWLOG/dbglog_host.c b/drivers/staging/qcacld-2.0/CORE/UTILS/FWLOG/dbglog_host.c index 729fd786b9d..47a4fabbc79 100644 --- a/drivers/staging/qcacld-2.0/CORE/UTILS/FWLOG/dbglog_host.c +++ b/drivers/staging/qcacld-2.0/CORE/UTILS/FWLOG/dbglog_host.c @@ -1745,6 +1745,9 @@ send_diag_netlink_data(const u_int8_t *buffer, slot->dropped = get_version; memcpy(slot->payload, buffer, len); + /* Need to pad each record to fixed length ATH6KL_FWLOG_PAYLOAD_SIZE */ + memset(slot->payload + len, 0, ATH6KL_FWLOG_PAYLOAD_SIZE - len); + res = nl_srv_bcast_fw_logs(skb_out); if (res < 0) { AR_DEBUG_PRINTF(ATH_DEBUG_RSVD1, @@ -1791,6 +1794,9 @@ dbglog_process_netlink_data(wmi_unified_t wmi_handle, const u_int8_t *buffer, slot->dropped = cpu_to_le32(dropped); memcpy(slot->payload, buffer, len); + /* Need to pad each record to fixed length ATH6KL_FWLOG_PAYLOAD_SIZE */ + memset(slot->payload + len, 0, ATH6KL_FWLOG_PAYLOAD_SIZE - len); + res = nl_srv_bcast_fw_logs(skb_out); if (res < 0) { From 928bf4c101e87cba00d34943e4fe44e4fe167a14 Mon Sep 17 00:00:00 2001 From: Dundi Raviteja Date: Wed, 23 May 2018 19:03:57 +0530 Subject: [PATCH 40/53] qcacld-2.0: Modify addition of proper length to payload Currently, in ptt_sock_send_msg_to_app() function sizeof(tAniHdr) is adding to payload, but this size is already added in length field of tAniHdr. To address this issue, remove the addition of sizeof(tAniHdr) in ptt_sock_send_msg_to_app(). Also remove the checking of length against sizeof(tAniHdr) in ptt_cmd_handler() function. Bug: 73884889 Change-Id: I58036fd172f3a3c6963757205e0c82e407e2f69b CRs-Fixed: 2247469 Signed-off-by: Ecco Park --- .../CORE/SVC/src/ptt/wlan_ptt_sock_svc.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/drivers/staging/qcacld-2.0/CORE/SVC/src/ptt/wlan_ptt_sock_svc.c b/drivers/staging/qcacld-2.0/CORE/SVC/src/ptt/wlan_ptt_sock_svc.c index 4558ee84e13..7c01407f64c 100644 --- a/drivers/staging/qcacld-2.0/CORE/SVC/src/ptt/wlan_ptt_sock_svc.c +++ b/drivers/staging/qcacld-2.0/CORE/SVC/src/ptt/wlan_ptt_sock_svc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -125,7 +125,7 @@ int ptt_sock_send_msg_to_app(tAniHdr *wmsg, int radio, int src_mod, int pid) __func__, radio); return -EINVAL; } - payload_len = wmsg_length + sizeof(wnl->radio) + sizeof(tAniHdr); + payload_len = wmsg_length + sizeof(wnl->radio); tot_msg_len = NLMSG_SPACE(payload_len); if ((skb = dev_alloc_skb(tot_msg_len)) == NULL) { PTT_TRACE(VOS_TRACE_LEVEL_ERROR, "%s: dev_alloc_skb() failed for msg size[%d]\n", @@ -261,18 +261,9 @@ static void ptt_cmd_handler(const void *data, int data_len, void *ctx, int pid) payload = (ptt_app_reg_req *)(nla_data(tb[CLD80211_ATTR_DATA])); length = be16_to_cpu(payload->wmsg.length); - if ((USHRT_MAX - length) < (sizeof(payload->radio) + sizeof(tAniHdr))) { - PTT_TRACE(VOS_TRACE_LEVEL_ERROR, - "u16 overflow length %d %zu %zu", - length, - sizeof(payload->radio), - sizeof(tAniHdr)); - return; - } if (nla_len(tb[CLD80211_ATTR_DATA]) < (length + - sizeof(payload->radio) + - sizeof(tAniHdr))) { + sizeof(payload->radio))) { PTT_TRACE(VOS_TRACE_LEVEL_ERROR, "ATTR_DATA len check failed"); return; } From f236b924eef5be30e92ae435f6a4e9de62de42e3 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Wed, 11 Jan 2017 16:30:00 +0530 Subject: [PATCH 41/53] nf_conntrack: Null pointer check added prior deleting sip node Prior to null pointer check, SIP node was deleted from the list a null pointer check is added to confront the exception. Bug: 111529827 Change-Id: Ia12fa468eed7d1a91fad96840fa27cb0e4e208a8 Acked-by: Rishav LNU Signed-off-by: Utkarsh Saxena --- net/netfilter/nf_conntrack_core.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 3f8abfad7bc..dcef48289a0 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -325,12 +325,14 @@ destroy_conntrack(struct nf_conntrack *nfct) local_bh_disable(); pr_debug("freeing item in the SIP list\n"); - list_for_each_safe(sip_node_list, sip_node_save_list, - &ct->sip_segment_list) { - sip_node = list_entry(sip_node_list, struct sip_list, list); - list_del(&sip_node->list); - kfree(sip_node); - } + if (ct->sip_segment_list.next != NULL) + list_for_each_safe(sip_node_list, sip_node_save_list, + &ct->sip_segment_list) { + sip_node = list_entry(sip_node_list, + struct sip_list, list); + list_del(&sip_node->list); + kfree(sip_node); + } /* Expectations will have been removed in clean_from_lists, * except TFTP can create an expectation on the first packet, * before connection is in the list, so we need to clean here, From 8da4c405af46ef2194289b5c3e3eee2535c4ae64 Mon Sep 17 00:00:00 2001 From: Petri Gynther Date: Mon, 23 Jul 2018 21:51:20 -0700 Subject: [PATCH 42/53] arm64/configs: marlin: increase log buffer to 1 MiB Right after boot, /dev/kmsg no longer contains the earliest boot messages. Increase log buffer to 1 MiB, same as Wahoo. 6,64,0,-;log_buf_len individual max cpu contribution: 262144 bytes 6,65,0,-;log_buf_len total cpu_extra contributions: 786432 bytes 6,66,0,-;log_buf_len min size: 131072 bytes 6,67,0,-;log_buf_len: 1048576 bytes Change-Id: I7cc1736dccfa2d0ee4bb4db9292c75b4ae883671 Signed-off-by: Petri Gynther --- arch/arm64/configs/marlin_defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/configs/marlin_defconfig b/arch/arm64/configs/marlin_defconfig index 2baa17ae88e..fc59f7820d1 100644 --- a/arch/arm64/configs/marlin_defconfig +++ b/arch/arm64/configs/marlin_defconfig @@ -12,7 +12,7 @@ CONFIG_RCU_FAST_NO_HZ=y CONFIG_RCU_BOOST=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y -CONFIG_LOG_CPU_MAX_BUF_SHIFT=15 +CONFIG_LOG_CPU_MAX_BUF_SHIFT=18 CONFIG_CGROUPS=y CONFIG_CGROUP_DEBUG=y CONFIG_CGROUP_FREEZER=y From 036e9a199477cc7cf1d7a1572582bfca61f40759 Mon Sep 17 00:00:00 2001 From: John Dias Date: Tue, 24 Jul 2018 17:42:47 -0700 Subject: [PATCH 43/53] Revert "arm64: cputype: Add missing MIDR values for Cortex-A72 and Cortex-A75" This reverts commit bc6d069fdc883bcc99290c00cd511c7d3efa69ac. Bug: 111785512 Change-Id: Ia475f609ccd003f368f8739cc712b5efe640172d Signed-off-by: John Dias --- arch/arm64/include/asm/cputype.h | 1 - arch/arm64/kernel/cpu_errata.c | 2 -- 2 files changed, 3 deletions(-) diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h index 389c9210758..6b3982df94e 100644 --- a/arch/arm64/include/asm/cputype.h +++ b/arch/arm64/include/asm/cputype.h @@ -69,7 +69,6 @@ #define ARM_CPU_PART_CORTEX_A57 0xD07 #define ARM_CPU_PART_CORTEX_A53 0xD03 #define ARM_CPU_PART_CORTEX_A72 0xD08 -#define ARM_CPU_PART_CORTEX_A75 0xD0A #define ARM_CPU_PART_KRYO2XX_GOLD 0x800 #define ARM_CPU_PART_KRYO2XX_SILVER 0x801 #define QCOM_CPU_PART_KRYO 0x200 diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index bf2887df55b..37e278e4fd9 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -25,8 +25,6 @@ #define MIDR_CORTEX_A57 MIDR_CPU_PART(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A57) #define MIDR_KRYO2XX_SILVER MIDR_CPU_PART(ARM_CPU_IMP_QCOM, ARM_CPU_PART_KRYO2XX_SILVER) #define MIDR_QCOM_KRYO MIDR_CPU_PART(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO) -#define MIDR_CORTEX_A72 MIDR_CPU_PART(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A72) -#define MIDR_CORTEX_A75 MIDR_CPU_PART(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A75) #define CPU_MODEL_MASK (MIDR_IMPLEMENTOR_MASK | MIDR_PARTNUM_MASK | \ MIDR_ARCHITECTURE_MASK) From 6e7e885bb02b3cfd2c5d916dcdf87a868eb02fbb Mon Sep 17 00:00:00 2001 From: John Dias Date: Tue, 24 Jul 2018 17:43:09 -0700 Subject: [PATCH 44/53] Revert "arm64: Add BTAC/LinkStack sanitizations for Kryo" This reverts commit 4b532ed831b2cf2bf079412c45e6350007985c8f. Bug: 111785512 Change-Id: I9a4de66e2f1b441ef4bf2aeeaae2228cc5ab93b7 Signed-off-by: John Dias --- arch/arm64/kernel/cpu_errata.c | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index 37e278e4fd9..db1a5cd2328 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -147,7 +147,7 @@ static void enable_psci_bp_hardening(void *data) } -static void qcom_link_stack_sanitization(void) +static void __maybe_unused qcom_link_stack_sanitization(void) { u64 tmp; @@ -159,22 +159,6 @@ static void qcom_link_stack_sanitization(void) : "=&r" (tmp)); } -static void qcom_bp_hardening(void) -{ - qcom_link_stack_sanitization(); - if (psci_ops.get_version) - psci_ops.get_version(); -} - -static void enable_qcom_bp_hardening(void *data) -{ - const struct arm64_cpu_capabilities *entry = data; - - install_bp_hardening_cb(entry, - (bp_hardening_cb_t)qcom_bp_hardening, - __psci_hyp_bp_inval_start, - __psci_hyp_bp_inval_end); -} #endif /* CONFIG_HARDEN_BRANCH_PREDICTOR */ #define MIDR_RANGE(model, min, max) \ @@ -237,12 +221,6 @@ const struct arm64_cpu_capabilities arm64_errata[] = { MIDR_ALL_VERSIONS(MIDR_CORTEX_A57), .enable = enable_psci_bp_hardening, }, - { - .capability = ARM64_HARDEN_BRANCH_PREDICTOR, - .midr_model = MIDR_QCOM_KRYO, - .matches = is_kryo_midr, - .enable = enable_qcom_bp_hardening, - }, #endif { } From 25e6c82efd623874eeac779871b373079073fcf9 Mon Sep 17 00:00:00 2001 From: John Dias Date: Tue, 24 Jul 2018 17:43:25 -0700 Subject: [PATCH 45/53] Revert "arm64: Implement branch predictor hardening for Falkor" This reverts commit 99db809d28b8993cc6b1a6ae61cc760ff245a317. Bug: 111785512 Change-Id: I9a61a66896a7fdf7e56774e8b1f6c7bdd82f77c1 Signed-off-by: John Dias --- arch/arm64/kernel/cpu_errata.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index db1a5cd2328..2ffdac0b342 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -146,19 +146,6 @@ static void enable_psci_bp_hardening(void *data) __psci_hyp_bp_inval_end); } - -static void __maybe_unused qcom_link_stack_sanitization(void) -{ - u64 tmp; - - asm volatile("mov %0, x30 \n" - ".rept 16 \n" - "bl . + 4 \n" - ".endr \n" - "mov x30, %0 \n" - : "=&r" (tmp)); -} - #endif /* CONFIG_HARDEN_BRANCH_PREDICTOR */ #define MIDR_RANGE(model, min, max) \ From c21cb6ab044c7d7df577bc19379f7511591871e6 Mon Sep 17 00:00:00 2001 From: John Dias Date: Tue, 24 Jul 2018 17:43:38 -0700 Subject: [PATCH 46/53] Revert "arm64: cpu_errata: Add Kryo to Falkor 1003 errata" This reverts commit 57d5741eddccc5cd7e9130498e06eef239fdf12f. Bug: 111785512 Change-Id: I61003411db013e10c5a9e5c9ffecbf0d56d05324 Signed-off-by: John Dias --- arch/arm64/include/asm/cputype.h | 1 - arch/arm64/kernel/cpu_errata.c | 13 ------------- 2 files changed, 14 deletions(-) diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h index 6b3982df94e..d0edb7774b6 100644 --- a/arch/arm64/include/asm/cputype.h +++ b/arch/arm64/include/asm/cputype.h @@ -71,7 +71,6 @@ #define ARM_CPU_PART_CORTEX_A72 0xD08 #define ARM_CPU_PART_KRYO2XX_GOLD 0x800 #define ARM_CPU_PART_KRYO2XX_SILVER 0x801 -#define QCOM_CPU_PART_KRYO 0x200 #define APM_CPU_PART_POTENZA 0x000 diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index 2ffdac0b342..834af5d6478 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -24,7 +24,6 @@ #define MIDR_CORTEX_A53 MIDR_CPU_PART(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A53) #define MIDR_CORTEX_A57 MIDR_CPU_PART(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A57) #define MIDR_KRYO2XX_SILVER MIDR_CPU_PART(ARM_CPU_IMP_QCOM, ARM_CPU_PART_KRYO2XX_SILVER) -#define MIDR_QCOM_KRYO MIDR_CPU_PART(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO) #define CPU_MODEL_MASK (MIDR_IMPLEMENTOR_MASK | MIDR_PARTNUM_MASK | \ MIDR_ARCHITECTURE_MASK) @@ -42,18 +41,6 @@ is_affected_midr_range(const struct arm64_cpu_capabilities *entry) return (midr >= entry->midr_range_min && midr <= entry->midr_range_max); } -static bool __maybe_unused -is_kryo_midr(const struct arm64_cpu_capabilities *entry) -{ - u32 model; - - model = read_cpuid_id(); - model &= MIDR_IMPLEMENTOR_MASK | (0xf00 << MIDR_PARTNUM_SHIFT) | - MIDR_ARCHITECTURE_MASK; - - return model == entry->midr_model; -} - #ifdef CONFIG_HARDEN_BRANCH_PREDICTOR #include #include From 192dd7365f6b32c3b2807ff6a2b7ec4d028ab8f2 Mon Sep 17 00:00:00 2001 From: John Dias Date: Tue, 24 Jul 2018 17:43:49 -0700 Subject: [PATCH 47/53] Revert "arm64: Implement branch predictor hardening for affected Cortex-A CPUs" This reverts commit 1fc04374acc23198d1309a8e3f7adfbdb3a26010. Bug: 111785512 Change-Id: I5f69feb079346a99036f62bca57918451804c5cb Signed-off-by: John Dias --- arch/arm64/kernel/cpu_errata.c | 33 ++++----------------------------- 1 file changed, 4 insertions(+), 29 deletions(-) diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index 834af5d6478..561faa3d2e6 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -48,8 +48,6 @@ is_affected_midr_range(const struct arm64_cpu_capabilities *entry) DEFINE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data); #ifdef CONFIG_KVM -extern char __psci_hyp_bp_inval_start[], __psci_hyp_bp_inval_end[]; - static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start, const char *hyp_vecs_end) { @@ -91,12 +89,10 @@ static void __install_bp_hardening_cb(bp_hardening_cb_t fn, spin_unlock(&bp_lock); } #else -#define __psci_hyp_bp_inval_start NULL -#define __psci_hyp_bp_inval_end NULL - -static void __install_bp_hardening_cb(bp_hardening_cb_t fn, - const char *hyp_vecs_start, - const char *hyp_vecs_end) +static void __maybe_unused +__install_bp_hardening_cb(bp_hardening_cb_t fn, + const char *hyp_vecs_start, + const char *hyp_vecs_end) { __this_cpu_write(bp_hardening_data.fn, fn); } @@ -119,20 +115,6 @@ install_bp_hardening_cb(const struct arm64_cpu_capabilities *entry, __install_bp_hardening_cb(fn, hyp_vecs_start, hyp_vecs_end); } - -#include - -static void enable_psci_bp_hardening(void *data) -{ - const struct arm64_cpu_capabilities *entry = data; - - if (psci_ops.get_version) - install_bp_hardening_cb(entry, - (bp_hardening_cb_t)psci_ops.get_version, - __psci_hyp_bp_inval_start, - __psci_hyp_bp_inval_end); - -} #endif /* CONFIG_HARDEN_BRANCH_PREDICTOR */ #define MIDR_RANGE(model, min, max) \ @@ -188,13 +170,6 @@ const struct arm64_cpu_capabilities arm64_errata[] = { .capability = ARM64_WORKAROUND_845719, MIDR_RANGE(MIDR_KRYO2XX_SILVER, 0xA00004, 0xA00004), }, -#endif -#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR - { - .capability = ARM64_HARDEN_BRANCH_PREDICTOR, - MIDR_ALL_VERSIONS(MIDR_CORTEX_A57), - .enable = enable_psci_bp_hardening, - }, #endif { } From 734a0e81e22881dad7d71e8e6da3dd93b01dfb13 Mon Sep 17 00:00:00 2001 From: John Dias Date: Tue, 24 Jul 2018 17:43:58 -0700 Subject: [PATCH 48/53] Revert "drivers/firmware: Expose psci_get_version through psci_ops structure" This reverts commit dde04deca9687fcb4dd32943ea5d7bff94832787. Bug: 111785512 Change-Id: I0e6fae1862044e54d51d5919783015e1f86b5c5c Signed-off-by: John Dias --- arch/arm64/include/asm/psci.h | 20 -------------------- arch/arm64/kernel/psci.c | 22 ++++++++++++++++++---- 2 files changed, 18 insertions(+), 24 deletions(-) diff --git a/arch/arm64/include/asm/psci.h b/arch/arm64/include/asm/psci.h index fabf1084372..e5312ea0ec1 100644 --- a/arch/arm64/include/asm/psci.h +++ b/arch/arm64/include/asm/psci.h @@ -16,24 +16,4 @@ int psci_init(void); -struct psci_power_state { - u16 id; - u8 type; - u8 affinity_level; -}; - -struct psci_operations { - int (*get_version)(void); - int (*cpu_suspend)(unsigned long state_id, - unsigned long entry_point); - int (*cpu_off)(struct psci_power_state state); - int (*cpu_on)(unsigned long cpuid, unsigned long entry_point); - int (*migrate)(unsigned long cpuid); - int (*affinity_info)(unsigned long target_affinity, - unsigned long lowest_affinity_level); - int (*migrate_info_type)(void); -}; - -extern struct psci_operations psci_ops; - #endif /* __ASM_PSCI_H */ diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c index e2333060489..d8fd766b86e 100644 --- a/arch/arm64/kernel/psci.c +++ b/arch/arm64/kernel/psci.c @@ -43,7 +43,24 @@ #define PSCI_POWER_STATE_BIT BIT(30) -struct psci_operations psci_ops; +struct psci_power_state { + u16 id; + u8 type; + u8 affinity_level; +}; + +struct psci_operations { + int (*cpu_suspend)(unsigned long state_id, + unsigned long entry_point); + int (*cpu_off)(struct psci_power_state state); + int (*cpu_on)(unsigned long cpuid, unsigned long entry_point); + int (*migrate)(unsigned long cpuid); + int (*affinity_info)(unsigned long target_affinity, + unsigned long lowest_affinity_level); + int (*migrate_info_type)(void); +}; + +static struct psci_operations psci_ops; static int (*invoke_psci_fn)(u64, u64, u64, u64); typedef int (*psci_initcall_t)(const struct device_node *); @@ -308,7 +325,6 @@ static int __init psci_1_0_init(struct device_node *np) } pr_info("Using standard PSCI v0.2 function IDs\n"); - psci_ops.get_version = psci_get_version; psci_function_id[PSCI_FN_CPU_SUSPEND] = PSCI_0_2_FN64_CPU_SUSPEND; psci_ops.cpu_suspend = psci_cpu_suspend; @@ -362,7 +378,6 @@ static int __init psci_0_2_init(struct device_node *np) } pr_info("Using standard PSCI v0.2 function IDs\n"); - psci_ops.get_version = psci_get_version; psci_function_id[PSCI_FN_CPU_SUSPEND] = PSCI_0_2_FN64_CPU_SUSPEND; psci_ops.cpu_suspend = psci_cpu_suspend; @@ -405,7 +420,6 @@ static int __init psci_0_1_init(struct device_node *np) goto out_put_node; pr_info("Using PSCI v0.1 Function IDs from DT\n"); - psci_ops.get_version = psci_get_version; if (!of_property_read_u32(np, "cpu_suspend", &id)) { psci_function_id[PSCI_FN_CPU_SUSPEND] = id; From 2ec58365c16efc497cdc9b1cc6620e98abee156f Mon Sep 17 00:00:00 2001 From: John Dias Date: Tue, 24 Jul 2018 17:44:08 -0700 Subject: [PATCH 49/53] Revert "arm64: cpu_errata: Allow an erratum to be match for all revisions of a core" This reverts commit 118e7e0a13be3285f1456ab3741ecd148d24e4ab. Bug: 111785512 Change-Id: Ib11bcfafee33dd8ea40edbc4172e14d3d93300ec Signed-off-by: John Dias --- arch/arm64/kernel/cpu_errata.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index 561faa3d2e6..499a67de185 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -123,12 +123,6 @@ install_bp_hardening_cb(const struct arm64_cpu_capabilities *entry, .midr_range_min = min, \ .midr_range_max = max -#define MIDR_ALL_VERSIONS(model) \ - .matches = is_affected_midr_range, \ - .midr_model = model, \ - .midr_range_min = 0, \ - .midr_range_max = (MIDR_VARIANT_MASK | MIDR_REVISION_MASK) - const struct arm64_cpu_capabilities arm64_errata[] = { #if defined(CONFIG_ARM64_ERRATUM_826319) || \ defined(CONFIG_ARM64_ERRATUM_827319) || \ From ed068033eb19d9a6f9cb2cb92dfa4afcd3a94eb2 Mon Sep 17 00:00:00 2001 From: John Dias Date: Tue, 24 Jul 2018 17:44:19 -0700 Subject: [PATCH 50/53] Revert "arm64: Add skeleton to harden the branch predictor against aliasing attacks" This reverts commit 116af8e87eeb73ad395c05a6f0296dfc60f1ec80. Bug: 111785512 Change-Id: I2d1afc6243638cbc9e3b36067e3c95c40c2a0ae6 Signed-off-by: John Dias --- arch/arm64/Kconfig | 17 ------- arch/arm64/include/asm/cpufeature.h | 1 - arch/arm64/include/asm/mmu.h | 42 ---------------- arch/arm64/include/asm/sysreg.h | 1 - arch/arm64/kernel/Makefile | 4 -- arch/arm64/kernel/cpu_errata.c | 76 ----------------------------- arch/arm64/kernel/cpufeature.c | 1 - arch/arm64/kernel/entry.S | 8 ++- arch/arm64/mm/context.c | 1 - arch/arm64/mm/fault.c | 16 ------ 10 files changed, 3 insertions(+), 164 deletions(-) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 7f463b6eca5..c5052bbe744 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -796,23 +796,6 @@ config UNMAP_KERNEL_AT_EL0 If unsure, say Y. -config HARDEN_BRANCH_PREDICTOR - bool "Harden the branch predictor against aliasing attacks" if EXPERT - default y - help - Speculation attacks against some high-performance processors rely on - being able to manipulate the branch predictor for a victim context by - executing aliasing branches in the attacker context. Such attacks - can be partially mitigated against by clearing internal branch - predictor state and limiting the prediction logic in some situations. - - This config option will take CPU-specific actions to harden the - branch predictor against aliasing attacks and may rely on specific - instruction sequences or control bits being set by the system - firmware. - - If unsure, say Y. - menuconfig ARMV8_DEPRECATED bool "Emulate deprecated/obsolete ARMv8 instructions" depends on COMPAT diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index cacf6c74c7f..81e39e9e1f0 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -29,7 +29,6 @@ #define ARM64_HAS_PAN 4 #define ARM64_HAS_UAO 5 #define ARM64_ALT_PAN_NOT_UAO 6 -#define ARM64_HARDEN_BRANCH_PREDICTOR 7 #define ARM64_UNMAP_KERNEL_AT_EL0 23 #define ARM64_NCAPS 24 diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h index 6b0dd551a6c..e3ffa74e555 100644 --- a/arch/arm64/include/asm/mmu.h +++ b/arch/arm64/include/asm/mmu.h @@ -21,11 +21,6 @@ #ifndef __ASSEMBLY__ -#include - -#include -#include - typedef struct { atomic64_t id; void *vdso; @@ -44,43 +39,6 @@ static inline bool arm64_kernel_unmapped_at_el0(void) cpus_have_cap(ARM64_UNMAP_KERNEL_AT_EL0); } -typedef void (*bp_hardening_cb_t)(void); - -struct bp_hardening_data { - int hyp_vectors_slot; - bp_hardening_cb_t fn; -}; - -#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR -extern char __bp_harden_hyp_vecs_start[], __bp_harden_hyp_vecs_end[]; - -DECLARE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data); - -static inline struct bp_hardening_data *arm64_get_bp_hardening_data(void) -{ - return this_cpu_ptr(&bp_hardening_data); -} - -static inline void arm64_apply_bp_hardening(void) -{ - struct bp_hardening_data *d; - - if (!cpus_have_cap(ARM64_HARDEN_BRANCH_PREDICTOR)) - return; - - d = arm64_get_bp_hardening_data(); - if (d->fn) - d->fn(); -} -#else -static inline struct bp_hardening_data *arm64_get_bp_hardening_data(void) -{ - return NULL; -} - -static inline void arm64_apply_bp_hardening(void) { } -#endif /* CONFIG_HARDEN_BRANCH_PREDICTOR */ - extern void paging_init(void); extern void __iomem *early_io_map(phys_addr_t phys, unsigned long virt); extern void init_mem_pgprot(void); diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h index 3e4294cb3c5..0cc436bf726 100644 --- a/arch/arm64/include/asm/sysreg.h +++ b/arch/arm64/include/asm/sysreg.h @@ -101,7 +101,6 @@ #define ID_AA64ISAR0_AES_SHIFT 4 /* id_aa64pfr0 */ -#define ID_AA64PFR0_CSV2_SHIFT 56 #define ID_AA64PFR0_GIC_SHIFT 24 #define ID_AA64PFR0_ASIMD_SHIFT 20 #define ID_AA64PFR0_FP_SHIFT 16 diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index e56a0d13bff..848a5b232ed 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -47,10 +47,6 @@ arm64-obj-$(CONFIG_ARMV8_DEPRECATED) += armv8_deprecated.o arm64-obj-$(CONFIG_MSM_APP_API) += app_api.o arm64-obj-$(CONFIG_MSM_APP_SETTINGS) += app_setting.o -ifeq ($(CONFIG_KVM),y) -arm64-obj-$(CONFIG_HARDEN_BRANCH_PREDICTOR) += bpi.o -endif - obj-y += $(arm64-obj-y) vdso/ obj-$(CONFIG_VDSO32) += vdso32/ obj-m += $(arm64-obj-m) diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index 499a67de185..efcf303b047 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -41,82 +41,6 @@ is_affected_midr_range(const struct arm64_cpu_capabilities *entry) return (midr >= entry->midr_range_min && midr <= entry->midr_range_max); } -#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR -#include -#include - -DEFINE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data); - -#ifdef CONFIG_KVM -static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start, - const char *hyp_vecs_end) -{ - void *dst = lm_alias(__bp_harden_hyp_vecs_start + slot * SZ_2K); - int i; - - for (i = 0; i < SZ_2K; i += 0x80) - memcpy(dst + i, hyp_vecs_start, hyp_vecs_end - hyp_vecs_start); - - flush_icache_range((uintptr_t)dst, (uintptr_t)dst + SZ_2K); -} - -static void __install_bp_hardening_cb(bp_hardening_cb_t fn, - const char *hyp_vecs_start, - const char *hyp_vecs_end) -{ - static int last_slot = -1; - static DEFINE_SPINLOCK(bp_lock); - int cpu, slot = -1; - - spin_lock(&bp_lock); - for_each_possible_cpu(cpu) { - if (per_cpu(bp_hardening_data.fn, cpu) == fn) { - slot = per_cpu(bp_hardening_data.hyp_vectors_slot, cpu); - break; - } - } - - if (slot == -1) { - last_slot++; - BUG_ON(((__bp_harden_hyp_vecs_end - __bp_harden_hyp_vecs_start) - / SZ_2K) <= last_slot); - slot = last_slot; - __copy_hyp_vect_bpi(slot, hyp_vecs_start, hyp_vecs_end); - } - - __this_cpu_write(bp_hardening_data.hyp_vectors_slot, slot); - __this_cpu_write(bp_hardening_data.fn, fn); - spin_unlock(&bp_lock); -} -#else -static void __maybe_unused -__install_bp_hardening_cb(bp_hardening_cb_t fn, - const char *hyp_vecs_start, - const char *hyp_vecs_end) -{ - __this_cpu_write(bp_hardening_data.fn, fn); -} -#endif /* CONFIG_KVM */ - -static void __maybe_unused -install_bp_hardening_cb(const struct arm64_cpu_capabilities *entry, - bp_hardening_cb_t fn, - const char *hyp_vecs_start, - const char *hyp_vecs_end) -{ - u64 pfr0; - - if (!entry->matches(entry)) - return; - - pfr0 = read_cpuid(SYS_ID_AA64PFR0_EL1); - if (cpuid_feature_extract_unsigned_field(pfr0, ID_AA64PFR0_CSV2_SHIFT)) - return; - - __install_bp_hardening_cb(fn, hyp_vecs_start, hyp_vecs_end); -} -#endif /* CONFIG_HARDEN_BRANCH_PREDICTOR */ - #define MIDR_RANGE(model, min, max) \ .matches = is_affected_midr_range, \ .midr_model = model, \ diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 52c8f3cb8e3..ddd84dfd406 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -87,7 +87,6 @@ static struct arm64_ftr_bits ftr_id_aa64isar0[] = { static struct arm64_ftr_bits ftr_id_aa64pfr0[] = { ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 32, 32, 0), ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 28, 4, 0), - ARM64_FTR_BITS(FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_CSV2_SHIFT, 4, 0), ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64PFR0_GIC_SHIFT, 4, 0), ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_ASIMD_SHIFT, 4, ID_AA64PFR0_ASIMD_NI), ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_FP_SHIFT, 4, ID_AA64PFR0_FP_NI), diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index 3369f6b72a0..3c0d34dda83 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -632,15 +632,13 @@ el0_ia: * Instruction abort handling */ mrs x26, far_el1 - enable_dbg -#ifdef CONFIG_TRACE_IRQFLAGS - bl trace_hardirqs_off -#endif + // enable interrupts before calling the main handler + enable_dbg_and_irq ct_user_exit mov x0, x26 mov x1, x25 mov x2, sp - bl do_el0_ia_bp_hardening + bl do_mem_abort b ret_to_user el0_fpsimd_acc: /* diff --git a/arch/arm64/mm/context.c b/arch/arm64/mm/context.c index 9758b3d3e0a..cc3664b088d 100644 --- a/arch/arm64/mm/context.c +++ b/arch/arm64/mm/context.c @@ -202,7 +202,6 @@ void check_and_switch_context(struct mm_struct *mm, unsigned int cpu) /* Errata workaround post TTBRx_EL1 update. */ asmlinkage void post_ttbr_update_workaround(void) { - arm64_apply_bp_hardening(); } static int asids_init(void) diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index ad6c276b81b..bfce642eb1c 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -529,22 +529,6 @@ asmlinkage void __exception do_mem_abort(unsigned long addr, unsigned int esr, arm64_notify_die("", regs, &info, esr); } -asmlinkage void __exception do_el0_ia_bp_hardening(unsigned long addr, - unsigned int esr, - struct pt_regs *regs) -{ - /* - * We've taken an instruction abort from userspace and not yet - * re-enabled IRQs. If the address is a kernel address, apply - * BP hardening prior to enabling IRQs and pre-emption. - */ - if (addr > TASK_SIZE) - arm64_apply_bp_hardening(); - - local_irq_enable(); - do_mem_abort(addr, esr, regs); -} - /* * Handle stack alignment exceptions. */ From c445ef510babac050c0c91ba44133f5aff7dcc83 Mon Sep 17 00:00:00 2001 From: John Dias Date: Tue, 24 Jul 2018 17:44:31 -0700 Subject: [PATCH 51/53] Revert "arm64: cpufeature: Pass capability structure to ->enable callback" This reverts commit c1a59ea9c2d227f5ee09d40d3741f8d0459c5ea8. Bug: 111785512 Change-Id: Ieadadca78653b11119cd32042a6203ab4c5eb190 Signed-off-by: John Dias --- arch/arm64/kernel/cpufeature.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index ddd84dfd406..a51301773ef 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -805,7 +805,7 @@ void __init enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps) for (i = 0; caps[i].matches; i++) if (caps[i].enable && cpus_have_cap(caps[i].capability)) - on_each_cpu(caps[i].enable, (void *)&(caps[i]), true); + on_each_cpu(caps[i].enable, NULL, true); } #ifdef CONFIG_HOTPLUG_CPU @@ -920,7 +920,7 @@ void verify_local_cpu_capabilities(void) if (!feature_matches(__raw_read_system_reg(caps[i].sys_reg), &caps[i])) fail_incapable_cpu("arm64_features", &caps[i]); if (caps[i].enable) - caps[i].enable((void *)&(caps[i])); + caps[i].enable(NULL); } for (i = 0, caps = arm64_hwcaps; caps[i].matches; i++) { From bfb692d213be225c52ffcecd0d58df44bb5c23d0 Mon Sep 17 00:00:00 2001 From: John Dias Date: Tue, 24 Jul 2018 17:44:43 -0700 Subject: [PATCH 52/53] Revert "arm64: errata: Calling enable functions for CPU errata too" This reverts commit 09ec05ace0cd6dba97d9b3abedc1d680819a827c. Bug: 111785512 Change-Id: Ib0cb0f27b1def6163b039dd63ef86e360226a0c5 Signed-off-by: John Dias --- arch/arm64/include/asm/cpufeature.h | 2 -- arch/arm64/kernel/cpu_errata.c | 5 ----- arch/arm64/kernel/cpufeature.c | 4 ++-- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index 81e39e9e1f0..ba6983e901d 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -162,9 +162,7 @@ void __init setup_cpu_features(void); void update_cpu_capabilities(const struct arm64_cpu_capabilities *caps, const char *info); -void enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps); void check_local_cpu_errata(void); -void __init enable_errata_workarounds(void); #ifdef CONFIG_HOTPLUG_CPU void verify_local_cpu_capabilities(void); diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index efcf303b047..807d1c1de9d 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -97,8 +97,3 @@ void check_local_cpu_errata(void) { update_cpu_capabilities(arm64_errata, "enabling workaround for"); } - -void __init enable_errata_workarounds(void) -{ - enable_cpu_capabilities(arm64_errata); -} diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index a51301773ef..ec7e68c2c73 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -799,7 +799,8 @@ void update_cpu_capabilities(const struct arm64_cpu_capabilities *caps, * Run through the enabled capabilities and enable() it on all active * CPUs */ -void __init enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps) +static void __init +enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps) { int i; @@ -953,7 +954,6 @@ void __init setup_cpu_features(void) /* Set the CPU feature capabilies */ setup_feature_capabilities(); setup_cpu_hwcaps(); - enable_errata_workarounds(); /* Advertise that we have computed the system capabilities */ set_sys_caps_initialised(); From a3ced9894032cd3de6f0f0fabb0144fb355e46d0 Mon Sep 17 00:00:00 2001 From: John Dias Date: Thu, 9 Aug 2018 15:44:28 -0700 Subject: [PATCH 53/53] Revert "msm: ADSPRPC: Assign memory to VMID_SSC_Q6" This reverts commit 6568e2639e3481020fdfb4ee159b83d58ac84f87. Bug: 112247868 Signed-off-by: John Dias --- .../bindings/qdsp/msm-mdsprpc-mem.txt | 24 ---------- arch/arm/boot/dts/qcom/msm8996.dtsi | 7 +-- drivers/char/adsprpc.c | 47 +------------------ 3 files changed, 2 insertions(+), 76 deletions(-) delete mode 100644 Documentation/devicetree/bindings/qdsp/msm-mdsprpc-mem.txt diff --git a/Documentation/devicetree/bindings/qdsp/msm-mdsprpc-mem.txt b/Documentation/devicetree/bindings/qdsp/msm-mdsprpc-mem.txt deleted file mode 100644 index 2a5fc0ff17d..00000000000 --- a/Documentation/devicetree/bindings/qdsp/msm-mdsprpc-mem.txt +++ /dev/null @@ -1,24 +0,0 @@ -Qualcomm Technologies, Inc. FastRPC MDSP CMA Heap - -The MSM MDSPRPC memory device allocates CMA memory, for sharing memory -of FastRPC buffers to remote processor(MDSP). - -Required properties: --compatible: Must be "qcom,msm-mdsprpc-mem-region" --memory-region: A phandle that points to a memory heap where the -heap memory is allocated - -Example: - qcom,mdsprpc-mem { - compatible = "qcom,msm-mdsprpc-mem-region"; - memory-region = <&mdsp_mem>; - }; - -Ion Heap: - -Ion heap allows for sharing of buffers between different processors -and between user space and kernel space. -(see Documentation/devicetree/bindings/arm/msm/msm_ion.txt). - -Required properties for Ion heap: -- compatible : "qcom,msm-ion" diff --git a/arch/arm/boot/dts/qcom/msm8996.dtsi b/arch/arm/boot/dts/qcom/msm8996.dtsi index cd4401c638d..acb7aad8eb8 100644 --- a/arch/arm/boot/dts/qcom/msm8996.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996.dtsi @@ -294,7 +294,7 @@ compatible = "shared-dma-pool"; alloc-ranges = <0 0x00000000 0 0xffffffff>; reusable; - alignment = <0 0x400000>; + alignment = <0 0x100000>; size = <0 0x400000>; }; @@ -3588,11 +3588,6 @@ memory-region = <&adsp_mem>; }; - qcom,msm-mdsprpc-mem { - compatible = "qcom,msm-mdsprpc-mem-region"; - memory-region = <&adsp_mem>; - }; - qcom,msm_fastrpc { compatible = "qcom,msm-fastrpc-adsp"; diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 7c8a8918b51..9cb1a60b53a 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -58,7 +58,6 @@ #define ADSP_MMAP_HEAP_ADDR 4 #define FASTRPC_ENOSUCH 39 #define VMID_SSC_Q6 5 -#define VMID_ADSP_Q6 6 #define RPC_TIMEOUT (5 * HZ) #define BALIGN 128 @@ -218,7 +217,6 @@ struct fastrpc_apps { spinlock_t hlock; struct ion_client *client; struct device *dev; - struct device *modem_cma_dev; bool glink; spinlock_t ctxlock; struct smq_invoke_ctx *ctxtable[FASTRPC_CTX_MAX]; @@ -272,6 +270,7 @@ static struct fastrpc_channel_ctx gcinfo[NUM_CHANNELS] = { .subsys = "dsps", .channel = SMD_APPS_DSPS, .edge = "dsps", + .vmid = VMID_SSC_Q6, }, }; @@ -2268,7 +2267,6 @@ static struct of_device_id fastrpc_match_table[] = { { .compatible = "qcom,msm-fastrpc-compute-cb", }, { .compatible = "qcom,msm-fastrpc-legacy-compute-cb", }, { .compatible = "qcom,msm-adsprpc-mem-region", }, - { .compatible = "qcom,msm-mdsprpc-mem-region", }, {} }; @@ -2421,11 +2419,6 @@ static int fastrpc_probe(struct platform_device *pdev) int err = 0; struct fastrpc_apps *me = &gfa; struct device *dev = &pdev->dev; - struct smq_phy_page range; - struct device_node *ion_node, *node; - struct platform_device *ion_pdev; - struct cma *cma; - uint32_t val; if (of_device_is_compatible(dev->of_node, "qcom,msm-fastrpc-compute-cb")) @@ -2447,44 +2440,6 @@ static int fastrpc_probe(struct platform_device *pdev) return 0; } - if (of_device_is_compatible(dev->of_node, - "qcom,msm-mdsprpc-mem-region")) { - me->modem_cma_dev = dev; - range.addr = 0; - ion_node = of_find_compatible_node(NULL, NULL, "qcom,msm-ion"); - if (ion_node) { - for_each_available_child_of_node(ion_node, node) { - if (of_property_read_u32(node, "reg", &val)) - continue; - if (val != ION_ADSP_HEAP_ID) - continue; - ion_pdev = of_find_device_by_node(node); - if (!ion_pdev) - break; - cma = dev_get_cma_area(&ion_pdev->dev); - if (cma) { - range.addr = cma_get_base(cma); - range.size = (size_t)cma_get_size(cma); - } - break; - } - } - if (range.addr) { - int srcVM[1] = {VMID_HLOS}; - int destVM[3] = {VMID_HLOS, VMID_SSC_Q6, - VMID_ADSP_Q6}; - int destVMperm[3] = {PERM_READ | PERM_WRITE | PERM_EXEC, - PERM_READ | PERM_WRITE | PERM_EXEC, - PERM_READ | PERM_WRITE | PERM_EXEC, - }; - VERIFY(err, !hyp_assign_phys(range.addr, range.size, - srcVM, 1, destVM, destVMperm, 3)); - if (err) - goto bail; - } - return 0; - } - me->glink = of_property_read_bool(dev->of_node, "qcom,fastrpc-glink"); pr_info("adsprpc: channel link type: %d\n", me->glink);