Skip to content

core: add new PRC and PTA for loadable plugins framework - #4248

Merged
jforissier merged 2 commits into
OP-TEE:masterfrom
anisyanka:plugin-pta
Feb 4, 2021
Merged

core: add new PRC and PTA for loadable plugins framework#4248
jforissier merged 2 commits into
OP-TEE:masterfrom
anisyanka:plugin-pta

Conversation

@anisyanka

Copy link
Copy Markdown
Contributor

Any external TEE services can be designed as a tee-supplicant plugin.
The plugins will be loaded by the supplicant during startup process
using libdl.
It makes it easy to:

  • add new features in the supplicant that aren't needed in upstream,
    e.g. Rich OS specific services;
  • sync upstream version with own fork;

These patches add a new RPC - 'OPTEE_RPC_CMD_PLUGIN' as an unified
interface between OP-TEE and any plugins and a new PTA as an unified
interface between any user's TAs and any plugins.

Kernel code can use RPC directly to call for execution of some command in plugins.
TAs can use the plugin-pta.

Every plugin has own name based on UUID.
OP-TEE has access to plugins by it.

See definition of protocol for the command 'OPTEE_RPC_CMD_PLUGIN'
in 'core/include/optee_rpc_cmd.h' file.

Signed-off-by: Aleksandr Anisimov a.anisimov@omprussia.ru

@jforissier jforissier left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @anisyanka,

Thanks for the patches. Please see my comments below.

Comment thread core/include/optee_rpc_cmd.h Outdated
#define OPTEE_RPC_CMD_FTRACE 11

/*
* Plugin command, see definition of protocol below

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tee-supplicant plugin command ...

Comment thread core/include/optee_rpc_cmd.h Outdated
/*
* Plugin command, see definition of protocol below
*/
#define OPTEE_RPC_CMD_PLUGIN 12

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OPTEE_RPC_CMD_SUPP_PLUGIN

Comment thread core/include/optee_rpc_cmd.h Outdated
* [in] value[2].a sub_cmd for plugin
* [in] memref[3] buffer holding data for plugin
*/
#define OPTEE_INVOKE_PLUGIN 0

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For consistency: OPTEE_RPC_SUPP_PLUGIN_INVOKE

Comment thread core/include/optee_rpc_cmd.h Outdated
* [in] value[1].b uuid.d4
* [in] value[1].c cmd for plugin
* [in] value[2].a sub_cmd for plugin
* [in] memref[3] buffer holding data for plugin

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any chance one would need to return data back to secure world? ([in/out]).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think such cases are possible and we should provide the [in/out] ability, thanks

Comment thread core/include/tee/uuid.h Outdated
* Returns TEE_SUCCESS, when successfully converting a string or an error code,
* if it has a wrong format or NULL.
*/
TEE_Result tee_uuid_from_string(TEE_UUID *dst, const char *str, int len);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This duplicates tee_uuid_from_str() from lib/libutee/tee_uuid_from_str.c. If we keep string UUIDs (which I'm not convinced we should), then the implementation could be moved to libutils I think.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wow, I will try to use the tee_uuid_from_str() from libutee :)
In this case I will drop own implementation.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I said even better would be to not use character strings at all and use a TEE_UUID instead, unless I am missing something?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TAs work with plugins by its names and that's why the TAs pass the string with name to TEE_InvokeTACommand(), like here. This string is passed to the plugin-pta.
We can use tee_uuid_from_str() inside the PTA before calling tee_invoke_plugin_rpc().
If we will not use character strings at all in optee, we will need convert the strings in TA, when we want to call plugins.
I don't mind, but seems it looks not convinient for TA developes. What do you think?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could do:

#define SYSLOG_PLUGIN_UUID { 0x96bcf744, 0x4f72, 0x4866, \
                         { 0xbf, 0x1d, 0x86, 0x34, 0xfd, 0x9c, 0x65, 0xe5 } }

...instead of:

#define SYSLOG_PLUGIN_NAME "96bcf744-4f72-4866-bf1d-8634fd9c65e5"

