diff --git a/kabi/severities b/kabi/severities index 75634f4..c0cac3b 100644 --- a/kabi/severities +++ b/kabi/severities @@ -51,3 +51,6 @@ drivers/net/wireless/ath/ath9k/* PASS # local symbols sound/soc/rockchip/* PASS +# not used externally, mark it pass in +# order to catch any wrong use bsc#1193767 +drivers/tee/tee PASS diff --git a/patches.suse/tee-don-t-assign-shm-id-for-private-shms.patch b/patches.suse/tee-don-t-assign-shm-id-for-private-shms.patch new file mode 100644 index 0000000..107a52d --- /dev/null +++ b/patches.suse/tee-don-t-assign-shm-id-for-private-shms.patch @@ -0,0 +1,93 @@ +From: Jens Wiklander +Date: Thu, 7 Nov 2019 11:42:56 +0100 +Subject: tee: don't assign shm id for private shms +Git-commit: f1bbacedb0af640a93e47799203e556be2825da3 +Patch-mainline: v5.7-rc1 +References: bsc#1193767 CVE-2021-44733 + +Private shared memory object must not be referenced from user space. To +guarantee that, don't assign an id to shared memory objects which are +driver private. + +Signed-off-by: Jens Wiklander +Acked-by: Borislav Petkov +--- + drivers/tee/tee_private.h | 3 ++- + drivers/tee/tee_shm.c | 31 ++++++++++++++++++------------- + 2 files changed, 20 insertions(+), 14 deletions(-) + +diff --git a/drivers/tee/tee_private.h b/drivers/tee/tee_private.h +index f797171f0434..e55204df31ce 100644 +--- a/drivers/tee/tee_private.h ++++ b/drivers/tee/tee_private.h +@@ -37,7 +37,8 @@ struct tee_shm_pool { + * @num_users: number of active users of this device + * @c_no_user: completion used when unregistering the device + * @mutex: mutex protecting @num_users and @idr +- * @idr: register of shared memory object allocated on this device ++ * @idr: register of user space shared memory objects allocated or ++ * registered on this device + * @pool: shared memory pool + */ + struct tee_device { +diff --git a/drivers/tee/tee_shm.c b/drivers/tee/tee_shm.c +index b666854c2491..02210f179ae3 100644 +--- a/drivers/tee/tee_shm.c ++++ b/drivers/tee/tee_shm.c +@@ -15,9 +15,11 @@ static void tee_shm_release(struct tee_shm *shm) + { + struct tee_device *teedev = shm->teedev; + +- mutex_lock(&teedev->mutex); +- idr_remove(&teedev->idr, shm->id); +- mutex_unlock(&teedev->mutex); ++ if (shm->flags & TEE_SHM_DMA_BUF) { ++ mutex_lock(&teedev->mutex); ++ idr_remove(&teedev->idr, shm->id); ++ mutex_unlock(&teedev->mutex); ++ } + + if (shm->flags & TEE_SHM_POOL) { + struct tee_shm_pool_mgr *poolm; +@@ -137,17 +139,18 @@ struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags) + goto err_kfree; + } + +- mutex_lock(&teedev->mutex); +- shm->id = idr_alloc(&teedev->idr, shm, 1, 0, GFP_KERNEL); +- mutex_unlock(&teedev->mutex); +- if (shm->id < 0) { +- ret = ERR_PTR(shm->id); +- goto err_pool_free; +- } + + if (flags & TEE_SHM_DMA_BUF) { + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); + ++ mutex_lock(&teedev->mutex); ++ shm->id = idr_alloc(&teedev->idr, shm, 1, 0, GFP_KERNEL); ++ mutex_unlock(&teedev->mutex); ++ if (shm->id < 0) { ++ ret = ERR_PTR(shm->id); ++ goto err_pool_free; ++ } ++ + exp_info.ops = &tee_shm_dma_buf_ops; + exp_info.size = shm->size; + exp_info.flags = O_RDWR; +@@ -165,9 +168,11 @@ struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags) + + return shm; + err_rem: +- mutex_lock(&teedev->mutex); +- idr_remove(&teedev->idr, shm->id); +- mutex_unlock(&teedev->mutex); ++ if (flags & TEE_SHM_DMA_BUF) { ++ mutex_lock(&teedev->mutex); ++ idr_remove(&teedev->idr, shm->id); ++ mutex_unlock(&teedev->mutex); ++ } + err_pool_free: + poolm->ops->free(poolm, shm); + err_kfree: + diff --git a/patches.suse/tee-handle-lookup-of-shm-with-reference-count-0.patch b/patches.suse/tee-handle-lookup-of-shm-with-reference-count-0.patch new file mode 100644 index 0000000..a40e0ab --- /dev/null +++ b/patches.suse/tee-handle-lookup-of-shm-with-reference-count-0.patch @@ -0,0 +1,333 @@ +From: Jens Wiklander +Date: Thu, 9 Dec 2021 15:59:37 +0100 +Subject: tee: handle lookup of shm with reference count 0 +Git-commit: dfd0743f1d9ea76931510ed150334d571fbab49d +Patch-mainline: v5.16-rc7 +References: bsc#1193767 CVE-2021-44733 + +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 +Signed-off-by: Jens Wiklander +Acked-by: Borislav Petkov +--- + drivers/tee/tee_shm.c | 177 +++++++++++++++++------------------------------- + include/linux/tee_drv.h | 4 - + 2 files changed, 68 insertions(+), 113 deletions(-) + +--- a/drivers/tee/tee_shm.c ++++ b/drivers/tee/tee_shm.c +@@ -1,26 +1,18 @@ + // SPDX-License-Identifier: GPL-2.0-only + /* +- * Copyright (c) 2015-2016, Linaro Limited ++ * Copyright (c) 2015-2017, 2019-2021 Linaro Limited + */ ++#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; +- +- if (shm->flags & TEE_SHM_DMA_BUF) { +- mutex_lock(&teedev->mutex); +- idr_remove(&teedev->idr, shm->id); +- mutex_unlock(&teedev->mutex); +- } +- + if (shm->flags & TEE_SHM_POOL) { + struct tee_shm_pool_mgr *poolm; + +@@ -52,45 +52,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 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; +- +- /* Refuse sharing shared memory provided by application */ +- if (shm->flags & TEE_SHM_REGISTER) +- return -EINVAL; +- +- 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, +- .mmap = tee_shm_op_mmap, +-}; +- + static struct tee_shm *__tee_shm_alloc(struct tee_context *ctx, + struct tee_device *teedev, + size_t size, u32 flags) +@@ -137,6 +84,7 @@ static struct tee_shm *__tee_shm_alloc(s + goto err_dev_put; + } + ++ refcount_set(&shm->refcount, 1); + shm->flags = flags | TEE_SHM_POOL; + shm->teedev = teedev; + shm->ctx = ctx; +@@ -151,10 +99,7 @@ static struct tee_shm *__tee_shm_alloc(s + goto err_kfree; + } + +- + if (flags & TEE_SHM_DMA_BUF) { +- DEFINE_DMA_BUF_EXPORT_INFO(exp_info); +- + mutex_lock(&teedev->mutex); + shm->id = idr_alloc(&teedev->idr, shm, 1, 0, GFP_KERNEL); + mutex_unlock(&teedev->mutex); +@@ -162,29 +107,12 @@ static struct tee_shm *__tee_shm_alloc(s + ret = ERR_PTR(shm->id); + goto err_pool_free; + } +- +- 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; +- } + } + + if (ctx) + teedev_ctx_get(ctx); + + return shm; +-err_rem: +- if (flags & TEE_SHM_DMA_BUF) { +- mutex_lock(&teedev->mutex); +- idr_remove(&teedev->idr, shm->id); +- mutex_unlock(&teedev->mutex); +- } + err_pool_free: + poolm->ops->free(poolm, shm); + err_kfree: +@@ -249,6 +177,7 @@ struct tee_shm *tee_shm_register(struct + goto err; + } + ++ refcount_set(&shm->refcount, 1); + shm->flags = flags | TEE_SHM_REGISTER; + shm->teedev = teedev; + shm->ctx = ctx; +@@ -289,22 +218,6 @@ struct tee_shm *tee_shm_register(struct + goto err; + } + +- 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); +- teedev->desc->ops->shm_unregister(ctx, shm); +- goto err; +- } +- } +- + return shm; + err: + if (shm) { +@@ -328,6 +241,35 @@ err: + } + EXPORT_SYMBOL_GPL(tee_shm_register); + ++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; ++ ++ /* Refuse sharing shared memory provided by application */ ++ if (shm->flags & TEE_SHM_USER_MAPPED) ++ return -EINVAL; ++ ++ /* 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 +@@ -340,10 +282,11 @@ int tee_shm_get_fd(struct tee_shm *shm) + if (!(shm->flags & TEE_SHM_DMA_BUF)) + 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; + } + +@@ -353,17 +296,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); + +@@ -470,10 +403,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; + } +@@ -485,7 +423,24 @@ EXPORT_SYMBOL_GPL(tee_shm_get_from_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->ctx->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->flags & TEE_SHM_DMA_BUF) ++ idr_remove(&teedev->idr, shm->id); ++ do_release = true; ++ } ++ mutex_unlock(&teedev->mutex); ++ ++ if (do_release) ++ tee_shm_release(teedev, shm); + } + EXPORT_SYMBOL_GPL(tee_shm_put); +--- a/include/linux/tee_drv.h ++++ b/include/linux/tee_drv.h +@@ -177,7 +177,7 @@ void tee_device_unregister(struct tee_de + * @offset: offset of buffer in user space + * @pages: locked pages from userspace + * @num_pages: number of locked pages +- * @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 + * +@@ -194,7 +194,7 @@ struct tee_shm { + unsigned int offset; + struct page **pages; + size_t num_pages; +- struct dma_buf *dmabuf; ++ refcount_t refcount; + u32 flags; + int id; + }; diff --git a/patches.suse/tee-remove-linked-list-of-struct-tee_shm.patch b/patches.suse/tee-remove-linked-list-of-struct-tee_shm.patch new file mode 100644 index 0000000..b04d474 --- /dev/null +++ b/patches.suse/tee-remove-linked-list-of-struct-tee_shm.patch @@ -0,0 +1,64 @@ +From: Jens Wiklander +Date: Thu, 7 Nov 2019 11:42:49 +0100 +Subject: tee: remove linked list of struct tee_shm +Git-commit: 59a135f6fb669f4f79f43160c7b8c8d6bfb37f75 +Patch-mainline: v5.7-rc1 +References: bsc#1193767 CVE-2021-44733 + +Removes list_shm from struct tee_context since the linked list isn't used +any longer. + +Signed-off-by: Jens Wiklander + [ bp: Drop the include/linux/tee_drv.h hunk to avoid kABI breakage ] +Acked-by: Borislav Petkov +--- + drivers/tee/tee_core.c | 1 - + drivers/tee/tee_shm.c | 12 +----------- + 2 files changed, 1 insertion(+), 12 deletions(-) + +--- a/drivers/tee/tee_core.c ++++ b/drivers/tee/tee_core.c +@@ -44,7 +44,6 @@ static struct tee_context *teedev_open(s + + kref_init(&ctx->refcount); + ctx->teedev = teedev; +- INIT_LIST_HEAD(&ctx->list_shm); + rc = teedev->desc->ops->open(ctx); + if (rc) + goto err; +--- a/drivers/tee/tee_shm.c ++++ b/drivers/tee/tee_shm.c +@@ -17,8 +17,6 @@ static void tee_shm_release(struct tee_s + + 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_POOL) { +@@ -174,12 +172,8 @@ static struct tee_shm *__tee_shm_alloc(s + } + } + +- if (ctx) { ++ if (ctx) + teedev_ctx_get(ctx); +- mutex_lock(&teedev->mutex); +- list_add_tail(&shm->link, &ctx->list_shm); +- mutex_unlock(&teedev->mutex); +- } + + return shm; + err_rem: +@@ -306,10 +300,6 @@ struct tee_shm *tee_shm_register(struct + } + } + +- mutex_lock(&teedev->mutex); +- list_add_tail(&shm->link, &ctx->list_shm); +- mutex_unlock(&teedev->mutex); +- + return shm; + err: + if (shm) { diff --git a/series.conf b/series.conf index e3bdd25..0b7a62e 100644 --- a/series.conf +++ b/series.conf @@ -28019,6 +28019,8 @@ patches.suse/soc-fsl-qe-fix-sparse-warnings-for-qe_ic.c.patch patches.suse/soc-fsl-qe-ucc_slow-remove-0-assignment-for-kzalloc-.patch patches.suse/soc-fsl-qe-fix-sparse-warnings-for-ucc_slow.c.patch + patches.suse/tee-remove-linked-list-of-struct-tee_shm.patch + patches.suse/tee-don-t-assign-shm-id-for-private-shms.patch patches.suse/ARM-dts-sunxi-Fix-DE2-clocks-register-range.patch patches.suse/arm64-dts-allwinner-a64-Fix-display-clock-register-r.patch patches.suse/arm64-tegra-Fix-Tegra194-PCIe-compatible-string.patch @@ -53485,6 +53487,7 @@ patches.suse/xen-netback-don-t-queue-unlimited-number-of-packages.patch patches.suse/spi-change-clk_disable_unprepare-to-clk_unprepare.patch patches.suse/RDMA-hns-Replace-kfree-with-kvfree.patch + patches.suse/tee-handle-lookup-of-shm-with-reference-count-0.patch patches.suse/mmc-sdhci-tegra-Fix-switch-to-HS400ES-mode.patch patches.suse/ALSA-drivers-opl3-Fix-incorrect-use-of-vp-state.patch patches.suse/ALSA-jack-Check-the-return-value-of-kstrdup.patch