From 6ad1b1ce29e96115e87cb14b9b6ee8abb4457efb Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Thu, 12 Aug 2021 07:51:33 -0400 Subject: [PATCH] Fixes for 5.4 Signed-off-by: Sasha Levin --- ...by-one-indexing-when-nullifying-last.patch | 52 ++++++ queue-5.4/series | 3 + ...propriate-usage-of-tee_shm_dma_buf-f.patch | 148 ++++++++++++++++++ ...use-list_replace_init-before-travers.patch | 117 ++++++++++++++ 4 files changed, 320 insertions(+) create mode 100644 queue-5.4/kvm-svm-fix-off-by-one-indexing-when-nullifying-last.patch create mode 100644 queue-5.4/series create mode 100644 queue-5.4/tee-correct-inappropriate-usage-of-tee_shm_dma_buf-f.patch create mode 100644 queue-5.4/usb-dwc3-gadget-use-list_replace_init-before-travers.patch diff --git a/queue-5.4/kvm-svm-fix-off-by-one-indexing-when-nullifying-last.patch b/queue-5.4/kvm-svm-fix-off-by-one-indexing-when-nullifying-last.patch new file mode 100644 index 00000000000..66fe497dca6 --- /dev/null +++ b/queue-5.4/kvm-svm-fix-off-by-one-indexing-when-nullifying-last.patch @@ -0,0 +1,52 @@ +From f3fe4c34ef2801ae8ad6144f11330b372872d649 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.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c +index 7341d22ed04f..2a958dcc80f2 100644 +--- a/arch/x86/kvm/svm.c ++++ b/arch/x86/kvm/svm.c +@@ -1783,7 +1783,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; + } + } + +-- +2.30.2 + diff --git a/queue-5.4/series b/queue-5.4/series new file mode 100644 index 00000000000..abf81961e66 --- /dev/null +++ b/queue-5.4/series @@ -0,0 +1,3 @@ +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 diff --git a/queue-5.4/tee-correct-inappropriate-usage-of-tee_shm_dma_buf-f.patch b/queue-5.4/tee-correct-inappropriate-usage-of-tee_shm_dma_buf-f.patch new file mode 100644 index 00000000000..914a2515002 --- /dev/null +++ b/queue-5.4/tee-correct-inappropriate-usage-of-tee_shm_dma_buf-f.patch @@ -0,0 +1,148 @@ +From 5ee3f4d4c0206969a1f3122a8fc259f32acde4c6 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 4b5069f88d78..3a54455d9ddf 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 432dd38921dd..4bb4c8f28cbd 100644 +--- a/drivers/tee/optee/core.c ++++ b/drivers/tee/optee/core.c +@@ -254,7 +254,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 b4ade54d1f28..aecf62016e7b 100644 +--- a/drivers/tee/optee/rpc.c ++++ b/drivers/tee/optee/rpc.c +@@ -220,7 +220,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; +@@ -405,7 +405,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 1b4b4a1ba91d..d6491e973fa4 100644 +--- a/drivers/tee/tee_shm.c ++++ b/drivers/tee/tee_shm.c +@@ -117,7 +117,7 @@ static struct tee_shm *__tee_shm_alloc(struct tee_context *ctx, + 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); + } +@@ -233,7 +233,7 @@ EXPORT_SYMBOL_GPL(tee_shm_priv_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 91677f2fa2e8..cd15c1b7fae0 100644 +--- a/include/linux/tee_drv.h ++++ b/include/linux/tee_drv.h +@@ -26,6 +26,7 @@ + #define TEE_SHM_REGISTER BIT(3) /* Memory registered in secure world */ + #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_PRIV BIT(7) /* Memory private to TEE driver */ + + struct device; + struct tee_device; +-- +2.30.2 + diff --git a/queue-5.4/usb-dwc3-gadget-use-list_replace_init-before-travers.patch b/queue-5.4/usb-dwc3-gadget-use-list_replace_init-before-travers.patch new file mode 100644 index 00000000000..1ad9182214a --- /dev/null +++ b/queue-5.4/usb-dwc3-gadget-use-list_replace_init-before-travers.patch @@ -0,0 +1,117 @@ +From 3b6405938fd74df7b35ae997af0f481e0ce80d52 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 9cf66636b19d..dd0aff33c7ca 100644 +--- a/drivers/usb/dwc3/gadget.c ++++ b/drivers/usb/dwc3/gadget.c +@@ -1623,11 +1623,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, +@@ -2684,8 +2691,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, +@@ -2693,6 +2704,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