That's how TAs open other TAs or PTAs for example. The only place you may need to convert from binary UUIDs to a string is in tee-supplicant when looking for a plugin (and even in this case it may not be necessary, I mean assuming tee-supplicant enumerates and loads all the plugins on startup, it would convert from plugin name to UUID instead, or find the UUID in the plugin).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, got it, thanks!

Comment thread core/include/tee/tee_plugin_rpc.h Outdated
#include <tee_api_types.h>

struct tee_plugin_rpc_operation {
const char *name; /* string "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" */

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use a TEE_UUID?

Comment thread core/tee/sub.mk Outdated

srcs-y += uuid.c
srcs-y += tee_ta_enc_manager.c
srcs-y += tee_plugin_rpc.c No newline at end of file

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tee_supp_plugin_rpc.c

Comment thread core/include/tee/tee_plugin_rpc.h Outdated
#include <stdint.h>
#include <tee_api_types.h>

struct tee_plugin_rpc_operation {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"supplicant" is missing here, struct supp_plugin_rpc_op maybe?
And filename could be supp_plugin_rpc.h.

Comment thread core/tee/tee_plugin_rpc.c Outdated

res = tee_uuid_from_string(&u, op->name, strlen(op->name));
if (res) {
EMSG("can't convert string <%s> to UUID", op->name);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You wouldn't need to care about this if you used TEE_UUID.

Comment thread core/pta/sub.mk Outdated
srcs-$(CFG_WITH_STATS) += stats.c
srcs-$(CFG_SYSTEM_PTA) += system.c
srcs-$(CFG_NXP_SE05X) += scp03.c
srcs-$(CFG_PLUGIN_PTA) += plugin.c

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CFG_SUPP_PLUGIN_PTA += supp_plugin.c

@etienne-lms

Copy link
Copy Markdown
Contributor

Isn't this providing the same kind of services as proposed by the OCALLs P-Rs (#3673 and related)?

@anisyanka

Copy link
Copy Markdown
Contributor Author

Isn't this providing the same kind of services as proposed by the OCALLs P-Rs (#3673 and related)?

Thanks for the link. I looked those PRs. The goals of our PRs are similar, but there are important differences:

  • OCALLs is about an interaction TA with a particular CA, but plugins can be common for several TAs without opening a session.
    The tee-supplicant loads all plugins using libdl from special directory during startup and after that all plugins are alive.
    For example see the syslog plugin (file tee-supplicant/plugins/syslog/syslog_plugin.c in tee-supplicant: add a framework for loadable plugins optee_client#239). With the help of it any TAs can write something to system log.
  • The proposed plugins don't require changes in Linux kernel and in libteec API. That's why plugins look more easy, but they still have the same capabilities.

@jenswikl jenswikl left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it make sense to add this to the system PTA instead of defining yet another PTA? System PTA is about providing system services to user TAs so it seems like a good match.

Comment thread core/tee/tee_plugin_rpc.c Outdated
goto out;
}

memcpy(&plug_uuid, &u, sizeof(TEE_UUID));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe tee_uuid_to_octets() would be a better choice in order to get the correct byte order.

Comment thread core/tee/tee_plugin_rpc.c Outdated
uint32_t d2;
uint32_t d3;
uint32_t d4;
} plug_uuid;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like uint32_t plug_uuid[4] = { }; would be just as useful and a bit simpler.

Comment thread core/tee/tee_plugin_rpc.c Outdated

memcpy(&plug_uuid, &u, sizeof(TEE_UUID));

struct thread_param params[THREAD_RPC_MAX_NUM_PARAMS] = {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Declarations of variables at the start of the block please.

Comment thread lib/libutee/include/pta_plugin.h Outdated
* [in] value[1].b sub_command for plugin
* [in] memref[2] additional data for plugin
*/
#define PTA_PLUGIN_INVOKE 0

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it be nice with a wrapper in libutee, something like:

TEE_Result optee_invoke_supp_plugin(const TEE_UUID *uuid, uint32_t cmd, uint32_t sub_cmd,
                                    void *buf, size_t len);

Comment thread lib/libutee/include/pta_plugin.h Outdated
* [in] memref[0].size length of the uuid string including '\0' symbol
* [in] value[1].a command for plugin
* [in] value[1].b sub_command for plugin
* [in] memref[2] additional data for plugin

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be in and out?

@anisyanka

Copy link
Copy Markdown
Contributor Author

Wouldn't it make sense to add this to the system PTA instead of defining yet another PTA? System PTA is about providing system services to user TAs so it seems like a good match.

Sounds good. I will move core/pta/supp_plugin.c functionality to core/pta/system and add a new API like #4248 (comment) to lib/libutee/tee_system_pta.c

@anisyanka

Copy link
Copy Markdown
Contributor Author

All comments have been addressed

@etienne-lms etienne-lms left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor comments

Comment thread core/include/tee/tee_supp_plugin_rpc.h Outdated
*/

#ifndef TEE_PLUGIN_RPC_H
#define TEE_PLUGIN_RPC_H

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TEE_SUPP_PLUGIN_RPC_H

Comment thread core/pta/system.c Outdated
static TEE_Result system_supp_plugin_invoke(uint32_t param_types,
TEE_Param params[TEE_NUM_PARAMS])
{
struct tee_supp_plugin_rpc_op op;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

= { };

Comment thread core/tee/tee_supp_plugin_rpc.c Outdated
#include <tee/tee_supp_plugin_rpc.h>
#include <tee/uuid.h>
#include <trace.h>
#include <mm/mobj.h>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move before line 8

Comment thread core/tee/tee_supp_plugin_rpc.c Outdated
{
TEE_Result res = TEE_ERROR_GENERIC;
struct thread_param params[THREAD_RPC_MAX_NUM_PARAMS];
uint32_t plugin_uuid[4];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

= { 0 };

Comment thread core/tee/tee_supp_plugin_rpc.c Outdated
uint32_t plugin_uuid[4];
void *va = NULL;
struct mobj *mobj = NULL;
uint32_t outlen;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

= 0;

Comment thread lib/libutee/tee_system_pta.c Outdated
res = invoke_system_pta(PTA_SYSTEM_SUPP_PLUGIN_INVOKE, param_types,
params);
if (res)
EMSG("Invoke tee-supplicant's plugin failed");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would make it a DMSG():

		DMSG("Invoke tee-supplicant's plugin failed: %#"PRIx32, res);

@anisyanka anisyanka Dec 17, 2020

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please explain why you want to use DMSG() instead EMSG()?
In this case we print the error message, that's why it seems EMSG is more suitable.

Comment thread core/pta/system.c Outdated
Comment thread lib/libutee/include/pta_system.h Outdated
/*
* Invoke a tee-supplicant's plugin
*
* [in] memref[0] uuid(octets) of the plugin

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Specify that it's a TEE_UUID to be clear.

* @cmd: command for the plugin
* @sub_cmd: subcommand for the plugin
* @buf: data [for/from] the plugin [in/out]
* @len: length of the buf

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be an out parameter too, in case the size is smaller when returning some result?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think yes.
We can replace size_t len to size_t *len and use one pointer to input and output length.

Comment thread core/tee/tee_supp_plugin_rpc.c Outdated
#include <trace.h>
#include <mm/mobj.h>

TEE_Result tee_invoke_supp_plugin_rpc(struct tee_supp_plugin_rpc_op *op)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this function taking a struct tee_supp_plugin_rpc_op only used for this purpose instead of separate parameters?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can use separate parameters here. Ok, I will drop tee_supp_plugin_rpc_op

@anisyanka

Copy link
Copy Markdown
Contributor Author

All comments have been addressed

Comment thread core/pta/system.c Outdated
params[1].value.b, /* sub_cmd */
params[2].memref.buffer, /* data */
params[2].memref.size, /* in len */
(size_t *)&params[3].value.a

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This cast isn't portable.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you are right. I will fix it

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sorry, I should have been more clear. Please use a temporary helper variable instead of changing the type in the argument of tee_invoke_supp_plugin_rpc().

@anisyanka anisyanka Jan 10, 2021

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems you see outdated changes.
In previous commits I changed outlen type for tee_invoke_supp_plugin_rpc() from size_t * to uint32_t * and removed type conversion in core/pta/system.c:863. See the last fixup commit: 3a46040#diff-80ee4f614b595d036997a8c22e8034f37acf85250c5829593e630cab71a9bb4aR863.

I can return back size_t * and add temporary helper variable, if it will be better.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can return back size_t * and add temporary helper variable, if it will be better.

Please do so.

Comment thread core/tee/tee_supp_plugin_rpc.c Outdated
memcpy(va, buf, len);
}

plugin_uuid = (uint32_t *)uuid;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe you need to do something like:

uint32_t uuid_words[4] = { };
tee_uuid_to_octets(uuid_words, uuid);

Secure world is always in little endian so there's no need for any more byte swapping.

Later when decoding this in tee-supplicant you'd do something like:

TEEC_UUID uuid = { };
uint32_t uuid_words[4] = { };

uuid_words[0] = from_le32(params[0].b);
...
tee_uuid_from_octets(&uuid, (void *)uuid_words);

This should work for both a big and little endian normal world. Other parts in the chain (driver) are missing so a big endian normal world wouldn't work for other reasons, but we shouldn't make it harder than necessary in case we'd ever fix that.

Do it make sense?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it make sense. I added le32toh() to tee-supplicant when decoding uuid_words[].

Comment thread core/include/optee_rpc_cmd.h Outdated
* [out] value[2].b length of the outbuf (memref[3]), if out is needed.
* [in/out] memref[3] buffer holding data for plugin
*
* Serialized bytes of the TEE_UUID:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be more clear to say: "UUID serialized into octets".

This is not to be confused with the in memory representation of TEE_UUID.

@anisyanka

Copy link
Copy Markdown
Contributor Author

All comments have been addressed

@jenswikl

Copy link
Copy Markdown
Contributor

Reviewed-by: Jens Wiklander <jens.wiklander@linaro.org>

Aleksandr Anisimov added 2 commits January 25, 2021 12:15
Any external TEE services can be designed as a tee-supplicant plugin.
The plugins will be loaded by the supplicant during startup process
using libdl.
It makes it easy to:
 - add new features in the supplicant that aren't needed in upstream,
   e.g. Rich OS specific services;
 - sync upstream version with own fork;

This patch adds a new RPC - 'OPTEE_RPC_CMD_SUPP_PLUGIN' as an unified
interface between OP-TEE and any plugins. Kernel code can use it
to call for execution of some command in plugins.

Every plugin has own name based on UUID.
OP-TEE has access to plugins by it.

See definition of protocol for the plugin RPC command
in 'core/include/optee_rpc_cmd.h' file.

Signed-off-by: Aleksandr Anisimov <a.anisimov@omprussia.ru>
Reviewed-by: Jens Wiklander <jens.wiklander@linaro.org>
This patch adds a new API to libutee to interact
with tee-supplicant plugins from TEE userspace.

Every user TA can use 'tee_invoke_supp_plugin()' to send any commands
to a plugin. The commands are predefined by the plugin developer.

See the https://github.com/linaro-swg/optee_examples
repo for an example of using plugins.

Signed-off-by: Aleksandr Anisimov <a.anisimov@omprussia.ru>
Reviewed-by: Jens Wiklander <jens.wiklander@linaro.org>
@anisyanka

Copy link
Copy Markdown
Contributor Author

The commits reworded.
Thank you for the review!

@jforissier
jforissier merged commit e4ad5cc into OP-TEE:master Feb 4, 2021
@jforissier

Copy link
Copy Markdown
Contributor

@anisyanka thanks for your contribution.

@anisyanka
anisyanka deleted the plugin-pta branch February 4, 2021 15:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants