* [PATCH v4 0/8] tee: Improve support for kexec and kdump
@ 2021-06-10 21:09 Tyler Hicks
2021-06-10 21:09 ` [PATCH v4 1/8] optee: Fix memory leak when failing to register shm pages Tyler Hicks
` (7 more replies)
0 siblings, 8 replies; 18+ messages in thread
From: Tyler Hicks @ 2021-06-10 21:09 UTC (permalink / raw)
To: op-tee
[-- Attachment #1: Type: text/plain, Size: 5129 bytes --]
v4:
- Incorporated 'tee: add tee_shm_alloc_kernel_buf()' from Jens to remove
the need to expose TEE_SHM_REGISTER to callers of tee_shm_alloc()
- Updated 'tee: Support kernel shm registration without dma-buf backing'
to drop the TEE_SHM_DMA_BUF flag when tee_shm_alloc_kernel_buf() calls
tee_shm_alloc()
- Updated the final two patches, against ftpm and tee_bnxt_fw, to use
tee_shm_alloc_kernel_buf() instead of tee_shm_alloc()
- Minor cleanups to the commit messages of the updates patches
v3: https://lore.kernel.org/lkml/20210609002326.210024-1-tyhicks(a)linux.microsoft.com/
v2: https://lore.kernel.org/lkml/20210225090610.242623-1-allen.lkml(a)gmail.com/
v1: https://lore.kernel.org/lkml/20210217092714.121297-1-allen.lkml(a)gmail.com/
This series fixes several bugs uncovered while exercising the OP-TEE
(Open Portable Trusted Execution Environment), ftpm (firmware TPM), and
tee_bnxt_fw (Broadcom BNXT firmware manager) drivers with kexec and
kdump (emergency kexec) based workflows.
The majority of the problems are caused by missing .shutdown hooks in
the drivers. The .shutdown hooks are used by the normal kexec code path
to let the drivers clean up prior to executing the target kernel. The
.remove hooks, which are already implemented in these drivers, are not
called as part of the kexec code path. This resulted in shared memory
regions, that were cached and/or registered with OP-TEE, not being
cleared/unregistered prior to kexec. The new kernel would then run into
problems when handling the previously cached virtual addresses or trying
to register newly allocated shared memory objects that overlapped with
the previously registered virtual addresses. The TEE didn't receive
notification that the old virtual addresses were no longer meaningful
and that a new kernel, with a new address space, would soon be running.
However, implementing .shutdown hooks was not enough for supporting
kexec. There was an additional problem caused by the TEE driver's
reliance on the dma-buf subsystem for multi-page shared memory objects
that were registered with the TEE. Shared memory objects backed by a
dma-buf use a different mechanism for reference counting. When the final
reference is released, work is scheduled to be executed to unregister
the shared memory with the TEE but that work is only completed prior to
the current task returning the userspace. In the case of a kexec
operation, the current task that's calling the driver .shutdown hooks
never returns to userspace prior to the kexec operation so the shared
memory was never unregistered. This eventually caused problems from
overlapping shared memory regions that were registered with the TEE
after several kexec operations. The large 4M contiguous region
allocated by the tee_bnxt_fw driver reliably ran into this issue on the
fourth kexec on a system with 8G of RAM.
The use of dma-buf makes sense for shared memory that's in use by
userspace but dma-buf's aren't needed for shared memory that will only
used by the driver. This series separates dma-buf backed shared memory
allocated by the kernel from multi-page shared memory that the kernel
simply needs registered with the TEE for private use.
One other noteworthy change in this series is to completely refuse to
load the OP-TEE driver in the kdump kernel. This is needed because the
secure world may have had all of its threads in suspended state when the
regular kernel crashed. The kdump kernel would then hang during boot
because the OP-TEE driver's .probe function would attempt to use a
secure world thread when they're all in suspended state. Another problem
is that shared memory allocations could fail under the kdump kernel
because the previously registered were not unregistered (the .shutdown
hook is not called when kexec'ing into the kdump kernel).
The first patch in the series fixes potential memory leaks that are not
directly related to kexec or kdump but were noticed during the
development of this series.
Tyler
Allen Pais (2):
optee: fix tee out of memory failure seen during kexec reboot
firmware: tee_bnxt: Release TEE shm, session, and context during kexec
Jens Wiklander (1):
tee: add tee_shm_alloc_kernel_buf()
Tyler Hicks (5):
optee: Fix memory leak when failing to register shm pages
optee: Refuse to load the driver under the kdump kernel
optee: Clear stale cache entries during initialization
tee: Support kernel shm registration without dma-buf backing
tpm_ftpm_tee: Free and unregister TEE shared memory during kexec
drivers/char/tpm/tpm_ftpm_tee.c | 8 ++---
drivers/firmware/broadcom/tee_bnxt_fw.c | 14 +++++++--
drivers/tee/optee/call.c | 11 ++++++-
drivers/tee/optee/core.c | 42 ++++++++++++++++++++++++-
drivers/tee/optee/optee_private.h | 2 +-
drivers/tee/optee/shm_pool.c | 17 +++++++---
drivers/tee/tee_shm.c | 29 ++++++++++++++++-
include/linux/tee_drv.h | 1 +
8 files changed, 108 insertions(+), 16 deletions(-)
--
2.25.1
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v4 1/8] optee: Fix memory leak when failing to register shm pages
2021-06-10 21:09 [PATCH v4 0/8] tee: Improve support for kexec and kdump Tyler Hicks
@ 2021-06-10 21:09 ` Tyler Hicks
2021-06-11 9:05 ` Jens Wiklander
2021-06-10 21:09 ` [PATCH v4 2/8] optee: Refuse to load the driver under the kdump kernel Tyler Hicks
` (6 subsequent siblings)
7 siblings, 1 reply; 18+ messages in thread
From: Tyler Hicks @ 2021-06-10 21:09 UTC (permalink / raw)
To: op-tee
[-- Attachment #1: Type: text/plain, Size: 1220 bytes --]
Free the previously allocated pages when we encounter an error condition
while attempting to register the pages with the secure world.
Fixes: a249dd200d03 ("tee: optee: Fix dynamic shm pool allocations")
Fixes: 5a769f6ff439 ("optee: Fix multi page dynamic shm pool alloc")
Signed-off-by: Tyler Hicks <tyhicks@linux.microsoft.com>
---
drivers/tee/optee/shm_pool.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/drivers/tee/optee/shm_pool.c b/drivers/tee/optee/shm_pool.c
index d767eebf30bd..da06ce9b9313 100644
--- a/drivers/tee/optee/shm_pool.c
+++ b/drivers/tee/optee/shm_pool.c
@@ -32,8 +32,10 @@ static int pool_op_alloc(struct tee_shm_pool_mgr *poolm,
struct page **pages;
pages = kcalloc(nr_pages, sizeof(pages), GFP_KERNEL);
- if (!pages)
- return -ENOMEM;
+ if (!pages) {
+ rc = -ENOMEM;
+ goto err;
+ }
for (i = 0; i < nr_pages; i++) {
pages[i] = page;
@@ -44,8 +46,14 @@ static int pool_op_alloc(struct tee_shm_pool_mgr *poolm,
rc = optee_shm_register(shm->ctx, shm, pages, nr_pages,
(unsigned long)shm->kaddr);
kfree(pages);
+ if (rc)
+ goto err;
}
+ return 0;
+
+err:
+ __free_pages(page, order);
return rc;
}
--
2.25.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v4 2/8] optee: Refuse to load the driver under the kdump kernel
2021-06-10 21:09 [PATCH v4 0/8] tee: Improve support for kexec and kdump Tyler Hicks
2021-06-10 21:09 ` [PATCH v4 1/8] optee: Fix memory leak when failing to register shm pages Tyler Hicks
@ 2021-06-10 21:09 ` Tyler Hicks
2021-06-11 9:08 ` Jens Wiklander
2021-06-10 21:09 ` [PATCH v4 3/8] optee: fix tee out of memory failure seen during kexec reboot Tyler Hicks
` (5 subsequent siblings)
7 siblings, 1 reply; 18+ messages in thread
From: Tyler Hicks @ 2021-06-10 21:09 UTC (permalink / raw)
To: op-tee
[-- Attachment #1: Type: text/plain, Size: 2540 bytes --]
Fix a hung task issue, seen when booting the kdump kernel, that is
caused by all of the secure world threads being in a permanent suspended
state:
INFO: task swapper/0:1 blocked for more than 120 seconds.
Not tainted 5.4.83 #1
"echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
swapper/0 D 0 1 0 0x00000028
Call trace:
__switch_to+0xc8/0x118
__schedule+0x2e0/0x700
schedule+0x38/0xb8
schedule_timeout+0x258/0x388
wait_for_completion+0x16c/0x4b8
optee_cq_wait_for_completion+0x28/0xa8
optee_disable_shm_cache+0xb8/0xf8
optee_probe+0x560/0x61c
platform_drv_probe+0x58/0xa8
really_probe+0xe0/0x338
driver_probe_device+0x5c/0xf0
device_driver_attach+0x74/0x80
__driver_attach+0x64/0xe0
bus_for_each_dev+0x84/0xd8
driver_attach+0x30/0x40
bus_add_driver+0x188/0x1e8
driver_register+0x64/0x110
__platform_driver_register+0x54/0x60
optee_driver_init+0x20/0x28
do_one_initcall+0x54/0x24c
kernel_init_freeable+0x1e8/0x2c0
kernel_init+0x18/0x118
ret_from_fork+0x10/0x18
The invoke_fn hook returned OPTEE_SMC_RETURN_ETHREAD_LIMIT, indicating
that the secure world threads were all in a suspended state at the time
of the kernel crash. This intermittently prevented the kdump kernel from
booting, resulting in a failure to collect the kernel dump.
Make kernel dump collection more reliable on systems utilizing OP-TEE by
refusing to load the driver under the kdump kernel.
Signed-off-by: Tyler Hicks <tyhicks@linux.microsoft.com>
---
drivers/tee/optee/core.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
index ddb8f9ecf307..5288cd767d82 100644
--- a/drivers/tee/optee/core.c
+++ b/drivers/tee/optee/core.c
@@ -6,6 +6,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/arm-smccc.h>
+#include <linux/crash_dump.h>
#include <linux/errno.h>
#include <linux/io.h>
#include <linux/module.h>
@@ -612,6 +613,16 @@ static int optee_probe(struct platform_device *pdev)
u32 sec_caps;
int rc;
+ /*
+ * The kernel may have crashed at the same time that all available
+ * secure world threads were suspended and we cannot reschedule the
+ * suspended threads without access to the crashed kernel's wait_queue.
+ * Therefore, we cannot reliably initialize the OP-TEE driver in the
+ * kdump kernel.
+ */
+ if (is_kdump_kernel())
+ return -ENODEV;
+
invoke_fn = get_invoke_func(&pdev->dev);
if (IS_ERR(invoke_fn))
return PTR_ERR(invoke_fn);
--
2.25.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v4 3/8] optee: fix tee out of memory failure seen during kexec reboot
2021-06-10 21:09 [PATCH v4 0/8] tee: Improve support for kexec and kdump Tyler Hicks
2021-06-10 21:09 ` [PATCH v4 1/8] optee: Fix memory leak when failing to register shm pages Tyler Hicks
2021-06-10 21:09 ` [PATCH v4 2/8] optee: Refuse to load the driver under the kdump kernel Tyler Hicks
@ 2021-06-10 21:09 ` Tyler Hicks
2021-06-11 9:11 ` Jens Wiklander
2021-06-14 7:22 ` Jens Wiklander
2021-06-10 21:09 ` [PATCH v4 4/8] optee: Clear stale cache entries during initialization Tyler Hicks
` (4 subsequent siblings)
7 siblings, 2 replies; 18+ messages in thread
From: Tyler Hicks @ 2021-06-10 21:09 UTC (permalink / raw)
To: op-tee
[-- Attachment #1: Type: text/plain, Size: 2151 bytes --]
From: Allen Pais <apais@linux.microsoft.com>
The following out of memory errors are seen on kexec reboot
from the optee core.
[ 0.368428] tee_bnxt_fw optee-clnt0: tee_shm_alloc failed
[ 0.368461] tee_bnxt_fw: probe of optee-clnt0 failed with error -22
tee_shm_release() is not invoked on dma shm buffer.
Implement .shutdown() method to handle the release of the buffers
correctly.
More info:
https://github.com/OP-TEE/optee_os/issues/3637
Signed-off-by: Allen Pais <apais@linux.microsoft.com>
Reviewed-by: Tyler Hicks <tyhicks@linux.microsoft.com>
---
drivers/tee/optee/core.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
index 5288cd767d82..0987074d7ed0 100644
--- a/drivers/tee/optee/core.c
+++ b/drivers/tee/optee/core.c
@@ -573,6 +573,13 @@ static optee_invoke_fn *get_invoke_func(struct device *dev)
return ERR_PTR(-EINVAL);
}
+/* optee_remove - Device Removal Routine
+ * @pdev: platform device information struct
+ *
+ * optee_remove is called by platform subsystem to alert the driver
+ * that it should release the device
+ */
+
static int optee_remove(struct platform_device *pdev)
{
struct optee *optee = platform_get_drvdata(pdev);
@@ -603,6 +610,18 @@ static int optee_remove(struct platform_device *pdev)
return 0;
}
+/* optee_shutdown - Device Removal Routine
+ * @pdev: platform device information struct
+ *
+ * platform_shutdown is called by the platform subsystem to alert
+ * the driver that a shutdown, reboot, or kexec is happening and
+ * device must be disabled.
+ */
+static void optee_shutdown(struct platform_device *pdev)
+{
+ optee_disable_shm_cache(platform_get_drvdata(pdev));
+}
+
static int optee_probe(struct platform_device *pdev)
{
optee_invoke_fn *invoke_fn;
@@ -739,6 +758,7 @@ MODULE_DEVICE_TABLE(of, optee_dt_match);
static struct platform_driver optee_driver = {
.probe = optee_probe,
.remove = optee_remove,
+ .shutdown = optee_shutdown,
.driver = {
.name = "optee",
.of_match_table = optee_dt_match,
--
2.25.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v4 4/8] optee: Clear stale cache entries during initialization
2021-06-10 21:09 [PATCH v4 0/8] tee: Improve support for kexec and kdump Tyler Hicks
` (2 preceding siblings ...)
2021-06-10 21:09 ` [PATCH v4 3/8] optee: fix tee out of memory failure seen during kexec reboot Tyler Hicks
@ 2021-06-10 21:09 ` Tyler Hicks
2021-06-14 8:27 ` Jens Wiklander
2021-06-10 21:09 ` [PATCH v4 5/8] tee: add tee_shm_alloc_kernel_buf() Tyler Hicks
` (3 subsequent siblings)
7 siblings, 1 reply; 18+ messages in thread
From: Tyler Hicks @ 2021-06-10 21:09 UTC (permalink / raw)
To: op-tee
[-- Attachment #1: Type: text/plain, Size: 4128 bytes --]
The shm cache could contain invalid addresses if
optee_disable_shm_cache() was not called from the .shutdown hook of the
previous kernel before a kexec. These addresses could be unmapped or
they could point to mapped but unintended locations in memory.
Clear the shared memory cache, while being careful to not translate the
addresses returned from OPTEE_SMC_DISABLE_SHM_CACHE, during driver
initialization. Once all pre-cache shm objects are removed, proceed with
enabling the cache so that we know that we can handle cached shm objects
with confidence later in the .shutdown hook.
Signed-off-by: Tyler Hicks <tyhicks@linux.microsoft.com>
---
drivers/tee/optee/call.c | 11 ++++++++++-
drivers/tee/optee/core.c | 13 +++++++++++--
drivers/tee/optee/optee_private.h | 2 +-
3 files changed, 22 insertions(+), 4 deletions(-)
diff --git a/drivers/tee/optee/call.c b/drivers/tee/optee/call.c
index 6e6eb836e9b6..5dcba6105ed7 100644
--- a/drivers/tee/optee/call.c
+++ b/drivers/tee/optee/call.c
@@ -419,8 +419,10 @@ void optee_enable_shm_cache(struct optee *optee)
* optee_disable_shm_cache() - Disables caching of some shared memory allocation
* in OP-TEE
* @optee: main service struct
+ * @is_mapped: true if the cached shared memory addresses were mapped by this
+ * kernel, are safe to dereference, and should be freed
*/
-void optee_disable_shm_cache(struct optee *optee)
+void optee_disable_shm_cache(struct optee *optee, bool is_mapped)
{
struct optee_call_waiter w;
@@ -439,6 +441,13 @@ void optee_disable_shm_cache(struct optee *optee)
if (res.result.status == OPTEE_SMC_RETURN_OK) {
struct tee_shm *shm;
+ /*
+ * Shared memory references that were not mapped by
+ * this kernel must be ignored to prevent a crash.
+ */
+ if (!is_mapped)
+ continue;
+
shm = reg_pair_to_ptr(res.result.shm_upper32,
res.result.shm_lower32);
tee_shm_free(shm);
diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
index 0987074d7ed0..6974e1104bd4 100644
--- a/drivers/tee/optee/core.c
+++ b/drivers/tee/optee/core.c
@@ -589,7 +589,7 @@ static int optee_remove(struct platform_device *pdev)
* reference counters and also avoid wild pointers in secure world
* into the old shared memory range.
*/
- optee_disable_shm_cache(optee);
+ optee_disable_shm_cache(optee, true);
/*
* The two devices have to be unregistered before we can free the
@@ -619,7 +619,7 @@ static int optee_remove(struct platform_device *pdev)
*/
static void optee_shutdown(struct platform_device *pdev)
{
- optee_disable_shm_cache(platform_get_drvdata(pdev));
+ optee_disable_shm_cache(platform_get_drvdata(pdev), true);
}
static int optee_probe(struct platform_device *pdev)
@@ -716,6 +716,15 @@ static int optee_probe(struct platform_device *pdev)
optee->memremaped_shm = memremaped_shm;
optee->pool = pool;
+ /*
+ * Ensure that there are no pre-existing shm objects before enabling
+ * the shm cache so that there's no chance of receiving an invalid
+ * address during shutdown. This could occur, for example, if we're
+ * kexec booting from an older kernel that did not properly cleanup the
+ * shm cache.
+ */
+ optee_disable_shm_cache(optee, false);
+
optee_enable_shm_cache(optee);
if (optee->sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM)
diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h
index e25b216a14ef..16d8c82213e7 100644
--- a/drivers/tee/optee/optee_private.h
+++ b/drivers/tee/optee/optee_private.h
@@ -158,7 +158,7 @@ int optee_invoke_func(struct tee_context *ctx, struct tee_ioctl_invoke_arg *arg,
int optee_cancel_req(struct tee_context *ctx, u32 cancel_id, u32 session);
void optee_enable_shm_cache(struct optee *optee);
-void optee_disable_shm_cache(struct optee *optee);
+void optee_disable_shm_cache(struct optee *optee, bool is_mapped);
int optee_shm_register(struct tee_context *ctx, struct tee_shm *shm,
struct page **pages, size_t num_pages,
--
2.25.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v4 5/8] tee: add tee_shm_alloc_kernel_buf()
2021-06-10 21:09 [PATCH v4 0/8] tee: Improve support for kexec and kdump Tyler Hicks
` (3 preceding siblings ...)
2021-06-10 21:09 ` [PATCH v4 4/8] optee: Clear stale cache entries during initialization Tyler Hicks
@ 2021-06-10 21:09 ` Tyler Hicks
2021-06-10 21:09 ` [PATCH v4 6/8] tee: Support kernel shm registration without dma-buf backing Tyler Hicks
` (2 subsequent siblings)
7 siblings, 0 replies; 18+ messages in thread
From: Tyler Hicks @ 2021-06-10 21:09 UTC (permalink / raw)
To: op-tee
[-- Attachment #1: Type: text/plain, Size: 2104 bytes --]
From: Jens Wiklander <jens.wiklander@linaro.org>
Adds a new function tee_shm_alloc_kernel_buf() to allocate shared memory
from a kernel driver. This function can later be made more lightweight
by unnecessary dma-buf export.
Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
Reviewed-by: Tyler Hicks <tyhicks@linux.microsoft.com>
---
drivers/tee/tee_shm.c | 18 ++++++++++++++++++
include/linux/tee_drv.h | 1 +
2 files changed, 19 insertions(+)
diff --git a/drivers/tee/tee_shm.c b/drivers/tee/tee_shm.c
index 00472f5ce22e..c65e44707cd6 100644
--- a/drivers/tee/tee_shm.c
+++ b/drivers/tee/tee_shm.c
@@ -193,6 +193,24 @@ struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags)
}
EXPORT_SYMBOL_GPL(tee_shm_alloc);
+/**
+ * tee_shm_alloc_kernel_buf() - Allocate shared memory for kernel buffer
+ * @ctx: Context that allocates the shared memory
+ * @size: Requested size of shared memory
+ *
+ * The returned memory registered in secure world and is suitable to be
+ * passed as a memory buffer in parameter argument to
+ * tee_client_invoke_func(). The memory allocated is later freed with a
+ * call to tee_shm_free().
+ *
+ * @returns a pointer to 'struct tee_shm'
+ */
+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);
+}
+EXPORT_SYMBOL_GPL(tee_shm_alloc_kernel_buf);
+
struct tee_shm *tee_shm_register(struct tee_context *ctx, unsigned long addr,
size_t length, u32 flags)
{
diff --git a/include/linux/tee_drv.h b/include/linux/tee_drv.h
index 54269e47ac9a..8990f7628387 100644
--- a/include/linux/tee_drv.h
+++ b/include/linux/tee_drv.h
@@ -332,6 +332,7 @@ void *tee_get_drvdata(struct tee_device *teedev);
* @returns a pointer to 'struct tee_shm'
*/
struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags);
+struct tee_shm *tee_shm_alloc_kernel_buf(struct tee_context *ctx, size_t size);
/**
* tee_shm_register() - Register shared memory buffer
--
2.25.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v4 6/8] tee: Support kernel shm registration without dma-buf backing
2021-06-10 21:09 [PATCH v4 0/8] tee: Improve support for kexec and kdump Tyler Hicks
` (4 preceding siblings ...)
2021-06-10 21:09 ` [PATCH v4 5/8] tee: add tee_shm_alloc_kernel_buf() Tyler Hicks
@ 2021-06-10 21:09 ` Tyler Hicks
2021-06-11 5:16 ` Sumit Garg
2021-06-10 21:09 ` [PATCH v4 7/8] tpm_ftpm_tee: Free and unregister TEE shared memory during kexec Tyler Hicks
2021-06-10 21:09 ` [PATCH v4 8/8] firmware: tee_bnxt: Release TEE shm, session, and context " Tyler Hicks
7 siblings, 1 reply; 18+ messages in thread
From: Tyler Hicks @ 2021-06-10 21:09 UTC (permalink / raw)
To: op-tee
[-- Attachment #1: Type: text/plain, Size: 3481 bytes --]
Uncouple the registration of kernel shared memory buffers from the
TEE_SHM_DMA_BUF flag. Drivers may wish to allocate multi-page contiguous
shared memory regions but do not need them to be backed by a dma-buf
when the memory region is only used by the driver.
If the TEE implementation does not require shared memory to be
registered, clear the flag prior to calling the corresponding pool alloc
function. Update the OP-TEE driver to respect TEE_SHM_REGISTER, rather
than TEE_SHM_DMA_BUF, when deciding whether to (un)register on
alloc/free operations. The AMD-TEE driver continues to ignore the
TEE_SHM_REGISTER flag.
Allow callers of tee_shm_alloc_kernel_buf() to allocate and register a
shared memory region without the backing of dma-buf.
Signed-off-by: Tyler Hicks <tyhicks@linux.microsoft.com>
---
drivers/tee/optee/shm_pool.c | 5 ++---
drivers/tee/tee_shm.c | 13 +++++++++++--
2 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/drivers/tee/optee/shm_pool.c b/drivers/tee/optee/shm_pool.c
index da06ce9b9313..6054343a29fb 100644
--- a/drivers/tee/optee/shm_pool.c
+++ b/drivers/tee/optee/shm_pool.c
@@ -27,7 +27,7 @@ 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) {
+ if (shm->flags & TEE_SHM_REGISTER) {
unsigned int nr_pages = 1 << order, i;
struct page **pages;
@@ -42,7 +42,6 @@ static int pool_op_alloc(struct tee_shm_pool_mgr *poolm,
page++;
}
- shm->flags |= TEE_SHM_REGISTER;
rc = optee_shm_register(shm->ctx, shm, pages, nr_pages,
(unsigned long)shm->kaddr);
kfree(pages);
@@ -60,7 +59,7 @@ static int pool_op_alloc(struct tee_shm_pool_mgr *poolm,
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_REGISTER)
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..26a76f817c57 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_REGISTER))) {
dev_err(teedev->dev.parent, "invalid shm flags 0x%x", flags);
return ERR_PTR(-EINVAL);
}
@@ -137,6 +137,15 @@ struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags)
goto err_dev_put;
}
+ if (!teedev->desc->ops->shm_register ||
+ !teedev->desc->ops->shm_unregister) {
+ /* registration is not required by the TEE implementation */
+ flags &= ~TEE_SHM_REGISTER;
+ } else if (flags & TEE_SHM_DMA_BUF) {
+ /* all dma-buf backed shm allocations are registered */
+ flags |= TEE_SHM_REGISTER;
+ }
+
shm->flags = flags | TEE_SHM_POOL;
shm->ctx = ctx;
if (flags & TEE_SHM_DMA_BUF)
@@ -207,7 +216,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 | TEE_SHM_REGISTER);
}
EXPORT_SYMBOL_GPL(tee_shm_alloc_kernel_buf);
--
2.25.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v4 7/8] tpm_ftpm_tee: Free and unregister TEE shared memory during kexec
2021-06-10 21:09 [PATCH v4 0/8] tee: Improve support for kexec and kdump Tyler Hicks
` (5 preceding siblings ...)
2021-06-10 21:09 ` [PATCH v4 6/8] tee: Support kernel shm registration without dma-buf backing Tyler Hicks
@ 2021-06-10 21:09 ` Tyler Hicks
2021-06-15 13:04 ` Jarkko Sakkinen
2021-06-10 21:09 ` [PATCH v4 8/8] firmware: tee_bnxt: Release TEE shm, session, and context " Tyler Hicks
7 siblings, 1 reply; 18+ messages in thread
From: Tyler Hicks @ 2021-06-10 21:09 UTC (permalink / raw)
To: op-tee
[-- Attachment #1: Type: text/plain, Size: 1901 bytes --]
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: 09e574831b27 ("tpm/tpm_ftpm_tee: A driver for firmware TPM running inside TEE")
Fixes: 1760eb689ed6 ("tpm/tpm_ftpm_tee: add shutdown call back")
Signed-off-by: Tyler Hicks <tyhicks@linux.microsoft.com>
---
drivers/char/tpm/tpm_ftpm_tee.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/char/tpm/tpm_ftpm_tee.c b/drivers/char/tpm/tpm_ftpm_tee.c
index 2ccdf8ac6994..6e3235565a4d 100644
--- a/drivers/char/tpm/tpm_ftpm_tee.c
+++ b/drivers/char/tpm/tpm_ftpm_tee.c
@@ -254,11 +254,11 @@ static int ftpm_tee_probe(struct device *dev)
pvt_data->session = sess_arg.session;
/* Allocate dynamic shared memory with fTPM TA */
- pvt_data->shm = tee_shm_alloc(pvt_data->ctx,
- MAX_COMMAND_SIZE + MAX_RESPONSE_SIZE,
- TEE_SHM_MAPPED | TEE_SHM_DMA_BUF);
+ pvt_data->shm = tee_shm_alloc_kernel_buf(pvt_data->ctx,
+ MAX_COMMAND_SIZE +
+ MAX_RESPONSE_SIZE);
if (IS_ERR(pvt_data->shm)) {
- dev_err(dev, "%s: tee_shm_alloc failed\n", __func__);
+ dev_err(dev, "%s: tee_shm_alloc_kernel_buf failed\n", __func__);
rc = -ENOMEM;
goto out_shm_alloc;
}
--
2.25.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v4 8/8] firmware: tee_bnxt: Release TEE shm, session, and context during kexec
2021-06-10 21:09 [PATCH v4 0/8] tee: Improve support for kexec and kdump Tyler Hicks
` (6 preceding siblings ...)
2021-06-10 21:09 ` [PATCH v4 7/8] tpm_ftpm_tee: Free and unregister TEE shared memory during kexec Tyler Hicks
@ 2021-06-10 21:09 ` Tyler Hicks
7 siblings, 0 replies; 18+ messages in thread
From: Tyler Hicks @ 2021-06-10 21:09 UTC (permalink / raw)
To: op-tee
[-- Attachment #1: Type: text/plain, Size: 2872 bytes --]
From: Allen Pais <apais@linux.microsoft.com>
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")
Signed-off-by: Allen Pais <apais@linux.microsoft.com>
Co-developed-by: Tyler Hicks <tyhicks@linux.microsoft.com>
Signed-off-by: Tyler Hicks <tyhicks@linux.microsoft.com>
---
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.25.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH v4 6/8] tee: Support kernel shm registration without dma-buf backing
2021-06-10 21:09 ` [PATCH v4 6/8] tee: Support kernel shm registration without dma-buf backing Tyler Hicks
@ 2021-06-11 5:16 ` Sumit Garg
0 siblings, 0 replies; 18+ messages in thread
From: Sumit Garg @ 2021-06-11 5:16 UTC (permalink / raw)
To: op-tee
[-- Attachment #1: Type: text/plain, Size: 5307 bytes --]
On Fri, 11 Jun 2021 at 02:39, Tyler Hicks <tyhicks@linux.microsoft.com> wrote:
>
> Uncouple the registration of kernel shared memory buffers from the
> TEE_SHM_DMA_BUF flag. Drivers may wish to allocate multi-page contiguous
> shared memory regions but do not need them to be backed by a dma-buf
> when the memory region is only used by the driver.
>
> If the TEE implementation does not require shared memory to be
> registered, clear the flag prior to calling the corresponding pool alloc
> function. Update the OP-TEE driver to respect TEE_SHM_REGISTER, rather
> than TEE_SHM_DMA_BUF, when deciding whether to (un)register on
> alloc/free operations.
> The AMD-TEE driver continues to ignore the
> TEE_SHM_REGISTER flag.
>
That's the main point that no other TEE implementation would honour
TEE_SHM_REGISTER and I think it's just the incorrect usage of
TEE_SHM_REGISTER flag to suffice OP-TEE underlying implementation.
> Allow callers of tee_shm_alloc_kernel_buf() to allocate and register a
> shared memory region without the backing of dma-buf.
>
> Signed-off-by: Tyler Hicks <tyhicks@linux.microsoft.com>
> ---
> drivers/tee/optee/shm_pool.c | 5 ++---
> drivers/tee/tee_shm.c | 13 +++++++++++--
> 2 files changed, 13 insertions(+), 5 deletions(-)
>
This patch is just mixing two separate approaches to TEE shared
memory. Have a look at alternative suggestions below.
> diff --git a/drivers/tee/optee/shm_pool.c b/drivers/tee/optee/shm_pool.c
> index da06ce9b9313..6054343a29fb 100644
> --- a/drivers/tee/optee/shm_pool.c
> +++ b/drivers/tee/optee/shm_pool.c
> @@ -27,7 +27,7 @@ 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) {
> + if (shm->flags & TEE_SHM_REGISTER) {
Here you can just do following check instead:
if (!(shm->flags & TEE_SHM_PRIV)) {
And this flag needs to be passed from the call sites here [1] [2].
[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/tee/optee/core.c#n280
[2] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/tee/optee/call.c#n186
> unsigned int nr_pages = 1 << order, i;
> struct page **pages;
>
> @@ -42,7 +42,6 @@ static int pool_op_alloc(struct tee_shm_pool_mgr *poolm,
> page++;
> }
>
> - shm->flags |= TEE_SHM_REGISTER;
This should remain as it is.
> rc = optee_shm_register(shm->ctx, shm, pages, nr_pages,
> (unsigned long)shm->kaddr);
> kfree(pages);
> @@ -60,7 +59,7 @@ static int pool_op_alloc(struct tee_shm_pool_mgr *poolm,
> 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_REGISTER)
Same as above.
> 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..26a76f817c57 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_REGISTER))) {
No need for this change.
> dev_err(teedev->dev.parent, "invalid shm flags 0x%x", flags);
> return ERR_PTR(-EINVAL);
> }
> @@ -137,6 +137,15 @@ struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags)
> goto err_dev_put;
> }
>
> + if (!teedev->desc->ops->shm_register ||
> + !teedev->desc->ops->shm_unregister) {
> + /* registration is not required by the TEE implementation */
> + flags &= ~TEE_SHM_REGISTER;
> + } else if (flags & TEE_SHM_DMA_BUF) {
> + /* all dma-buf backed shm allocations are registered */
> + flags |= TEE_SHM_REGISTER;
> + }
> +
This change isn't required as well as underlying TEE implementation:
OP-TEE in this case knows how to implement shared memory allocation
whether to use reserved shared memory pool or dynamic shared memory
pool. For more details see shared memory pool creation in
optee_probe().
> shm->flags = flags | TEE_SHM_POOL;
> shm->ctx = ctx;
> if (flags & TEE_SHM_DMA_BUF)
> @@ -207,7 +216,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 | TEE_SHM_REGISTER);
Here it could just be:
return tee_shm_alloc(ctx, size, TEE_SHM_MAPPED);
-Sumit
> }
> EXPORT_SYMBOL_GPL(tee_shm_alloc_kernel_buf);
>
> --
> 2.25.1
>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v4 1/8] optee: Fix memory leak when failing to register shm pages
2021-06-10 21:09 ` [PATCH v4 1/8] optee: Fix memory leak when failing to register shm pages Tyler Hicks
@ 2021-06-11 9:05 ` Jens Wiklander
0 siblings, 0 replies; 18+ messages in thread
From: Jens Wiklander @ 2021-06-11 9:05 UTC (permalink / raw)
To: op-tee
[-- Attachment #1: Type: text/plain, Size: 604 bytes --]
On Thu, Jun 10, 2021 at 11:09 PM Tyler Hicks
<tyhicks@linux.microsoft.com> wrote:
>
> Free the previously allocated pages when we encounter an error condition
> while attempting to register the pages with the secure world.
>
> Fixes: a249dd200d03 ("tee: optee: Fix dynamic shm pool allocations")
> Fixes: 5a769f6ff439 ("optee: Fix multi page dynamic shm pool alloc")
> Signed-off-by: Tyler Hicks <tyhicks@linux.microsoft.com>
> ---
> drivers/tee/optee/shm_pool.c | 12 ++++++++++--
> 1 file changed, 10 insertions(+), 2 deletions(-)
Looks good.
Reviewed-by: Jens Wiklander <jens.wiklander@linaro.org>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v4 2/8] optee: Refuse to load the driver under the kdump kernel
2021-06-10 21:09 ` [PATCH v4 2/8] optee: Refuse to load the driver under the kdump kernel Tyler Hicks
@ 2021-06-11 9:08 ` Jens Wiklander
0 siblings, 0 replies; 18+ messages in thread
From: Jens Wiklander @ 2021-06-11 9:08 UTC (permalink / raw)
To: op-tee
[-- Attachment #1: Type: text/plain, Size: 1838 bytes --]
On Thu, Jun 10, 2021 at 11:09 PM Tyler Hicks
<tyhicks@linux.microsoft.com> wrote:
>
> Fix a hung task issue, seen when booting the kdump kernel, that is
> caused by all of the secure world threads being in a permanent suspended
> state:
>
> INFO: task swapper/0:1 blocked for more than 120 seconds.
> Not tainted 5.4.83 #1
> "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
> swapper/0 D 0 1 0 0x00000028
> Call trace:
> __switch_to+0xc8/0x118
> __schedule+0x2e0/0x700
> schedule+0x38/0xb8
> schedule_timeout+0x258/0x388
> wait_for_completion+0x16c/0x4b8
> optee_cq_wait_for_completion+0x28/0xa8
> optee_disable_shm_cache+0xb8/0xf8
> optee_probe+0x560/0x61c
> platform_drv_probe+0x58/0xa8
> really_probe+0xe0/0x338
> driver_probe_device+0x5c/0xf0
> device_driver_attach+0x74/0x80
> __driver_attach+0x64/0xe0
> bus_for_each_dev+0x84/0xd8
> driver_attach+0x30/0x40
> bus_add_driver+0x188/0x1e8
> driver_register+0x64/0x110
> __platform_driver_register+0x54/0x60
> optee_driver_init+0x20/0x28
> do_one_initcall+0x54/0x24c
> kernel_init_freeable+0x1e8/0x2c0
> kernel_init+0x18/0x118
> ret_from_fork+0x10/0x18
>
> The invoke_fn hook returned OPTEE_SMC_RETURN_ETHREAD_LIMIT, indicating
> that the secure world threads were all in a suspended state at the time
> of the kernel crash. This intermittently prevented the kdump kernel from
> booting, resulting in a failure to collect the kernel dump.
>
> Make kernel dump collection more reliable on systems utilizing OP-TEE by
> refusing to load the driver under the kdump kernel.
>
> Signed-off-by: Tyler Hicks <tyhicks@linux.microsoft.com>
> ---
> drivers/tee/optee/core.c | 11 +++++++++++
> 1 file changed, 11 insertions(+)
Looks good
Reviewed-by: Jens Wiklander <jens.wiklander@linaro.org>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v4 3/8] optee: fix tee out of memory failure seen during kexec reboot
2021-06-10 21:09 ` [PATCH v4 3/8] optee: fix tee out of memory failure seen during kexec reboot Tyler Hicks
@ 2021-06-11 9:11 ` Jens Wiklander
2021-06-14 7:22 ` Jens Wiklander
1 sibling, 0 replies; 18+ messages in thread
From: Jens Wiklander @ 2021-06-11 9:11 UTC (permalink / raw)
To: op-tee
[-- Attachment #1: Type: text/plain, Size: 785 bytes --]
On Thu, Jun 10, 2021 at 11:09 PM Tyler Hicks
<tyhicks@linux.microsoft.com> wrote:
>
> From: Allen Pais <apais@linux.microsoft.com>
>
> The following out of memory errors are seen on kexec reboot
> from the optee core.
>
> [ 0.368428] tee_bnxt_fw optee-clnt0: tee_shm_alloc failed
> [ 0.368461] tee_bnxt_fw: probe of optee-clnt0 failed with error -22
>
> tee_shm_release() is not invoked on dma shm buffer.
>
> Implement .shutdown() method to handle the release of the buffers
> correctly.
>
> More info:
> https://github.com/OP-TEE/optee_os/issues/3637
>
> Signed-off-by: Allen Pais <apais@linux.microsoft.com>
> Reviewed-by: Tyler Hicks <tyhicks@linux.microsoft.com>
Do we really need this considering the patch "optee: Refuse to load
the driver under the kdump kernel"?
Jens
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v4 3/8] optee: fix tee out of memory failure seen during kexec reboot
2021-06-10 21:09 ` [PATCH v4 3/8] optee: fix tee out of memory failure seen during kexec reboot Tyler Hicks
2021-06-11 9:11 ` Jens Wiklander
@ 2021-06-14 7:22 ` Jens Wiklander
1 sibling, 0 replies; 18+ messages in thread
From: Jens Wiklander @ 2021-06-14 7:22 UTC (permalink / raw)
To: op-tee
[-- Attachment #1: Type: text/plain, Size: 810 bytes --]
On Thu, Jun 10, 2021 at 04:09:08PM -0500, Tyler Hicks wrote:
> From: Allen Pais <apais@linux.microsoft.com>
>
> The following out of memory errors are seen on kexec reboot
> from the optee core.
>
> [ 0.368428] tee_bnxt_fw optee-clnt0: tee_shm_alloc failed
> [ 0.368461] tee_bnxt_fw: probe of optee-clnt0 failed with error -22
>
> tee_shm_release() is not invoked on dma shm buffer.
>
> Implement .shutdown() method to handle the release of the buffers
> correctly.
>
> More info:
> https://github.com/OP-TEE/optee_os/issues/3637
>
> Signed-off-by: Allen Pais <apais@linux.microsoft.com>
> Reviewed-by: Tyler Hicks <tyhicks@linux.microsoft.com>
> ---
> drivers/tee/optee/core.c | 20 ++++++++++++++++++++
> 1 file changed, 20 insertions(+)
Reviewed-by: Jens Wiklander <jens.wiklander@linaro.org>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v4 4/8] optee: Clear stale cache entries during initialization
2021-06-10 21:09 ` [PATCH v4 4/8] optee: Clear stale cache entries during initialization Tyler Hicks
@ 2021-06-14 8:27 ` Jens Wiklander
2021-06-14 19:06 ` Tyler Hicks
0 siblings, 1 reply; 18+ messages in thread
From: Jens Wiklander @ 2021-06-14 8:27 UTC (permalink / raw)
To: op-tee
[-- Attachment #1: Type: text/plain, Size: 4696 bytes --]
On Thu, Jun 10, 2021 at 04:09:09PM -0500, Tyler Hicks wrote:
> The shm cache could contain invalid addresses if
> optee_disable_shm_cache() was not called from the .shutdown hook of the
> previous kernel before a kexec. These addresses could be unmapped or
> they could point to mapped but unintended locations in memory.
>
> Clear the shared memory cache, while being careful to not translate the
> addresses returned from OPTEE_SMC_DISABLE_SHM_CACHE, during driver
> initialization. Once all pre-cache shm objects are removed, proceed with
> enabling the cache so that we know that we can handle cached shm objects
> with confidence later in the .shutdown hook.
>
> Signed-off-by: Tyler Hicks <tyhicks@linux.microsoft.com>
> ---
> drivers/tee/optee/call.c | 11 ++++++++++-
> drivers/tee/optee/core.c | 13 +++++++++++--
> drivers/tee/optee/optee_private.h | 2 +-
> 3 files changed, 22 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/tee/optee/call.c b/drivers/tee/optee/call.c
> index 6e6eb836e9b6..5dcba6105ed7 100644
> --- a/drivers/tee/optee/call.c
> +++ b/drivers/tee/optee/call.c
> @@ -419,8 +419,10 @@ void optee_enable_shm_cache(struct optee *optee)
> * optee_disable_shm_cache() - Disables caching of some shared memory allocation
> * in OP-TEE
> * @optee: main service struct
> + * @is_mapped: true if the cached shared memory addresses were mapped by this
> + * kernel, are safe to dereference, and should be freed
> */
> -void optee_disable_shm_cache(struct optee *optee)
> +void optee_disable_shm_cache(struct optee *optee, bool is_mapped)
> {
> struct optee_call_waiter w;
>
> @@ -439,6 +441,13 @@ void optee_disable_shm_cache(struct optee *optee)
> if (res.result.status == OPTEE_SMC_RETURN_OK) {
> struct tee_shm *shm;
>
> + /*
> + * Shared memory references that were not mapped by
> + * this kernel must be ignored to prevent a crash.
> + */
> + if (!is_mapped)
> + continue;
> +
> shm = reg_pair_to_ptr(res.result.shm_upper32,
> res.result.shm_lower32);
> tee_shm_free(shm);
> diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
> index 0987074d7ed0..6974e1104bd4 100644
> --- a/drivers/tee/optee/core.c
> +++ b/drivers/tee/optee/core.c
> @@ -589,7 +589,7 @@ static int optee_remove(struct platform_device *pdev)
> * reference counters and also avoid wild pointers in secure world
> * into the old shared memory range.
> */
> - optee_disable_shm_cache(optee);
> + optee_disable_shm_cache(optee, true);
Naked "true" or "false" parameters are normally not very descriptive.
Would it make sense to write this as:
optee_disable_shm_cache(optee, true /*is_mapped*/);
instead (same for the other call sites in this patch)? That way it would
be easier to see what it is that is true or false.
/Jens
>
> /*
> * The two devices have to be unregistered before we can free the
> @@ -619,7 +619,7 @@ static int optee_remove(struct platform_device *pdev)
> */
> static void optee_shutdown(struct platform_device *pdev)
> {
> - optee_disable_shm_cache(platform_get_drvdata(pdev));
> + optee_disable_shm_cache(platform_get_drvdata(pdev), true);
> }
>
> static int optee_probe(struct platform_device *pdev)
> @@ -716,6 +716,15 @@ static int optee_probe(struct platform_device *pdev)
> optee->memremaped_shm = memremaped_shm;
> optee->pool = pool;
>
> + /*
> + * Ensure that there are no pre-existing shm objects before enabling
> + * the shm cache so that there's no chance of receiving an invalid
> + * address during shutdown. This could occur, for example, if we're
> + * kexec booting from an older kernel that did not properly cleanup the
> + * shm cache.
> + */
> + optee_disable_shm_cache(optee, false);
> +
> optee_enable_shm_cache(optee);
>
> if (optee->sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM)
> diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h
> index e25b216a14ef..16d8c82213e7 100644
> --- a/drivers/tee/optee/optee_private.h
> +++ b/drivers/tee/optee/optee_private.h
> @@ -158,7 +158,7 @@ int optee_invoke_func(struct tee_context *ctx, struct tee_ioctl_invoke_arg *arg,
> int optee_cancel_req(struct tee_context *ctx, u32 cancel_id, u32 session);
>
> void optee_enable_shm_cache(struct optee *optee);
> -void optee_disable_shm_cache(struct optee *optee);
> +void optee_disable_shm_cache(struct optee *optee, bool is_mapped);
>
> int optee_shm_register(struct tee_context *ctx, struct tee_shm *shm,
> struct page **pages, size_t num_pages,
> --
> 2.25.1
>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v4 4/8] optee: Clear stale cache entries during initialization
2021-06-14 8:27 ` Jens Wiklander
@ 2021-06-14 19:06 ` Tyler Hicks
2021-06-14 19:15 ` Jens Wiklander
0 siblings, 1 reply; 18+ messages in thread
From: Tyler Hicks @ 2021-06-14 19:06 UTC (permalink / raw)
To: op-tee
[-- Attachment #1: Type: text/plain, Size: 6043 bytes --]
On 2021-06-14 10:27:15, Jens Wiklander wrote:
> On Thu, Jun 10, 2021 at 04:09:09PM -0500, Tyler Hicks wrote:
> > The shm cache could contain invalid addresses if
> > optee_disable_shm_cache() was not called from the .shutdown hook of the
> > previous kernel before a kexec. These addresses could be unmapped or
> > they could point to mapped but unintended locations in memory.
> >
> > Clear the shared memory cache, while being careful to not translate the
> > addresses returned from OPTEE_SMC_DISABLE_SHM_CACHE, during driver
> > initialization. Once all pre-cache shm objects are removed, proceed with
> > enabling the cache so that we know that we can handle cached shm objects
> > with confidence later in the .shutdown hook.
> >
> > Signed-off-by: Tyler Hicks <tyhicks@linux.microsoft.com>
> > ---
> > drivers/tee/optee/call.c | 11 ++++++++++-
> > drivers/tee/optee/core.c | 13 +++++++++++--
> > drivers/tee/optee/optee_private.h | 2 +-
> > 3 files changed, 22 insertions(+), 4 deletions(-)
> >
> > diff --git a/drivers/tee/optee/call.c b/drivers/tee/optee/call.c
> > index 6e6eb836e9b6..5dcba6105ed7 100644
> > --- a/drivers/tee/optee/call.c
> > +++ b/drivers/tee/optee/call.c
> > @@ -419,8 +419,10 @@ void optee_enable_shm_cache(struct optee *optee)
> > * optee_disable_shm_cache() - Disables caching of some shared memory allocation
> > * in OP-TEE
> > * @optee: main service struct
> > + * @is_mapped: true if the cached shared memory addresses were mapped by this
> > + * kernel, are safe to dereference, and should be freed
> > */
> > -void optee_disable_shm_cache(struct optee *optee)
> > +void optee_disable_shm_cache(struct optee *optee, bool is_mapped)
> > {
> > struct optee_call_waiter w;
> >
> > @@ -439,6 +441,13 @@ void optee_disable_shm_cache(struct optee *optee)
> > if (res.result.status == OPTEE_SMC_RETURN_OK) {
> > struct tee_shm *shm;
> >
> > + /*
> > + * Shared memory references that were not mapped by
> > + * this kernel must be ignored to prevent a crash.
> > + */
> > + if (!is_mapped)
> > + continue;
> > +
> > shm = reg_pair_to_ptr(res.result.shm_upper32,
> > res.result.shm_lower32);
> > tee_shm_free(shm);
> > diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
> > index 0987074d7ed0..6974e1104bd4 100644
> > --- a/drivers/tee/optee/core.c
> > +++ b/drivers/tee/optee/core.c
> > @@ -589,7 +589,7 @@ static int optee_remove(struct platform_device *pdev)
> > * reference counters and also avoid wild pointers in secure world
> > * into the old shared memory range.
> > */
> > - optee_disable_shm_cache(optee);
> > + optee_disable_shm_cache(optee, true);
>
> Naked "true" or "false" parameters are normally not very descriptive.
> Would it make sense to write this as:
> optee_disable_shm_cache(optee, true /*is_mapped*/);
> instead (same for the other call sites in this patch)? That way it would
> be easier to see what it is that is true or false.
Yeah, I understand the issue with the naked bools. What about turning
'optee_disable_shm_cache(struct optee *optee, bool is_mapped)' into
'__optee_disable_shm_cache(struct optee *optee, bool is_mapped)' and
introducing these two wrappers:
/**
* optee_disable_shm_cache() - Disables caching of mapped shared memory
* allocations in OP-TEE
* @optee: main service struct
*/
void optee_disable_shm_cache(struct optee *optee)
{
return __optee_disable_shm_cache(optee, true);
}
/**
* optee_disable_unmapped_shm_cache() - Disables caching of shared memory
* allocations in OP-TEE which are not
* currently mapped
* @optee: main service struct
*/
void optee_disable_unmapped_shm_cache(struct optee *optee)
{
return __optee_disable_shm_cache(optee, false);
}
Existing callers of optee_disable_shm_cache() remain unchanged and we just add
one caller of optee_disable_unmapped_shm_cache() with this patch.
Tyler
>
> /Jens
>
> >
> > /*
> > * The two devices have to be unregistered before we can free the
> > @@ -619,7 +619,7 @@ static int optee_remove(struct platform_device *pdev)
> > */
> > static void optee_shutdown(struct platform_device *pdev)
> > {
> > - optee_disable_shm_cache(platform_get_drvdata(pdev));
> > + optee_disable_shm_cache(platform_get_drvdata(pdev), true);
> > }
> >
> > static int optee_probe(struct platform_device *pdev)
> > @@ -716,6 +716,15 @@ static int optee_probe(struct platform_device *pdev)
> > optee->memremaped_shm = memremaped_shm;
> > optee->pool = pool;
> >
> > + /*
> > + * Ensure that there are no pre-existing shm objects before enabling
> > + * the shm cache so that there's no chance of receiving an invalid
> > + * address during shutdown. This could occur, for example, if we're
> > + * kexec booting from an older kernel that did not properly cleanup the
> > + * shm cache.
> > + */
> > + optee_disable_shm_cache(optee, false);
> > +
> > optee_enable_shm_cache(optee);
> >
> > if (optee->sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM)
> > diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h
> > index e25b216a14ef..16d8c82213e7 100644
> > --- a/drivers/tee/optee/optee_private.h
> > +++ b/drivers/tee/optee/optee_private.h
> > @@ -158,7 +158,7 @@ int optee_invoke_func(struct tee_context *ctx, struct tee_ioctl_invoke_arg *arg,
> > int optee_cancel_req(struct tee_context *ctx, u32 cancel_id, u32 session);
> >
> > void optee_enable_shm_cache(struct optee *optee);
> > -void optee_disable_shm_cache(struct optee *optee);
> > +void optee_disable_shm_cache(struct optee *optee, bool is_mapped);
> >
> > int optee_shm_register(struct tee_context *ctx, struct tee_shm *shm,
> > struct page **pages, size_t num_pages,
> > --
> > 2.25.1
> >
>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v4 4/8] optee: Clear stale cache entries during initialization
2021-06-14 19:06 ` Tyler Hicks
@ 2021-06-14 19:15 ` Jens Wiklander
0 siblings, 0 replies; 18+ messages in thread
From: Jens Wiklander @ 2021-06-14 19:15 UTC (permalink / raw)
To: op-tee
[-- Attachment #1: Type: text/plain, Size: 4411 bytes --]
On Mon, Jun 14, 2021 at 02:06:46PM -0500, Tyler Hicks wrote:
> On 2021-06-14 10:27:15, Jens Wiklander wrote:
> > On Thu, Jun 10, 2021 at 04:09:09PM -0500, Tyler Hicks wrote:
> > > The shm cache could contain invalid addresses if
> > > optee_disable_shm_cache() was not called from the .shutdown hook of the
> > > previous kernel before a kexec. These addresses could be unmapped or
> > > they could point to mapped but unintended locations in memory.
> > >
> > > Clear the shared memory cache, while being careful to not translate the
> > > addresses returned from OPTEE_SMC_DISABLE_SHM_CACHE, during driver
> > > initialization. Once all pre-cache shm objects are removed, proceed with
> > > enabling the cache so that we know that we can handle cached shm objects
> > > with confidence later in the .shutdown hook.
> > >
> > > Signed-off-by: Tyler Hicks <tyhicks@linux.microsoft.com>
> > > ---
> > > drivers/tee/optee/call.c | 11 ++++++++++-
> > > drivers/tee/optee/core.c | 13 +++++++++++--
> > > drivers/tee/optee/optee_private.h | 2 +-
> > > 3 files changed, 22 insertions(+), 4 deletions(-)
> > >
> > > diff --git a/drivers/tee/optee/call.c b/drivers/tee/optee/call.c
> > > index 6e6eb836e9b6..5dcba6105ed7 100644
> > > --- a/drivers/tee/optee/call.c
> > > +++ b/drivers/tee/optee/call.c
> > > @@ -419,8 +419,10 @@ void optee_enable_shm_cache(struct optee *optee)
> > > * optee_disable_shm_cache() - Disables caching of some shared memory allocation
> > > * in OP-TEE
> > > * @optee: main service struct
> > > + * @is_mapped: true if the cached shared memory addresses were mapped by this
> > > + * kernel, are safe to dereference, and should be freed
> > > */
> > > -void optee_disable_shm_cache(struct optee *optee)
> > > +void optee_disable_shm_cache(struct optee *optee, bool is_mapped)
> > > {
> > > struct optee_call_waiter w;
> > >
> > > @@ -439,6 +441,13 @@ void optee_disable_shm_cache(struct optee *optee)
> > > if (res.result.status == OPTEE_SMC_RETURN_OK) {
> > > struct tee_shm *shm;
> > >
> > > + /*
> > > + * Shared memory references that were not mapped by
> > > + * this kernel must be ignored to prevent a crash.
> > > + */
> > > + if (!is_mapped)
> > > + continue;
> > > +
> > > shm = reg_pair_to_ptr(res.result.shm_upper32,
> > > res.result.shm_lower32);
> > > tee_shm_free(shm);
> > > diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
> > > index 0987074d7ed0..6974e1104bd4 100644
> > > --- a/drivers/tee/optee/core.c
> > > +++ b/drivers/tee/optee/core.c
> > > @@ -589,7 +589,7 @@ static int optee_remove(struct platform_device *pdev)
> > > * reference counters and also avoid wild pointers in secure world
> > > * into the old shared memory range.
> > > */
> > > - optee_disable_shm_cache(optee);
> > > + optee_disable_shm_cache(optee, true);
> >
> > Naked "true" or "false" parameters are normally not very descriptive.
> > Would it make sense to write this as:
> > optee_disable_shm_cache(optee, true /*is_mapped*/);
> > instead (same for the other call sites in this patch)? That way it would
> > be easier to see what it is that is true or false.
>
> Yeah, I understand the issue with the naked bools. What about turning
> 'optee_disable_shm_cache(struct optee *optee, bool is_mapped)' into
> '__optee_disable_shm_cache(struct optee *optee, bool is_mapped)' and
> introducing these two wrappers:
>
> /**
> * optee_disable_shm_cache() - Disables caching of mapped shared memory
> * allocations in OP-TEE
> * @optee: main service struct
> */
> void optee_disable_shm_cache(struct optee *optee)
> {
> return __optee_disable_shm_cache(optee, true);
> }
>
> /**
> * optee_disable_unmapped_shm_cache() - Disables caching of shared memory
> * allocations in OP-TEE which are not
> * currently mapped
> * @optee: main service struct
> */
> void optee_disable_unmapped_shm_cache(struct optee *optee)
> {
> return __optee_disable_shm_cache(optee, false);
> }
>
> Existing callers of optee_disable_shm_cache() remain unchanged and we just add
> one caller of optee_disable_unmapped_shm_cache() with this patch.
>
Sounds good.
Jens
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v4 7/8] tpm_ftpm_tee: Free and unregister TEE shared memory during kexec
2021-06-10 21:09 ` [PATCH v4 7/8] tpm_ftpm_tee: Free and unregister TEE shared memory during kexec Tyler Hicks
@ 2021-06-15 13:04 ` Jarkko Sakkinen
0 siblings, 0 replies; 18+ messages in thread
From: Jarkko Sakkinen @ 2021-06-15 13:04 UTC (permalink / raw)
To: op-tee
[-- Attachment #1: Type: text/plain, Size: 2119 bytes --]
On Thu, Jun 10, 2021 at 04:09:12PM -0500, Tyler Hicks wrote:
> 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: 09e574831b27 ("tpm/tpm_ftpm_tee: A driver for firmware TPM running inside TEE")
> Fixes: 1760eb689ed6 ("tpm/tpm_ftpm_tee: add shutdown call back")
> Signed-off-by: Tyler Hicks <tyhicks@linux.microsoft.com>
Acked-by: Jarkko Sakkinen <jarkko@kernel.org>
> ---
> drivers/char/tpm/tpm_ftpm_tee.c | 8 ++++----
> 1 file changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/char/tpm/tpm_ftpm_tee.c b/drivers/char/tpm/tpm_ftpm_tee.c
> index 2ccdf8ac6994..6e3235565a4d 100644
> --- a/drivers/char/tpm/tpm_ftpm_tee.c
> +++ b/drivers/char/tpm/tpm_ftpm_tee.c
> @@ -254,11 +254,11 @@ static int ftpm_tee_probe(struct device *dev)
> pvt_data->session = sess_arg.session;
>
> /* Allocate dynamic shared memory with fTPM TA */
> - pvt_data->shm = tee_shm_alloc(pvt_data->ctx,
> - MAX_COMMAND_SIZE + MAX_RESPONSE_SIZE,
> - TEE_SHM_MAPPED | TEE_SHM_DMA_BUF);
> + pvt_data->shm = tee_shm_alloc_kernel_buf(pvt_data->ctx,
> + MAX_COMMAND_SIZE +
> + MAX_RESPONSE_SIZE);
> if (IS_ERR(pvt_data->shm)) {
> - dev_err(dev, "%s: tee_shm_alloc failed\n", __func__);
> + dev_err(dev, "%s: tee_shm_alloc_kernel_buf failed\n", __func__);
> rc = -ENOMEM;
> goto out_shm_alloc;
> }
> --
> 2.25.1
>
>
/Jarkko
^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2021-06-15 13:04 UTC | newest]
Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2021-06-10 21:09 [PATCH v4 0/8] tee: Improve support for kexec and kdump Tyler Hicks
2021-06-10 21:09 ` [PATCH v4 1/8] optee: Fix memory leak when failing to register shm pages Tyler Hicks
2021-06-11 9:05 ` Jens Wiklander
2021-06-10 21:09 ` [PATCH v4 2/8] optee: Refuse to load the driver under the kdump kernel Tyler Hicks
2021-06-11 9:08 ` Jens Wiklander
2021-06-10 21:09 ` [PATCH v4 3/8] optee: fix tee out of memory failure seen during kexec reboot Tyler Hicks
2021-06-11 9:11 ` Jens Wiklander
2021-06-14 7:22 ` Jens Wiklander
2021-06-10 21:09 ` [PATCH v4 4/8] optee: Clear stale cache entries during initialization Tyler Hicks
2021-06-14 8:27 ` Jens Wiklander
2021-06-14 19:06 ` Tyler Hicks
2021-06-14 19:15 ` Jens Wiklander
2021-06-10 21:09 ` [PATCH v4 5/8] tee: add tee_shm_alloc_kernel_buf() Tyler Hicks
2021-06-10 21:09 ` [PATCH v4 6/8] tee: Support kernel shm registration without dma-buf backing Tyler Hicks
2021-06-11 5:16 ` Sumit Garg
2021-06-10 21:09 ` [PATCH v4 7/8] tpm_ftpm_tee: Free and unregister TEE shared memory during kexec Tyler Hicks
2021-06-15 13:04 ` Jarkko Sakkinen
2021-06-10 21:09 ` [PATCH v4 8/8] firmware: tee_bnxt: Release TEE shm, session, and context " Tyler Hicks
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).