From: Greg Kroah-Hartman Date: Wed, 29 Dec 2021 13:28:03 +0000 (+0100) Subject: 4.14-stable patches X-Git-Tag: v4.4.298~38 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=8ca5113f4ff9108dc26c874a0ecd9b30d402ae7f;p=thirdparty%2Fkernel%2Fstable-queue.git 4.14-stable patches added patches: hid-asus-add-depends-on-usb_hid-to-hid_asus-kconfig-option.patch tee-handle-lookup-of-shm-with-reference-count-0.patch --- diff --git a/queue-4.14/hid-asus-add-depends-on-usb_hid-to-hid_asus-kconfig-option.patch b/queue-4.14/hid-asus-add-depends-on-usb_hid-to-hid_asus-kconfig-option.patch new file mode 100644 index 00000000000..16ecabfa824 --- /dev/null +++ b/queue-4.14/hid-asus-add-depends-on-usb_hid-to-hid_asus-kconfig-option.patch @@ -0,0 +1,34 @@ +From c4f0126d487f3c68ab19ccb7c561e8fbf3ea2247 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Thu, 7 May 2020 11:53:34 +0200 +Subject: HID: asus: Add depends on USB_HID to HID_ASUS Kconfig option + +From: Hans de Goede + +commit c4f0126d487f3c68ab19ccb7c561e8fbf3ea2247 upstream. + +Since commit 4bc43a421218 ("HID: asus: Add +hid_is_using_ll_driver(usb_hid_driver) check") the hid-asus.c depends +on the usb_hid_driver symbol. Add a depends on USB_HID to Kconfig to +fix missing symbols errors in hid-asus when USB_HID is not enabled. + +Fixes: 4bc43a421218 ("HID: asus: Add hid_is_using_ll_driver(usb_hid_driver) check") +Reported-by: kbuild test robot +Signed-off-by: Hans de Goede +Signed-off-by: Jiri Kosina +Cc: Jason Self +Signed-off-by: Greg Kroah-Hartman +--- + drivers/hid/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -148,6 +148,7 @@ config HID_APPLEIR + + config HID_ASUS + tristate "Asus" ++ depends on USB_HID + depends on LEDS_CLASS + ---help--- + Support for Asus notebook built-in keyboard and touchpad via i2c, and diff --git a/queue-4.14/series b/queue-4.14/series new file mode 100644 index 00000000000..55c416b2c83 --- /dev/null +++ b/queue-4.14/series @@ -0,0 +1,2 @@ +hid-asus-add-depends-on-usb_hid-to-hid_asus-kconfig-option.patch +tee-handle-lookup-of-shm-with-reference-count-0.patch diff --git a/queue-4.14/tee-handle-lookup-of-shm-with-reference-count-0.patch b/queue-4.14/tee-handle-lookup-of-shm-with-reference-count-0.patch new file mode 100644 index 00000000000..ce19e43a4da --- /dev/null +++ b/queue-4.14/tee-handle-lookup-of-shm-with-reference-count-0.patch @@ -0,0 +1,304 @@ +From dfd0743f1d9ea76931510ed150334d571fbab49d Mon Sep 17 00:00:00 2001 +From: Jens Wiklander +Date: Thu, 9 Dec 2021 15:59:37 +0100 +Subject: tee: handle lookup of shm with reference count 0 + +From: Jens Wiklander + +commit dfd0743f1d9ea76931510ed150334d571fbab49d upstream. + +Since the tee subsystem does not keep a strong reference to its idle +shared memory buffers, it races with other threads that try to destroy a +shared memory through a close of its dma-buf fd or by unmapping the +memory. + +In tee_shm_get_from_id() when a lookup in teedev->idr has been +successful, it is possible that the tee_shm is in the dma-buf teardown +path, but that path is blocked by the teedev mutex. Since we don't have +an API to tell if the tee_shm is in the dma-buf teardown path or not we +must find another way of detecting this condition. + +Fix this by doing the reference counting directly on the tee_shm using a +new refcount_t refcount field. dma-buf is replaced by using +anon_inode_getfd() instead, this separates the life-cycle of the +underlying file from the tee_shm. tee_shm_put() is updated to hold the +mutex when decreasing the refcount to 0 and then remove the tee_shm from +teedev->idr before releasing the mutex. This means that the tee_shm can +never be found unless it has a refcount larger than 0. + +Fixes: 967c9cca2cc5 ("tee: generic TEE subsystem") +Cc: stable@vger.kernel.org +Reviewed-by: Greg Kroah-Hartman +Reviewed-by: Lars Persson +Reviewed-by: Sumit Garg +Reported-by: Patrik Lantz +[JW: backported to 4.14-stable] +Signed-off-by: Jens Wiklander +Signed-off-by: Greg Kroah-Hartman +--- + drivers/tee/tee_private.h | 4 - + drivers/tee/tee_shm.c | 155 ++++++++++++++++++---------------------------- + 2 files changed, 63 insertions(+), 96 deletions(-) + +--- a/drivers/tee/tee_private.h ++++ b/drivers/tee/tee_private.h +@@ -31,7 +31,7 @@ struct tee_device; + * @paddr: physical address of the shared memory + * @kaddr: virtual address of the shared memory + * @size: size of shared memory +- * @dmabuf: dmabuf used to for exporting to user space ++ * @refcount: reference counter + * @flags: defined by TEE_SHM_* in tee_drv.h + * @id: unique id of a shared memory object on this device + */ +@@ -42,7 +42,7 @@ struct tee_shm { + phys_addr_t paddr; + void *kaddr; + size_t size; +- struct dma_buf *dmabuf; ++ refcount_t refcount; + u32 flags; + int id; + }; +--- a/drivers/tee/tee_shm.c ++++ b/drivers/tee/tee_shm.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2015-2016, Linaro Limited ++ * Copyright (c) 2015-2017, 2019-2021 Linaro Limited + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and +@@ -11,26 +11,19 @@ + * GNU General Public License for more details. + * + */ ++#include + #include +-#include +-#include + #include ++#include + #include + #include + #include + #include "tee_private.h" + +-static void tee_shm_release(struct tee_shm *shm) ++static void tee_shm_release(struct tee_device *teedev, struct tee_shm *shm) + { +- struct tee_device *teedev = shm->teedev; + struct tee_shm_pool_mgr *poolm; + +- mutex_lock(&teedev->mutex); +- idr_remove(&teedev->idr, shm->id); +- if (shm->ctx) +- list_del(&shm->link); +- mutex_unlock(&teedev->mutex); +- + if (shm->flags & TEE_SHM_DMA_BUF) + poolm = &teedev->pool->dma_buf_mgr; + else +@@ -42,53 +35,6 @@ static void tee_shm_release(struct tee_s + tee_device_put(teedev); + } + +-static struct sg_table *tee_shm_op_map_dma_buf(struct dma_buf_attachment +- *attach, enum dma_data_direction dir) +-{ +- return NULL; +-} +- +-static void tee_shm_op_unmap_dma_buf(struct dma_buf_attachment *attach, +- struct sg_table *table, +- enum dma_data_direction dir) +-{ +-} +- +-static void tee_shm_op_release(struct dma_buf *dmabuf) +-{ +- struct tee_shm *shm = dmabuf->priv; +- +- tee_shm_release(shm); +-} +- +-static void *tee_shm_op_map_atomic(struct dma_buf *dmabuf, unsigned long pgnum) +-{ +- return NULL; +-} +- +-static void *tee_shm_op_map(struct dma_buf *dmabuf, unsigned long pgnum) +-{ +- return NULL; +-} +- +-static int tee_shm_op_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) +-{ +- struct tee_shm *shm = dmabuf->priv; +- size_t size = vma->vm_end - vma->vm_start; +- +- return remap_pfn_range(vma, vma->vm_start, shm->paddr >> PAGE_SHIFT, +- size, vma->vm_page_prot); +-} +- +-static const struct dma_buf_ops tee_shm_dma_buf_ops = { +- .map_dma_buf = tee_shm_op_map_dma_buf, +- .unmap_dma_buf = tee_shm_op_unmap_dma_buf, +- .release = tee_shm_op_release, +- .map_atomic = tee_shm_op_map_atomic, +- .map = tee_shm_op_map, +- .mmap = tee_shm_op_mmap, +-}; +- + /** + * tee_shm_alloc() - Allocate shared memory + * @ctx: Context that allocates the shared memory +@@ -135,6 +81,7 @@ struct tee_shm *tee_shm_alloc(struct tee + goto err_dev_put; + } + ++ refcount_set(&shm->refcount, 1); + shm->flags = flags; + shm->teedev = teedev; + shm->ctx = ctx; +@@ -157,29 +104,11 @@ struct tee_shm *tee_shm_alloc(struct tee + goto err_pool_free; + } + +- if (flags & TEE_SHM_DMA_BUF) { +- DEFINE_DMA_BUF_EXPORT_INFO(exp_info); +- +- exp_info.ops = &tee_shm_dma_buf_ops; +- exp_info.size = shm->size; +- exp_info.flags = O_RDWR; +- exp_info.priv = shm; +- +- shm->dmabuf = dma_buf_export(&exp_info); +- if (IS_ERR(shm->dmabuf)) { +- ret = ERR_CAST(shm->dmabuf); +- goto err_rem; +- } +- } + mutex_lock(&teedev->mutex); + list_add_tail(&shm->link, &ctx->list_shm); + mutex_unlock(&teedev->mutex); + + return shm; +-err_rem: +- mutex_lock(&teedev->mutex); +- idr_remove(&teedev->idr, shm->id); +- mutex_unlock(&teedev->mutex); + err_pool_free: + poolm->ops->free(poolm, shm); + err_kfree: +@@ -190,6 +119,31 @@ err_dev_put: + } + EXPORT_SYMBOL_GPL(tee_shm_alloc); + ++static int tee_shm_fop_release(struct inode *inode, struct file *filp) ++{ ++ tee_shm_put(filp->private_data); ++ return 0; ++} ++ ++static int tee_shm_fop_mmap(struct file *filp, struct vm_area_struct *vma) ++{ ++ struct tee_shm *shm = filp->private_data; ++ size_t size = vma->vm_end - vma->vm_start; ++ ++ /* check for overflowing the buffer's size */ ++ if (vma->vm_pgoff + vma_pages(vma) > shm->size >> PAGE_SHIFT) ++ return -EINVAL; ++ ++ return remap_pfn_range(vma, vma->vm_start, shm->paddr >> PAGE_SHIFT, ++ size, vma->vm_page_prot); ++} ++ ++static const struct file_operations tee_shm_fops = { ++ .owner = THIS_MODULE, ++ .release = tee_shm_fop_release, ++ .mmap = tee_shm_fop_mmap, ++}; ++ + /** + * tee_shm_get_fd() - Increase reference count and return file descriptor + * @shm: Shared memory handle +@@ -203,10 +157,11 @@ int tee_shm_get_fd(struct tee_shm *shm) + if ((shm->flags & req_flags) != req_flags) + return -EINVAL; + +- get_dma_buf(shm->dmabuf); +- fd = dma_buf_fd(shm->dmabuf, O_CLOEXEC); ++ /* matched by tee_shm_put() in tee_shm_op_release() */ ++ refcount_inc(&shm->refcount); ++ fd = anon_inode_getfd("tee_shm", &tee_shm_fops, shm, O_RDWR); + if (fd < 0) +- dma_buf_put(shm->dmabuf); ++ tee_shm_put(shm); + return fd; + } + +@@ -216,17 +171,7 @@ int tee_shm_get_fd(struct tee_shm *shm) + */ + void tee_shm_free(struct tee_shm *shm) + { +- /* +- * dma_buf_put() decreases the dmabuf reference counter and will +- * call tee_shm_release() when the last reference is gone. +- * +- * In the case of driver private memory we call tee_shm_release +- * directly instead as it doesn't have a reference counter. +- */ +- if (shm->flags & TEE_SHM_DMA_BUF) +- dma_buf_put(shm->dmabuf); +- else +- tee_shm_release(shm); ++ tee_shm_put(shm); + } + EXPORT_SYMBOL_GPL(tee_shm_free); + +@@ -327,10 +272,15 @@ struct tee_shm *tee_shm_get_from_id(stru + teedev = ctx->teedev; + mutex_lock(&teedev->mutex); + shm = idr_find(&teedev->idr, id); ++ /* ++ * If the tee_shm was found in the IDR it must have a refcount ++ * larger than 0 due to the guarantee in tee_shm_put() below. So ++ * it's safe to use refcount_inc(). ++ */ + if (!shm || shm->ctx != ctx) + shm = ERR_PTR(-EINVAL); +- else if (shm->flags & TEE_SHM_DMA_BUF) +- get_dma_buf(shm->dmabuf); ++ else ++ refcount_inc(&shm->refcount); + mutex_unlock(&teedev->mutex); + return shm; + } +@@ -353,7 +303,24 @@ EXPORT_SYMBOL_GPL(tee_shm_get_id); + */ + void tee_shm_put(struct tee_shm *shm) + { +- if (shm->flags & TEE_SHM_DMA_BUF) +- dma_buf_put(shm->dmabuf); ++ struct tee_device *teedev = shm->teedev; ++ bool do_release = false; ++ ++ mutex_lock(&teedev->mutex); ++ if (refcount_dec_and_test(&shm->refcount)) { ++ /* ++ * refcount has reached 0, we must now remove it from the ++ * IDR before releasing the mutex. This will guarantee ++ * that the refcount_inc() in tee_shm_get_from_id() never ++ * starts from 0. ++ */ ++ if (shm->ctx) ++ list_del(&shm->link); ++ do_release = true; ++ } ++ mutex_unlock(&teedev->mutex); ++ ++ if (do_release) ++ tee_shm_release(teedev, shm); + } + EXPORT_SYMBOL_GPL(tee_shm_put);