Hi,
LOC monthly meeting is planned to take place Monday December 21st(a)16.00
(UTC+1). This time it will just be an open discussion, since we have no
planned presentation/talks otherwise. So feel free to suggest topics you'd
like to discuss (by replying to this email or write it directly in the
meeting notes).
The issue we had last time with Zoom ID not valid any longer should have
been fixed now. Note that the fix involved generating a new meeting ID,
which means that the old connection information is no longer valid. It's
also worth mentioning that all upcoming meetings can now be found at the
TrustedFirmware calendar (url is below).
Meeting details:
---------------
Date/time: Monday December 21st(a)16.00 (UTC+1)
https://everytimezone.com/s/f5c1ffe4
Connection details: https://www.trustedfirmware.org/meetings/
Meeting notes: http://bit.ly/loc-notes
Project page: https://www.linaro.org/projects/#LOC
Regards,
Joakim on behalf of the Linaro OP-TEE team
Hi All,
The next TF-A Tech Forum is scheduled for Thu 17th December 2020 16:00 – 17:00 (GMT).
As well as being posted to the TF-A mailing list this has been cross posted to OPTEE mailing list. For OPTEE attendees the Zoom call details are included below.
Agenda:
* An introduction to the Trusted Services project
* Presented by Julian Hall
* Summary
* The Trusted Services project is a new trustedfirmware.org project that provides a home for security related service components that can run in the different isolated processing environments available on Arm Cortex-A. The project attempts to promote reuse and standardization to enable a consistent set of services to be provided by firmware, independent of which isolation technology is used.
If TF-A contributors have anything they wish to present at any future TF-A tech forum please contact me to have that scheduled.
Previous sessions, both recording and presentation material can be found on the trustedfirmware.org TF-A Technical meeting webpage: https://www.trustedfirmware.org/meetings/tf-a-technical-forum/
A scheduling tracking page is also available to help track sessions suggested and being prepared: https://developer.trustedfirmware.org/w/tf_a/tf-a-tech-forum-scheduling/ Final decisions on what will be presented will be shared a few days before the next meeting and shared on the TF-A mailing list.
This is the last TF-A Tech Forum session until January 2021.
Join Zoom Meeting
https://zoom.us/j/9159704974<https://www.google.com/url?q=https%3A%2F%2Fzoom.us%2Fj%2F9159704974&sa=D&us…>
Meeting ID: 915 970 4974
One tap mobile
+16465588656,,9159704974# US (New York)
+16699009128,,9159704974# US (San Jose)
Dial by your location
+1 646 558 8656 US (New York)
+1 669 900 9128 US (San Jose)
877 853 5247 US Toll-free
888 788 0099 US Toll-free
Meeting ID: 915 970 4974
Find your local number: https://zoom.us/u/ad27hc6t7h<https://www.google.com/url?q=https%3A%2F%2Fzoom.us%2Fu%2Fad27hc6t7h&sa=D&us…>
Thanks
Joanna
This is both a resend and a request for comments.
The main reason for implementing this was to be able to authorize
access to particular TAs based on the applications that request it.
Furthermore, being able to distinguish between different applications
also allows having trusted storage per-application.
I believe this functionality might be crucial to many users of op-tee.
This patch provides two possible ways of calculating the application
identifier strings. This also serves as a stub for other methods.
Since there is no concept of "application" known to the Linux kernel,
the two proposed methods are based on the calling task's executable:
the executable file's path and its SELinux attributes.
Some vendor-specific methods may employ a service running in userspace,
but these two methods are the only ones that we came up with that
are fully contained in the kernel and are usable (and we actually use
one of the two methods suggested).
There might be other valid definitions of application-based identifier
strings. The GP TEE Client API specifies the credentials generated as
"only depending on the identity of the application program", being
"persistent within one implementation, across multiple invocations of
the application and across power cycles, enabling them to be used to
disambiguate persistent storage"; not more specific than that.
Perhaps some other properties of a running task can be used to calculate
an app ID, for example, to not depend on having an executable file
(which is admittedly a rare thing to come by), or to be able
to distinguish between different scripts run with one interpreter
(which is also rare since the TEE Client API is C-based).
If you're interested in this patch, or if you're using application-based
login methods but with a different scheme, I would love to hear your
experiences. Maybe there are other methods to consider; maybe the
proposed methods are enough.
If you're interested in testing this patch out, there is a reviewed,
good-to-go pull request in the optee_test repository:
https://github.com/OP-TEE/optee_test/pull/468
>8------------------------------------------------------8<
GP TEE Client API in addition to login methods already supported
in the kernel also defines several application-based methods:
TEEC_LOGIN_APPLICATION, TEEC_LOGIN_USER_APPLICATION, and
TEEC_LOGIN_GROUP_APPLICATION.
It specifies credentials generated for TEEC_LOGIN_APPLICATION as only
depending on the identity of the program, being persistent within one
implementation, across multiple invocations of the application
and across power cycles, enabling them to be used to disambiguate
persistent storage. The exact nature is REE-specific.
As the exact method of generating application identifier strings may
vary between vendors, setups and installations, add two suggested
methods and an exact framework for vendors to extend upon.
Signed-off-by: Elvira Khabirova <e.khabirova(a)omprussia.ru>
---
Changes in v4:
- Fix potential exe_file leaks.
Changes in v3:
- Remove free_app_id() and replace it with calls to kfree().
Changes in v2:
- Rename some functions and variables to make them shorter.
- Include linux/security.h unconditionally.
- Restructure error handling in tee_session_calc_client_uuid().
---
drivers/tee/Kconfig | 29 ++++++++++
drivers/tee/tee_core.c | 126 ++++++++++++++++++++++++++++++++++++++---
2 files changed, 147 insertions(+), 8 deletions(-)
diff --git a/drivers/tee/Kconfig b/drivers/tee/Kconfig
index e99d840c2511..4cd6e0d2aad5 100644
--- a/drivers/tee/Kconfig
+++ b/drivers/tee/Kconfig
@@ -11,6 +11,35 @@ config TEE
This implements a generic interface towards a Trusted Execution
Environment (TEE).
+choice
+ prompt "Application ID for client UUID"
+ depends on TEE
+ default TEE_APPID_PATH
+ help
+ This option allows to choose which method will be used to generate
+ application identifiers for client UUID generation when login methods
+ TEE_LOGIN_APPLICATION, TEE_LOGIN_USER_APPLICATION
+ and TEE_LOGIN_GROUP_APPLICATION are used.
+ Please be mindful of the security of each method in your particular
+ installation.
+
+ config TEE_APPID_PATH
+ bool "Path-based application ID"
+ help
+ Use the executable's path as an application ID.
+
+ config TEE_APPID_SECURITY
+ bool "Security extended attribute based application ID"
+ help
+ Use the executable's security extended attribute as an application ID.
+endchoice
+
+config TEE_APPID_SECURITY_XATTR
+ string "Security extended attribute to use for application ID"
+ depends on TEE_APPID_SECURITY
+ help
+ Attribute to be used as an application ID (with the security prefix removed).
+
if TEE
menu "TEE drivers"
diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
index 6ade4a5c4840..510ef2fceb82 100644
--- a/drivers/tee/tee_core.c
+++ b/drivers/tee/tee_core.c
@@ -7,9 +7,12 @@
#include <linux/cdev.h>
#include <linux/cred.h>
+#include <linux/file.h>
#include <linux/fs.h>
#include <linux/idr.h>
+#include <linux/mm.h>
#include <linux/module.h>
+#include <linux/security.h>
#include <linux/slab.h>
#include <linux/tee_drv.h>
#include <linux/uaccess.h>
@@ -21,7 +24,7 @@
#define TEE_IOCTL_PARAM_SIZE(x) (sizeof(struct tee_param) * (x))
-#define TEE_UUID_NS_NAME_SIZE 128
+#define TEE_UUID_NS_NAME_SIZE PATH_MAX
/*
* TEE Client UUID name space identifier (UUIDv4)
@@ -125,6 +128,65 @@ static int tee_release(struct inode *inode, struct file *filp)
return 0;
}
+#ifdef CONFIG_TEE_APPID_SECURITY
+static const char *get_app_id(void **data)
+{
+ struct file *exe_file;
+ const char *name = CONFIG_TEE_APPID_SECURITY_XATTR;
+ int len;
+
+ exe_file = get_mm_exe_file(current->mm);
+ if (!exe_file)
+ return ERR_PTR(-ENOENT);
+
+ if (!exe_file->f_inode) {
+ fput(exe_file);
+ return ERR_PTR(-ENOENT);
+ }
+
+ /*
+ * An identifier string for the binary. Depends on the implementation.
+ * Could be, for example, a string containing the application vendor ID,
+ * or the binary's signature, or its hash and a timestamp.
+ */
+ len = security_inode_getsecurity(exe_file->f_inode, name, data, true);
+ fput(exe_file);
+
+ if (len < 0)
+ return ERR_PTR(len);
+
+ return *data;
+}
+#endif /* CONFIG_TEE_APPID_SECURITY */
+
+#ifdef CONFIG_TEE_APPID_PATH
+static const char *get_app_id(void **data)
+{
+ struct file *exe_file;
+ char *path;
+
+ *data = kzalloc(TEE_UUID_NS_NAME_SIZE, GFP_KERNEL);
+ if (!*data)
+ return ERR_PTR(-ENOMEM);
+
+ exe_file = get_mm_exe_file(current->mm);
+ if (!exe_file) {
+ kfree(*data);
+ return ERR_PTR(-ENOENT);
+ }
+
+ path = file_path(exe_file, *data, TEE_UUID_NS_NAME_SIZE);
+ fput(exe_file);
+
+ if (IS_ERR(path)) {
+ kfree(*data);
+ return path;
+ }
+
+ return path;
+}
+#endif /* CONFIG_TEE_APPID_PATH */
+
/**
* uuid_v5() - Calculate UUIDv5
* @uuid: Resulting UUID
@@ -197,6 +259,8 @@ int tee_session_calc_client_uuid(uuid_t *uuid, u32 connection_method,
gid_t ns_grp = (gid_t)-1;
kgid_t grp = INVALID_GID;
char *name = NULL;
+ void *app_id_data = NULL;
+ const char *app_id = NULL;
int name_len;
int rc;
@@ -218,6 +282,14 @@ int tee_session_calc_client_uuid(uuid_t *uuid, u32 connection_method,
* For TEEC_LOGIN_GROUP:
* gid=<gid>
*
+ * For TEEC_LOGIN_APPLICATION:
+ * app=<application id>
+ *
+ * For TEEC_LOGIN_USER_APPLICATION:
+ * uid=<uid>:app=<application id>
+ *
+ * For TEEC_LOGIN_GROUP_APPLICATION:
+ * gid=<gid>:app=<application id>
*/
name = kzalloc(TEE_UUID_NS_NAME_SIZE, GFP_KERNEL);
@@ -228,10 +300,6 @@ int tee_session_calc_client_uuid(uuid_t *uuid, u32 connection_method,
case TEE_IOCTL_LOGIN_USER:
name_len = snprintf(name, TEE_UUID_NS_NAME_SIZE, "uid=%x",
current_euid().val);
- if (name_len >= TEE_UUID_NS_NAME_SIZE) {
- rc = -E2BIG;
- goto out_free_name;
- }
break;
case TEE_IOCTL_LOGIN_GROUP:
@@ -244,10 +312,49 @@ int tee_session_calc_client_uuid(uuid_t *uuid, u32 connection_method,
name_len = snprintf(name, TEE_UUID_NS_NAME_SIZE, "gid=%x",
grp.val);
- if (name_len >= TEE_UUID_NS_NAME_SIZE) {
- rc = -E2BIG;
+ break;
+
+ case TEE_IOCTL_LOGIN_APPLICATION:
+ app_id = get_app_id(&app_id_data);
+ if (IS_ERR(app_id)) {
+ rc = PTR_ERR(app_id);
+ goto out_free_name;
+ }
+
+ name_len = snprintf(name, TEE_UUID_NS_NAME_SIZE, "app=%s",
+ app_id);
+ kfree(app_id_data);
+ break;
+
+ case TEE_IOCTL_LOGIN_USER_APPLICATION:
+ app_id = get_app_id(&app_id_data);
+ if (IS_ERR(app_id)) {
+ rc = PTR_ERR(app_id);
goto out_free_name;
}
+
+ name_len = snprintf(name, TEE_UUID_NS_NAME_SIZE, "uid=%x:app=%s",
+ current_euid().val, app_id);
+ kfree(app_id_data);
+ break;
+
+ case TEE_IOCTL_LOGIN_GROUP_APPLICATION:
+ memcpy(&ns_grp, connection_data, sizeof(gid_t));
+ grp = make_kgid(current_user_ns(), ns_grp);
+ if (!gid_valid(grp) || !in_egroup_p(grp)) {
+ rc = -EPERM;
+ goto out_free_name;
+ }
+
+ app_id = get_app_id(&app_id_data);
+ if (IS_ERR(app_id)) {
+ rc = PTR_ERR(app_id);
+ goto out_free_name;
+ }
+
+ name_len = snprintf(name, TEE_UUID_NS_NAME_SIZE, "gid=%x:app=%s",
+ grp.val, app_id);
+ kfree(app_id_data);
break;
default:
@@ -255,7 +362,10 @@ int tee_session_calc_client_uuid(uuid_t *uuid, u32 connection_method,
goto out_free_name;
}
- rc = uuid_v5(uuid, &tee_client_uuid_ns, name, name_len);
+ if (name_len < TEE_UUID_NS_NAME_SIZE)
+ rc = uuid_v5(uuid, &tee_client_uuid_ns, name, name_len);
+ else
+ rc = -E2BIG;
out_free_name:
kfree(name);
--
2.29.2
On Mon, 2020-12-07 at 16:48 +0000, Robert Deliën via OP-TEE wrote:
> Hi,
>
> Again, thank you very much for your prompt answer.
>
> > Looks good, the tee_mm functions handle resource allocation typically
> > virtual or physical memory. It doesn't touch the memory itself. The
> > code above looks OK. Yep, the memory will be physically contiguous
> > since the entire TA RAM range (represented here by tee_mm_sec_ddr) is
> > mapped with physically contiguous memory.
>
> The code 'works' beautifully. That is; The FB addresses it produces seem plausible:
> D/TC:0 0 imx_lcdif_init:334 fb[0] @0x88e00000 (pa 0x8e100000)
> D/TC:0 0 imx_lcdif_init:334 fb[1] @0x88e96000 (pa 0x8e196000)
> Even accessing the buffer using the corresponding virtual addresses produces no Abort faults.
>
> Unfortunately, it doesn't produce an image on the LCD either. However, if I (illegally) re-use part of shared memory as a frame buffer, I _do_ get an image.
> Details from conf.mk:
> CFG_DRAM_BASE = 0x80000000
> CFG_DDR_SIZE = 0x10000000
> CFG_SHMEM_SIZE = 0x00200000
> CFG_SHMEM_START = ($(CFG_DRAM_BASE) + $(CFG_DDR_SIZE) - $(CFG_SHMEM_SIZE))
>
> Details from code:
> fb_pa = 0x90000000 - FB_SIZE;
> fb_va = (void *fb_pa, MEM_AREA_NSEC_SHM);
>
> We are starting to suspect that the LCD peripheral is denied access to the frame buffer by the TZ controller, and this specific peripheral's bus master doesn't seem to have corresponding Supervisor mode bits in the HP0 or SA register.
>
> Now I do know that this problem is beyond the scope of this mailing list, but if anybody on this list knows more about this, I'd be more than happy to hear about it!
>
Hm, since the LCDIF CSL register is lumped together with the PXP, you
could try setting the SA bit for the PXP peripheral.
Regards,
Rouven Czerwinski
Hi Robert,
Some answers below.
On Wed, Dec 2, 2020 at 1:00 PM Robert Deliën via OP-TEE
<op-tee(a)lists.trustedfirmware.org> wrote:
>
> Hi,
>
> We are using op-tee 3.10 in our i.MX6UL-based product and we are running into a small problem we hope you can help us out with. Apologies for the large mail; It's mostly pictures.
>
> The nature of our product requires us to protect access to the display contents. To achieve this, we have added a display driver to op-tee and have allocated the frame buffers in op-tee too.
>
> We are conforming to the memory-map as layed out in .../core/arch/arm/include/mm/generic_ram_layout.h:
>
> TEE RAM layout without CFG_WITH_PAGER
>
> +----------------------------------+ <-- CFG_TZDRAM_START
> | TEE core secure RAM (TEE_RAM) |
> +----------------------------------+
> | Trusted Application RAM (TA_RAM) |
> +----------------------------------+
> | SDP test memory (optional) |
> +----------------------------------+ <-- CFG_TZDRAM_START + CFG_TZDRAM_SIZE
>
> +----------------------------------+ <-- CFG_SHMEM_START
> | Non-secure static SHM |
> +----------------------------------+ <-- CFG_SHMEM_START + CFG_SHMEM_SIZE
>
> With this memory map in mind, we came up with the following solution:
>
> +----------------------------------+ <-- CFG_DRAM_BASE
> | |
> | Non-secure memory |
> | |
> +----------------------------------+ <-- CFG_TZDRAM_START
> | TEE core secure RAM (TEE_RAM) |
> +----------------------------------+
> | Trusted Application RAM (TA_RAM) |
> +----------------------------------+ <-- CFG_POS_SEC_FB0_START
> | Secure frame buffer 0 |
> +----------------------------------+ <-- CFG_POS_SEC_FB1_START
> | Secure frame buffer 1 |
> +----------------------------------+ <-- CFG_SHMEM_START (== CFG_TZDRAM_START + CFG_TZDRAM_SIZE)
> | Non-secure static SHM |
> +----------------------------------+ <-- Top of DDR (CFG_SHMEM_START + CFG_SHMEM_SIZE)
> CFG_DDR_SIZE = 0x10000000
> CFG_SHMEM_SIZE = 0x00200000
> CFG_SHMEM_START = ($(CFG_DRAM_BASE) + $(CFG_DDR_SIZE) - $(CFG_SHMEM_SIZE))
> CFG_SEC_FB_SIZE = 0x00096000
> CFG_POS_SEC_FB1_START = ($(CFG_SHMEM_START) - $(CFG_SEC_FB_SIZE))
> CFG_POS_SEC_FB0_START = ($(CFG_POS_SEC_FB1_START) - $(CFG_SEC_FB_SIZE))
> CFG_TZDRAM_START = ($(CFG_DRAM_BASE) + 0x0e000000)
> CFG_TZDRAM_SIZE = ($(CFG_SHMEM_START) - $(CFG_TZDRAM_START))
>
> This solution keeps the frame buffers within the region CFG_TZDRAM_START:CFG_TZDRAM_SIZE, but when booting the system, we notice an overlap between TA_RAM and both frame buffer areas:
>
> D/TC:0 dump_mmap_table:732 type TA_RAM va 0x88c00000..0x8a8fffff pa 0x8e100000..0x8fdfffff size 0x01d00000 (pgdir)
> ...
> D/TC:0 dump_mmap_table:732 type RAM_SEC va 0x8ded4000..0x8df69fff pa 0x8fd6a000..0x8fdfffff size 0x00096000 (smallpg)
> D/TC:0 dump_mmap_table:732 type RAM_SEC va 0x8df6a000..0x8dffffff pa 0x8fcd4000..0x8fd69fff size 0x00096000 (smallpg)
>
> Without fully comprehending how memory is allocated, we fear that this situation will allow TA's to be loaded into these frame buffer areas.
> To mitigate this, we came up with this alternative:
>
> +----------------------------------+ <-- CFG_DRAM_BASE
> | |
> | Non-secure memory |
> | |
> +----------------------------------+ <-- CFG_TZDRAM_START
> | TEE core secure RAM (TEE_RAM) |
> +----------------------------------+
> | Trusted Application RAM (TA_RAM) |
> +----------------------------------+ <-- CFG_POS_SEC_FB0_START (== CFG_TZDRAM_START + CFG_TZDRAM_SIZE)
> | Secure frame buffer 0 |
> +----------------------------------+ <-- CFG_POS_SEC_FB1_START
> | Secure frame buffer 1 |
> +----------------------------------+ <-- CFG_SHMEM_START
> | Non-secure static SHM |
> +----------------------------------+ <-- Top of DDR (CFG_SHMEM_START + CFG_SHMEM_SIZE)
> CFG_DDR_SIZE = 0x10000000
> CFG_SHMEM_SIZE = 0x00200000
> CFG_SHMEM_START = ($(CFG_DRAM_BASE) + $(CFG_DDR_SIZE) - $(CFG_SHMEM_SIZE))
> CFG_SEC_FB_SIZE = 0x00096000
> CFG_POS_SEC_FB1_START = ($(CFG_SHMEM_START) - $(CFG_SEC_FB_SIZE))
> CFG_POS_SEC_FB0_START = ($(CFG_POS_SEC_FB1_START) - $(CFG_SEC_FB_SIZE))
> CFG_TZDRAM_START = ($(CFG_DRAM_BASE) + 0x0e000000)
> CFG_TZDRAM_SIZE = ($(CFG_POS_SEC_FB0_START) - $(CFG_TZDRAM_START))
>
> This solution puts the frame buffers outside the region CFG_TZDRAM_START:CFG_TZDRAM_SIZE so they no longer overlap with TA_RAM. However, when booting the system, op-tee panics:
>
> D/TC:0 dump_mmap_table:732 type RAM_SEC va 0x8c2d4000..0x8c369fff pa 0x8fd6a000..0x8fdfffff size 0x00096000 (smallpg)
> D/TC:0 dump_mmap_table:732 type RAM_SEC va 0x8c36a000..0x8c3fffff pa 0x8fcd4000..0x8fd69fff size 0x00096000 (smallpg)
> ...
> D/TC:0 dump_mmap_table:732 type TA_RAM va 0x8c400000..0x8dfd3fff pa 0x8e100000..0x8fcd3fff size 0x01bd4000 (smallpg)
> ...
> E/TC:0 0 check_phys_mem_is_outside:332 Non-sec mem (0x8fcd4000:0x12c000) overlaps map (type 12 0x8fd6a000:0x96000)
> E/TC:0 0 Panic at core/arch/arm/mm/core_mmu.c:336 <check_phys_mem_is_outside>
> E/TC:0 0 TEE load address @ 0x8e000000
> E/TC:0 0 Call stack:
> E/TC:0 0 0x8e005621
> E/TC:0 0 0x8e01d397
> E/TC:0 0 0x8e005aaf
> E/TC:0 0 0x8e004da7
> E/TC:0 0 0x8e000174
>
> In this situation, the memory area intended for the frame buffers (0x8fd6a000:0x96000) is now implicitly regarded as non-secure RAM, regardless of us registering it as MEM_AREA_RAM_SEC in main.c:
>
> register_phys_mem(MEM_AREA_RAM_SEC, CFG_POS_SEC_FB0_START, CFG_SEC_FB_SIZE);
> register_phys_mem(MEM_AREA_RAM_SEC, CFG_POS_SEC_FB1_START, CFG_SEC_FB_SIZE);
>
> Could you please confirm (or deny) that our first solution is the proper way to allocate these secure frame buffers and that they will not be overwritten by the process of loading TAs?
It looks like something went wrong in the first solution. The failure
in the last solution is because OP-TEE thinks that you've accidentally
tried to configure non-secure memory as secure memory.
> If this is not the proper way, could you give us some pointers on how to do this? We do not feel comfortable allocating such large areas on the heap because of good taste and because we're not sure yet whether or not there are additional alignment requirement for these frame buffers. Perhaps something similar to the Linux slab-allocator is available?
I think the easiest is to allocate memory from the pool used for TAs with:
mm = tee_mm_alloc(&tee_mm_sec_ddr, size);
Until this mm is freed no one else will use the memory it represents.
Returned memory is page aligned (based on CORE_MMU_USER_CODE_SHIFT).
This depends on paging being disabled, which it seems it is for the
IMX platforms.
If paging would have been enabled this memory might have been less
secure than what you require, depending on how the platform is
configured.
Cheers,
Jens
Hi,
LOC monthly meeting is planned to take place October 28th @ 16.00 (UTC+1).
Connection details can be found in the meeting notes document (link below).
Ilias and Jens will give an introduction to the secure partitions and
StandaloneMM parts in OP-TEE. Other than that feel free to suggest topics
you'd like to discuss (by replying to this email or write it directly in
the meeting notes).
Note that it's UTC+1 since we're moving to winter time in Sweden in a
couple of days from now (previous LOC meetings have been UTC+2).
Meeting details:
---------------
Date/time: Wednesday October 28th(a)16.00 (UTC+1)
https://everytimezone.com/s/9bfdb976
Invitation/connection details: In the meeting notes
Meeting notes: http://bit.ly/loc-notes
Project page: https://www.linaro.org/projects/#LOC
Regards,
Joakim on behalf of the Linaro OP-TEE team
Hi,
We are using op-tee 3.10 in our i.MX6UL-based product and we are running into a small problem we hope you can help us out with. Apologies for the large mail; It's mostly pictures.
The nature of our product requires us to protect access to the display contents. To achieve this, we have added a display driver to op-tee and have allocated the frame buffers in op-tee too.
We are conforming to the memory-map as layed out in .../core/arch/arm/include/mm/generic_ram_layout.h:
TEE RAM layout without CFG_WITH_PAGER
+----------------------------------+ <-- CFG_TZDRAM_START
| TEE core secure RAM (TEE_RAM) |
+----------------------------------+
| Trusted Application RAM (TA_RAM) |
+----------------------------------+
| SDP test memory (optional) |
+----------------------------------+ <-- CFG_TZDRAM_START + CFG_TZDRAM_SIZE
+----------------------------------+ <-- CFG_SHMEM_START
| Non-secure static SHM |
+----------------------------------+ <-- CFG_SHMEM_START + CFG_SHMEM_SIZE
With this memory map in mind, we came up with the following solution:
+----------------------------------+ <-- CFG_DRAM_BASE
| |
| Non-secure memory |
| |
+----------------------------------+ <-- CFG_TZDRAM_START
| TEE core secure RAM (TEE_RAM) |
+----------------------------------+
| Trusted Application RAM (TA_RAM) |
+----------------------------------+ <-- CFG_POS_SEC_FB0_START
| Secure frame buffer 0 |
+----------------------------------+ <-- CFG_POS_SEC_FB1_START
| Secure frame buffer 1 |
+----------------------------------+ <-- CFG_SHMEM_START (== CFG_TZDRAM_START + CFG_TZDRAM_SIZE)
| Non-secure static SHM |
+----------------------------------+ <-- Top of DDR (CFG_SHMEM_START + CFG_SHMEM_SIZE)
CFG_DDR_SIZE = 0x10000000
CFG_SHMEM_SIZE = 0x00200000
CFG_SHMEM_START = ($(CFG_DRAM_BASE) + $(CFG_DDR_SIZE) - $(CFG_SHMEM_SIZE))
CFG_SEC_FB_SIZE = 0x00096000
CFG_POS_SEC_FB1_START = ($(CFG_SHMEM_START) - $(CFG_SEC_FB_SIZE))
CFG_POS_SEC_FB0_START = ($(CFG_POS_SEC_FB1_START) - $(CFG_SEC_FB_SIZE))
CFG_TZDRAM_START = ($(CFG_DRAM_BASE) + 0x0e000000)
CFG_TZDRAM_SIZE = ($(CFG_SHMEM_START) - $(CFG_TZDRAM_START))
This solution keeps the frame buffers within the region CFG_TZDRAM_START:CFG_TZDRAM_SIZE, but when booting the system, we notice an overlap between TA_RAM and both frame buffer areas:
D/TC:0 dump_mmap_table:732 type TA_RAM va 0x88c00000..0x8a8fffff pa 0x8e100000..0x8fdfffff size 0x01d00000 (pgdir)
...
D/TC:0 dump_mmap_table:732 type RAM_SEC va 0x8ded4000..0x8df69fff pa 0x8fd6a000..0x8fdfffff size 0x00096000 (smallpg)
D/TC:0 dump_mmap_table:732 type RAM_SEC va 0x8df6a000..0x8dffffff pa 0x8fcd4000..0x8fd69fff size 0x00096000 (smallpg)
Without fully comprehending how memory is allocated, we fear that this situation will allow TA's to be loaded into these frame buffer areas.
To mitigate this, we came up with this alternative:
+----------------------------------+ <-- CFG_DRAM_BASE
| |
| Non-secure memory |
| |
+----------------------------------+ <-- CFG_TZDRAM_START
| TEE core secure RAM (TEE_RAM) |
+----------------------------------+
| Trusted Application RAM (TA_RAM) |
+----------------------------------+ <-- CFG_POS_SEC_FB0_START (== CFG_TZDRAM_START + CFG_TZDRAM_SIZE)
| Secure frame buffer 0 |
+----------------------------------+ <-- CFG_POS_SEC_FB1_START
| Secure frame buffer 1 |
+----------------------------------+ <-- CFG_SHMEM_START
| Non-secure static SHM |
+----------------------------------+ <-- Top of DDR (CFG_SHMEM_START + CFG_SHMEM_SIZE)
CFG_DDR_SIZE = 0x10000000
CFG_SHMEM_SIZE = 0x00200000
CFG_SHMEM_START = ($(CFG_DRAM_BASE) + $(CFG_DDR_SIZE) - $(CFG_SHMEM_SIZE))
CFG_SEC_FB_SIZE = 0x00096000
CFG_POS_SEC_FB1_START = ($(CFG_SHMEM_START) - $(CFG_SEC_FB_SIZE))
CFG_POS_SEC_FB0_START = ($(CFG_POS_SEC_FB1_START) - $(CFG_SEC_FB_SIZE))
CFG_TZDRAM_START = ($(CFG_DRAM_BASE) + 0x0e000000)
CFG_TZDRAM_SIZE = ($(CFG_POS_SEC_FB0_START) - $(CFG_TZDRAM_START))
This solution puts the frame buffers outside the region CFG_TZDRAM_START:CFG_TZDRAM_SIZE so they no longer overlap with TA_RAM. However, when booting the system, op-tee panics:
D/TC:0 dump_mmap_table:732 type RAM_SEC va 0x8c2d4000..0x8c369fff pa 0x8fd6a000..0x8fdfffff size 0x00096000 (smallpg)
D/TC:0 dump_mmap_table:732 type RAM_SEC va 0x8c36a000..0x8c3fffff pa 0x8fcd4000..0x8fd69fff size 0x00096000 (smallpg)
...
D/TC:0 dump_mmap_table:732 type TA_RAM va 0x8c400000..0x8dfd3fff pa 0x8e100000..0x8fcd3fff size 0x01bd4000 (smallpg)
...
E/TC:0 0 check_phys_mem_is_outside:332 Non-sec mem (0x8fcd4000:0x12c000) overlaps map (type 12 0x8fd6a000:0x96000)
E/TC:0 0 Panic at core/arch/arm/mm/core_mmu.c:336 <check_phys_mem_is_outside>
E/TC:0 0 TEE load address @ 0x8e000000
E/TC:0 0 Call stack:
E/TC:0 0 0x8e005621
E/TC:0 0 0x8e01d397
E/TC:0 0 0x8e005aaf
E/TC:0 0 0x8e004da7
E/TC:0 0 0x8e000174
In this situation, the memory area intended for the frame buffers (0x8fd6a000:0x96000) is now implicitly regarded as non-secure RAM, regardless of us registering it as MEM_AREA_RAM_SEC in main.c:
register_phys_mem(MEM_AREA_RAM_SEC, CFG_POS_SEC_FB0_START, CFG_SEC_FB_SIZE);
register_phys_mem(MEM_AREA_RAM_SEC, CFG_POS_SEC_FB1_START, CFG_SEC_FB_SIZE);
Could you please confirm (or deny) that our first solution is the proper way to allocate these secure frame buffers and that they will not be overwritten by the process of loading TAs? If this is not the proper way, could you give us some pointers on how to do this? We do not feel comfortable allocating such large areas on the heap because of good taste and because we're not sure yet whether or not there are additional alignment requirement for these frame buffers. Perhaps something similar to the Linux slab-allocator is available?
Thank you in advance for your help.
With kind regards,
Robert Deliën.
ARMv7 Architecture Reference Manual [1] section A3.5.5 details Normal
memory type, together with cacheability attributes that could be applied
to memory regions defined as "Normal memory".
Section B2.1.2 of the Architecture Reference Manual [1] also provides
details regarding the Memory attributes that could be assigned to
particular memory regions, which includes the descrption of cacheability
attributes and cache allocation hints.
Memory type and cacheability attributes forms 2 separate definitions,
where cacheability attributes defines a mechanism of coherency control
rather than the type of memory itself.
In other words: Normal memory type can be configured with several
combination of cacheability attributes, namely:
- Write-Through (WT)
- Write-Back (WB) followed by cache allocation hint:
- Write-Allocate
- No Write-Allocate (also known as Read-Allocate)
Those types are mapped in the kernel to corresponding macros:
- Write-Through: L_PTE_MT_WRITETHROUGH
- Write-Back Write-Allocate: L_PTE_MT_WRITEALLOC
- Write-Back Read-Allocate: L_PTE_MT_WRITEBACK
Current implementation of the op-tee driver takes in account only 2 last
memory region types, while performing a check if the memory block is
allocated as "Normal memory", leaving Write-Through allocations to be
not considered.
Extend verification mechanism to include also Normal memory regios,
which are designated with Write-Through cacheability attributes.
Link: [1]: https://developer.arm.com/documentation/ddi0406/cd
Fixes: 853735e40424 ("optee: add writeback to valid memory type")
Cc: stable(a)vger.kernel.org
Signed-off-by: Andrey Zhizhikin <andrey.zhizhikin(a)leica-geosystems.com>
---
drivers/tee/optee/call.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/tee/optee/call.c b/drivers/tee/optee/call.c
index c981757ba0d4..8da27d02a2d6 100644
--- a/drivers/tee/optee/call.c
+++ b/drivers/tee/optee/call.c
@@ -535,7 +535,8 @@ static bool is_normal_memory(pgprot_t p)
{
#if defined(CONFIG_ARM)
return (((pgprot_val(p) & L_PTE_MT_MASK) == L_PTE_MT_WRITEALLOC) ||
- ((pgprot_val(p) & L_PTE_MT_MASK) == L_PTE_MT_WRITEBACK));
+ ((pgprot_val(p) & L_PTE_MT_MASK) == L_PTE_MT_WRITEBACK) ||
+ ((pgprot_val(p) & L_PTE_MT_MASK) == L_PTE_MT_WRITETHROUGH));
#elif defined(CONFIG_ARM64)
return (pgprot_val(p) & PTE_ATTRINDX_MASK) == PTE_ATTRINDX(MT_NORMAL);
#else
--
2.17.1