core: add new PRC and PTA for loadable plugins framework - #4248
Conversation
jforissier
left a comment
There was a problem hiding this comment.
Hi @anisyanka,
Thanks for the patches. Please see my comments below.
| #define OPTEE_RPC_CMD_FTRACE 11 | ||
|
|
||
| /* | ||
| * Plugin command, see definition of protocol below |
There was a problem hiding this comment.
tee-supplicant plugin command ...
| /* | ||
| * Plugin command, see definition of protocol below | ||
| */ | ||
| #define OPTEE_RPC_CMD_PLUGIN 12 |
There was a problem hiding this comment.
OPTEE_RPC_CMD_SUPP_PLUGIN
| * [in] value[2].a sub_cmd for plugin | ||
| * [in] memref[3] buffer holding data for plugin | ||
| */ | ||
| #define OPTEE_INVOKE_PLUGIN 0 |
There was a problem hiding this comment.
For consistency: OPTEE_RPC_SUPP_PLUGIN_INVOKE
| * [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 |
There was a problem hiding this comment.
Any chance one would need to return data back to secure world? ([in/out]).
There was a problem hiding this comment.
I think such cases are possible and we should provide the [in/out] ability, thanks
| * 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); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
wow, I will try to use the tee_uuid_from_str() from libutee :)
In this case I will drop own implementation.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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).
There was a problem hiding this comment.
OK, got it, thanks!
| #include <tee_api_types.h> | ||
|
|
||
| struct tee_plugin_rpc_operation { | ||
| const char *name; /* string "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" */ |
|
|
||
| srcs-y += uuid.c | ||
| srcs-y += tee_ta_enc_manager.c | ||
| srcs-y += tee_plugin_rpc.c No newline at end of file |
| #include <stdint.h> | ||
| #include <tee_api_types.h> | ||
|
|
||
| struct tee_plugin_rpc_operation { |
There was a problem hiding this comment.
"supplicant" is missing here, struct supp_plugin_rpc_op maybe?
And filename could be supp_plugin_rpc.h.
|
|
||
| res = tee_uuid_from_string(&u, op->name, strlen(op->name)); | ||
| if (res) { | ||
| EMSG("can't convert string <%s> to UUID", op->name); |
There was a problem hiding this comment.
You wouldn't need to care about this if you used TEE_UUID.
| srcs-$(CFG_WITH_STATS) += stats.c | ||
| srcs-$(CFG_SYSTEM_PTA) += system.c | ||
| srcs-$(CFG_NXP_SE05X) += scp03.c | ||
| srcs-$(CFG_PLUGIN_PTA) += plugin.c |
There was a problem hiding this comment.
CFG_SUPP_PLUGIN_PTA += supp_plugin.c
|
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:
|
jenswikl
left a comment
There was a problem hiding this comment.
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.
| goto out; | ||
| } | ||
|
|
||
| memcpy(&plug_uuid, &u, sizeof(TEE_UUID)); |
There was a problem hiding this comment.
I believe tee_uuid_to_octets() would be a better choice in order to get the correct byte order.
| uint32_t d2; | ||
| uint32_t d3; | ||
| uint32_t d4; | ||
| } plug_uuid; |
There was a problem hiding this comment.
It seems like uint32_t plug_uuid[4] = { }; would be just as useful and a bit simpler.
|
|
||
| memcpy(&plug_uuid, &u, sizeof(TEE_UUID)); | ||
|
|
||
| struct thread_param params[THREAD_RPC_MAX_NUM_PARAMS] = { |
There was a problem hiding this comment.
Declarations of variables at the start of the block please.
| * [in] value[1].b sub_command for plugin | ||
| * [in] memref[2] additional data for plugin | ||
| */ | ||
| #define PTA_PLUGIN_INVOKE 0 |
There was a problem hiding this comment.
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);| * [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 |
There was a problem hiding this comment.
Shouldn't this be in and out?
Sounds good. I will move |
|
All comments have been addressed |
| */ | ||
|
|
||
| #ifndef TEE_PLUGIN_RPC_H | ||
| #define TEE_PLUGIN_RPC_H |
| static TEE_Result system_supp_plugin_invoke(uint32_t param_types, | ||
| TEE_Param params[TEE_NUM_PARAMS]) | ||
| { | ||
| struct tee_supp_plugin_rpc_op op; |
| #include <tee/tee_supp_plugin_rpc.h> | ||
| #include <tee/uuid.h> | ||
| #include <trace.h> | ||
| #include <mm/mobj.h> |
| { | ||
| TEE_Result res = TEE_ERROR_GENERIC; | ||
| struct thread_param params[THREAD_RPC_MAX_NUM_PARAMS]; | ||
| uint32_t plugin_uuid[4]; |
| uint32_t plugin_uuid[4]; | ||
| void *va = NULL; | ||
| struct mobj *mobj = NULL; | ||
| uint32_t outlen; |
| res = invoke_system_pta(PTA_SYSTEM_SUPP_PLUGIN_INVOKE, param_types, | ||
| params); | ||
| if (res) | ||
| EMSG("Invoke tee-supplicant's plugin failed"); |
There was a problem hiding this comment.
I would make it a DMSG():
DMSG("Invoke tee-supplicant's plugin failed: %#"PRIx32, res);There was a problem hiding this comment.
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.
| /* | ||
| * Invoke a tee-supplicant's plugin | ||
| * | ||
| * [in] memref[0] uuid(octets) of the plugin |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
Should this be an out parameter too, in case the size is smaller when returning some result?
There was a problem hiding this comment.
I think yes.
We can replace size_t len to size_t *len and use one pointer to input and output length.
| #include <trace.h> | ||
| #include <mm/mobj.h> | ||
|
|
||
| TEE_Result tee_invoke_supp_plugin_rpc(struct tee_supp_plugin_rpc_op *op) |
There was a problem hiding this comment.
Why is this function taking a struct tee_supp_plugin_rpc_op only used for this purpose instead of separate parameters?
There was a problem hiding this comment.
I think we can use separate parameters here. Ok, I will drop tee_supp_plugin_rpc_op
|
All comments have been addressed |
| params[1].value.b, /* sub_cmd */ | ||
| params[2].memref.buffer, /* data */ | ||
| params[2].memref.size, /* in len */ | ||
| (size_t *)¶ms[3].value.a |
There was a problem hiding this comment.
This cast isn't portable.
There was a problem hiding this comment.
Yes, you are right. I will fix it
There was a problem hiding this comment.
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().
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
I can return back size_t * and add temporary helper variable, if it will be better.
Please do so.
| memcpy(va, buf, len); | ||
| } | ||
|
|
||
| plugin_uuid = (uint32_t *)uuid; |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
Yes, it make sense. I added le32toh() to tee-supplicant when decoding uuid_words[].
| * [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: |
There was a problem hiding this comment.
Might be more clear to say: "UUID serialized into octets".
This is not to be confused with the in memory representation of TEE_UUID.
|
All comments have been addressed |
|
|
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>
|
The commits reworded. |
|
@anisyanka thanks for your contribution. |
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:
e.g. Rich OS specific services;
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