From 19cf8898c9d390c4a14e86a245b1131de514418b Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Thu, 12 Aug 2021 07:51:32 -0400 Subject: [PATCH] Fixes for 5.10 Signed-off-by: Sasha Levin --- ...t-release-tee-shm-session-and-contex.patch | 85 ++++++++++ ...by-one-indexing-when-nullifying-last.patch | 52 ++++++ queue-5.10/series | 4 + ...propriate-usage-of-tee_shm_dma_buf-f.patch | 148 ++++++++++++++++++ ...use-list_replace_init-before-travers.patch | 117 ++++++++++++++ 5 files changed, 406 insertions(+) create mode 100644 queue-5.10/firmware-tee_bnxt-release-tee-shm-session-and-contex.patch create mode 100644 queue-5.10/kvm-svm-fix-off-by-one-indexing-when-nullifying-last.patch create mode 100644 queue-5.10/series create mode 100644 queue-5.10/tee-correct-inappropriate-usage-of-tee_shm_dma_buf-f.patch create mode 100644 queue-5.10/usb-dwc3-gadget-use-list_replace_init-before-travers.patch diff --git a/queue-5.10/firmware-tee_bnxt-release-tee-shm-session-and-contex.patch b/queue-5.10/firmware-tee_bnxt-release-tee-shm-session-and-contex.patch new file mode 100644 index 00000000000..c9c458aaeb1 --- /dev/null +++ b/queue-5.10/firmware-tee_bnxt-release-tee-shm-session-and-contex.patch @@ -0,0 +1,85 @@ +From 5114754396a891105fa2fda1111831d71466eb6e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 14 Jun 2021 17:33:17 -0500 +Subject: firmware: tee_bnxt: Release TEE shm, session, and context during + kexec + +From: Allen Pais + +[ Upstream commit 914ab19e471d8fb535ed50dff108b0a615f3c2d8 ] + +Implement a .shutdown hook that will be called during a kexec operation +so that the TEE shared memory, session, and context that were set up +during .probe can be properly freed/closed. + +Additionally, don't use dma-buf backed shared memory for the +fw_shm_pool. dma-buf backed shared memory cannot be reliably freed and +unregistered during a kexec operation even when tee_shm_free() is called +on the shm from a .shutdown hook. The problem occurs because +dma_buf_put() calls fput() which then uses task_work_add(), with the +TWA_RESUME parameter, to queue tee_shm_release() to be called before the +current task returns to user mode. However, the current task never +returns to user mode before the kexec completes so the memory is never +freed nor unregistered. + +Use tee_shm_alloc_kernel_buf() to avoid dma-buf backed shared memory +allocation so that tee_shm_free() can directly call tee_shm_release(). +This will ensure that the shm can be freed and unregistered during a +kexec operation. + +Fixes: 246880958ac9 ("firmware: broadcom: add OP-TEE based BNXT f/w manager") +Cc: stable@vger.kernel.org +Signed-off-by: Allen Pais +Co-developed-by: Tyler Hicks +Signed-off-by: Tyler Hicks +Reviewed-by: Sumit Garg +Acked-by: Florian Fainelli +Signed-off-by: Jens Wiklander +Signed-off-by: Sasha Levin +--- + drivers/firmware/broadcom/tee_bnxt_fw.c | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +diff --git a/drivers/firmware/broadcom/tee_bnxt_fw.c b/drivers/firmware/broadcom/tee_bnxt_fw.c +index ed10da5313e8..a5bf4c3f6dc7 100644 +--- a/drivers/firmware/broadcom/tee_bnxt_fw.c ++++ b/drivers/firmware/broadcom/tee_bnxt_fw.c +@@ -212,10 +212,9 @@ static int tee_bnxt_fw_probe(struct device *dev) + + pvt_data.dev = dev; + +- fw_shm_pool = tee_shm_alloc(pvt_data.ctx, MAX_SHM_MEM_SZ, +- TEE_SHM_MAPPED | TEE_SHM_DMA_BUF); ++ fw_shm_pool = tee_shm_alloc_kernel_buf(pvt_data.ctx, MAX_SHM_MEM_SZ); + if (IS_ERR(fw_shm_pool)) { +- dev_err(pvt_data.dev, "tee_shm_alloc failed\n"); ++ dev_err(pvt_data.dev, "tee_shm_alloc_kernel_buf failed\n"); + err = PTR_ERR(fw_shm_pool); + goto out_sess; + } +@@ -242,6 +241,14 @@ static int tee_bnxt_fw_remove(struct device *dev) + return 0; + } + ++static void tee_bnxt_fw_shutdown(struct device *dev) ++{ ++ tee_shm_free(pvt_data.fw_shm_pool); ++ tee_client_close_session(pvt_data.ctx, pvt_data.session_id); ++ tee_client_close_context(pvt_data.ctx); ++ pvt_data.ctx = NULL; ++} ++ + static const struct tee_client_device_id tee_bnxt_fw_id_table[] = { + {UUID_INIT(0x6272636D, 0x2019, 0x0716, + 0x42, 0x43, 0x4D, 0x5F, 0x53, 0x43, 0x48, 0x49)}, +@@ -257,6 +264,7 @@ static struct tee_client_driver tee_bnxt_fw_driver = { + .bus = &tee_bus_type, + .probe = tee_bnxt_fw_probe, + .remove = tee_bnxt_fw_remove, ++ .shutdown = tee_bnxt_fw_shutdown, + }, + }; + +-- +2.30.2 + diff --git a/queue-5.10/kvm-svm-fix-off-by-one-indexing-when-nullifying-last.patch b/queue-5.10/kvm-svm-fix-off-by-one-indexing-when-nullifying-last.patch new file mode 100644 index 00000000000..8127e7d1762 --- /dev/null +++ b/queue-5.10/kvm-svm-fix-off-by-one-indexing-when-nullifying-last.patch @@ -0,0 +1,52 @@ +From 6a82a6669f0eb4635d3128baa4ce3004c2f34aa3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Aug 2021 09:27:46 -0700 +Subject: KVM: SVM: Fix off-by-one indexing when nullifying last used SEV VMCB + +From: Sean Christopherson + +[ Upstream commit 179c6c27bf487273652efc99acd3ba512a23c137 ] + +Use the raw ASID, not ASID-1, when nullifying the last used VMCB when +freeing an SEV ASID. The consumer, pre_sev_run(), indexes the array by +the raw ASID, thus KVM could get a false negative when checking for a +different VMCB if KVM manages to reallocate the same ASID+VMCB combo for +a new VM. + +Note, this cannot cause a functional issue _in the current code_, as +pre_sev_run() also checks which pCPU last did VMRUN for the vCPU, and +last_vmentry_cpu is initialized to -1 during vCPU creation, i.e. is +guaranteed to mismatch on the first VMRUN. However, prior to commit +8a14fe4f0c54 ("kvm: x86: Move last_cpu into kvm_vcpu_arch as +last_vmentry_cpu"), SVM tracked pCPU on its own and zero-initialized the +last_cpu variable. Thus it's theoretically possible that older versions +of KVM could miss a TLB flush if the first VMRUN is on pCPU0 and the ASID +and VMCB exactly match those of a prior VM. + +Fixes: 70cd94e60c73 ("KVM: SVM: VMRUN should use associated ASID when SEV is enabled") +Cc: Tom Lendacky +Cc: Brijesh Singh +Cc: stable@vger.kernel.org +Signed-off-by: Sean Christopherson +Signed-off-by: Paolo Bonzini +Signed-off-by: Sasha Levin +--- + arch/x86/kvm/svm/sev.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c +index 01547bdbfb06..6c82ef22985d 100644 +--- a/arch/x86/kvm/svm/sev.c ++++ b/arch/x86/kvm/svm/sev.c +@@ -124,7 +124,7 @@ static void sev_asid_free(int asid) + + for_each_possible_cpu(cpu) { + sd = per_cpu(svm_data, cpu); +- sd->sev_vmcbs[pos] = NULL; ++ sd->sev_vmcbs[asid] = NULL; + } + + mutex_unlock(&sev_bitmap_lock); +-- +2.30.2 + diff --git a/queue-5.10/series b/queue-5.10/series new file mode 100644 index 00000000000..f8481c70ad6 --- /dev/null +++ b/queue-5.10/series @@ -0,0 +1,4 @@ +kvm-svm-fix-off-by-one-indexing-when-nullifying-last.patch +tee-correct-inappropriate-usage-of-tee_shm_dma_buf-f.patch +usb-dwc3-gadget-use-list_replace_init-before-travers.patch +firmware-tee_bnxt-release-tee-shm-session-and-contex.patch diff --git a/queue-5.10/tee-correct-inappropriate-usage-of-tee_shm_dma_buf-f.patch b/queue-5.10/tee-correct-inappropriate-usage-of-tee_shm_dma_buf-f.patch new file mode 100644 index 00000000000..5b26cff1342 --- /dev/null +++ b/queue-5.10/tee-correct-inappropriate-usage-of-tee_shm_dma_buf-f.patch @@ -0,0 +1,148 @@ +From 4ffd7c162578c7f17231f5522bd3d537497dad20 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 14 Jun 2021 17:33:15 -0500 +Subject: tee: Correct inappropriate usage of TEE_SHM_DMA_BUF flag + +From: Sumit Garg + +[ Upstream commit 376e4199e327a5cf29b8ec8fb0f64f3d8b429819 ] + +Currently TEE_SHM_DMA_BUF flag has been inappropriately used to not +register shared memory allocated for private usage by underlying TEE +driver: OP-TEE in this case. So rather add a new flag as TEE_SHM_PRIV +that can be utilized by underlying TEE drivers for private allocation +and usage of shared memory. + +With this corrected, allow tee_shm_alloc_kernel_buf() to allocate a +shared memory region without the backing of dma-buf. + +Cc: stable@vger.kernel.org +Signed-off-by: Sumit Garg +Co-developed-by: Tyler Hicks +Signed-off-by: Tyler Hicks +Reviewed-by: Jens Wiklander +Reviewed-by: Sumit Garg +Signed-off-by: Jens Wiklander +Signed-off-by: Sasha Levin +--- + drivers/tee/optee/call.c | 2 +- + drivers/tee/optee/core.c | 3 ++- + drivers/tee/optee/rpc.c | 5 +++-- + drivers/tee/optee/shm_pool.c | 8 ++++++-- + drivers/tee/tee_shm.c | 4 ++-- + include/linux/tee_drv.h | 1 + + 6 files changed, 15 insertions(+), 8 deletions(-) + +diff --git a/drivers/tee/optee/call.c b/drivers/tee/optee/call.c +index 1231ce56e712..f8f1594bea43 100644 +--- a/drivers/tee/optee/call.c ++++ b/drivers/tee/optee/call.c +@@ -181,7 +181,7 @@ static struct tee_shm *get_msg_arg(struct tee_context *ctx, size_t num_params, + struct optee_msg_arg *ma; + + shm = tee_shm_alloc(ctx, OPTEE_MSG_GET_ARG_SIZE(num_params), +- TEE_SHM_MAPPED); ++ TEE_SHM_MAPPED | TEE_SHM_PRIV); + if (IS_ERR(shm)) + return shm; + +diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c +index 7b17248f1527..823a81d8ff0e 100644 +--- a/drivers/tee/optee/core.c ++++ b/drivers/tee/optee/core.c +@@ -278,7 +278,8 @@ static void optee_release(struct tee_context *ctx) + if (!ctxdata) + return; + +- shm = tee_shm_alloc(ctx, sizeof(struct optee_msg_arg), TEE_SHM_MAPPED); ++ shm = tee_shm_alloc(ctx, sizeof(struct optee_msg_arg), ++ TEE_SHM_MAPPED | TEE_SHM_PRIV); + if (!IS_ERR(shm)) { + arg = tee_shm_get_va(shm, 0); + /* +diff --git a/drivers/tee/optee/rpc.c b/drivers/tee/optee/rpc.c +index 6cbb3643c6c4..9dbdd783d6f2 100644 +--- a/drivers/tee/optee/rpc.c ++++ b/drivers/tee/optee/rpc.c +@@ -313,7 +313,7 @@ static void handle_rpc_func_cmd_shm_alloc(struct tee_context *ctx, + shm = cmd_alloc_suppl(ctx, sz); + break; + case OPTEE_MSG_RPC_SHM_TYPE_KERNEL: +- shm = tee_shm_alloc(ctx, sz, TEE_SHM_MAPPED); ++ shm = tee_shm_alloc(ctx, sz, TEE_SHM_MAPPED | TEE_SHM_PRIV); + break; + default: + arg->ret = TEEC_ERROR_BAD_PARAMETERS; +@@ -501,7 +501,8 @@ void optee_handle_rpc(struct tee_context *ctx, struct optee_rpc_param *param, + + switch (OPTEE_SMC_RETURN_GET_RPC_FUNC(param->a0)) { + case OPTEE_SMC_RPC_FUNC_ALLOC: +- shm = tee_shm_alloc(ctx, param->a1, TEE_SHM_MAPPED); ++ shm = tee_shm_alloc(ctx, param->a1, ++ TEE_SHM_MAPPED | TEE_SHM_PRIV); + if (!IS_ERR(shm) && !tee_shm_get_pa(shm, 0, &pa)) { + reg_pair_from_64(¶m->a1, ¶m->a2, pa); + reg_pair_from_64(¶m->a4, ¶m->a5, +diff --git a/drivers/tee/optee/shm_pool.c b/drivers/tee/optee/shm_pool.c +index da06ce9b9313..c41a9a501a6e 100644 +--- a/drivers/tee/optee/shm_pool.c ++++ b/drivers/tee/optee/shm_pool.c +@@ -27,7 +27,11 @@ static int pool_op_alloc(struct tee_shm_pool_mgr *poolm, + shm->paddr = page_to_phys(page); + shm->size = PAGE_SIZE << order; + +- if (shm->flags & TEE_SHM_DMA_BUF) { ++ /* ++ * Shared memory private to the OP-TEE driver doesn't need ++ * to be registered with OP-TEE. ++ */ ++ if (!(shm->flags & TEE_SHM_PRIV)) { + unsigned int nr_pages = 1 << order, i; + struct page **pages; + +@@ -60,7 +64,7 @@ err: + static void pool_op_free(struct tee_shm_pool_mgr *poolm, + struct tee_shm *shm) + { +- if (shm->flags & TEE_SHM_DMA_BUF) ++ if (!(shm->flags & TEE_SHM_PRIV)) + optee_shm_unregister(shm->ctx, shm); + + free_pages((unsigned long)shm->kaddr, get_order(shm->size)); +diff --git a/drivers/tee/tee_shm.c b/drivers/tee/tee_shm.c +index c65e44707cd6..8a9384a64f3e 100644 +--- a/drivers/tee/tee_shm.c ++++ b/drivers/tee/tee_shm.c +@@ -117,7 +117,7 @@ struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags) + return ERR_PTR(-EINVAL); + } + +- if ((flags & ~(TEE_SHM_MAPPED | TEE_SHM_DMA_BUF))) { ++ if ((flags & ~(TEE_SHM_MAPPED | TEE_SHM_DMA_BUF | TEE_SHM_PRIV))) { + dev_err(teedev->dev.parent, "invalid shm flags 0x%x", flags); + return ERR_PTR(-EINVAL); + } +@@ -207,7 +207,7 @@ EXPORT_SYMBOL_GPL(tee_shm_alloc); + */ + struct tee_shm *tee_shm_alloc_kernel_buf(struct tee_context *ctx, size_t size) + { +- return tee_shm_alloc(ctx, size, TEE_SHM_MAPPED | TEE_SHM_DMA_BUF); ++ return tee_shm_alloc(ctx, size, TEE_SHM_MAPPED); + } + EXPORT_SYMBOL_GPL(tee_shm_alloc_kernel_buf); + +diff --git a/include/linux/tee_drv.h b/include/linux/tee_drv.h +index 9b24cc3d3024..459e9a76d7e6 100644 +--- a/include/linux/tee_drv.h ++++ b/include/linux/tee_drv.h +@@ -27,6 +27,7 @@ + #define TEE_SHM_USER_MAPPED BIT(4) /* Memory mapped in user space */ + #define TEE_SHM_POOL BIT(5) /* Memory allocated from pool */ + #define TEE_SHM_KERNEL_MAPPED BIT(6) /* Memory mapped in kernel space */ ++#define TEE_SHM_PRIV BIT(7) /* Memory private to TEE driver */ + + struct device; + struct tee_device; +-- +2.30.2 + diff --git a/queue-5.10/usb-dwc3-gadget-use-list_replace_init-before-travers.patch b/queue-5.10/usb-dwc3-gadget-use-list_replace_init-before-travers.patch new file mode 100644 index 00000000000..b5bcbf4ff6b --- /dev/null +++ b/queue-5.10/usb-dwc3-gadget-use-list_replace_init-before-travers.patch @@ -0,0 +1,117 @@ +From c73f9064fdd78a34de47d939739b92cc54257c7c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jul 2021 00:33:14 -0700 +Subject: usb: dwc3: gadget: Use list_replace_init() before traversing lists + +From: Wesley Cheng + +[ Upstream commit d25d85061bd856d6be221626605319154f9b5043 ] + +The list_for_each_entry_safe() macro saves the current item (n) and +the item after (n+1), so that n can be safely removed without +corrupting the list. However, when traversing the list and removing +items using gadget giveback, the DWC3 lock is briefly released, +allowing other routines to execute. There is a situation where, while +items are being removed from the cancelled_list using +dwc3_gadget_ep_cleanup_cancelled_requests(), the pullup disable +routine is running in parallel (due to UDC unbind). As the cleanup +routine removes n, and the pullup disable removes n+1, once the +cleanup retakes the DWC3 lock, it references a request who was already +removed/handled. With list debug enabled, this leads to a panic. +Ensure all instances of the macro are replaced where gadget giveback +is used. + +Example call stack: + +Thread#1: +__dwc3_gadget_ep_set_halt() - CLEAR HALT + -> dwc3_gadget_ep_cleanup_cancelled_requests() + ->list_for_each_entry_safe() + ->dwc3_gadget_giveback(n) + ->dwc3_gadget_del_and_unmap_request()- n deleted[cancelled_list] + ->spin_unlock + ->Thread#2 executes + ... + ->dwc3_gadget_giveback(n+1) + ->Already removed! + +Thread#2: +dwc3_gadget_pullup() + ->waiting for dwc3 spin_lock + ... + ->Thread#1 released lock + ->dwc3_stop_active_transfers() + ->dwc3_remove_requests() + ->fetches n+1 item from cancelled_list (n removed by Thread#1) + ->dwc3_gadget_giveback() + ->dwc3_gadget_del_and_unmap_request()- n+1 +deleted[cancelled_list] + ->spin_unlock + +Fix this condition by utilizing list_replace_init(), and traversing +through a local copy of the current elements in the endpoint lists. +This will also set the parent list as empty, so if another thread is +also looping through the list, it will be empty on the next iteration. + +Fixes: d4f1afe5e896 ("usb: dwc3: gadget: move requests to cancelled_list") +Cc: stable +Acked-by: Felipe Balbi +Signed-off-by: Wesley Cheng +Link: https://lore.kernel.org/r/1627543994-20327-1-git-send-email-wcheng@codeaurora.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/dwc3/gadget.c | 18 ++++++++++++++++-- + 1 file changed, 16 insertions(+), 2 deletions(-) + +diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c +index 756839e0e91d..788bbb38cf79 100644 +--- a/drivers/usb/dwc3/gadget.c ++++ b/drivers/usb/dwc3/gadget.c +@@ -1733,11 +1733,18 @@ static void dwc3_gadget_ep_cleanup_cancelled_requests(struct dwc3_ep *dep) + { + struct dwc3_request *req; + struct dwc3_request *tmp; ++ struct list_head local; + +- list_for_each_entry_safe(req, tmp, &dep->cancelled_list, list) { ++restart: ++ list_replace_init(&dep->cancelled_list, &local); ++ ++ list_for_each_entry_safe(req, tmp, &local, list) { + dwc3_gadget_ep_skip_trbs(dep, req); + dwc3_gadget_giveback(dep, req, -ECONNRESET); + } ++ ++ if (!list_empty(&dep->cancelled_list)) ++ goto restart; + } + + static int dwc3_gadget_ep_dequeue(struct usb_ep *ep, +@@ -2867,8 +2874,12 @@ static void dwc3_gadget_ep_cleanup_completed_requests(struct dwc3_ep *dep, + { + struct dwc3_request *req; + struct dwc3_request *tmp; ++ struct list_head local; + +- list_for_each_entry_safe(req, tmp, &dep->started_list, list) { ++restart: ++ list_replace_init(&dep->started_list, &local); ++ ++ list_for_each_entry_safe(req, tmp, &local, list) { + int ret; + + ret = dwc3_gadget_ep_cleanup_completed_request(dep, event, +@@ -2876,6 +2887,9 @@ static void dwc3_gadget_ep_cleanup_completed_requests(struct dwc3_ep *dep, + if (ret) + break; + } ++ ++ if (!list_empty(&dep->started_list)) ++ goto restart; + } + + static bool dwc3_gadget_ep_should_continue(struct dwc3_ep *dep) +-- +2.30.2 + -- 2.47.3