From: Volodymyr Babchuk <Volodymyr_Babchuk@epam.com>
To: Julien Grall <julien.grall@arm.com>
Cc: "tee-dev@lists.linaro.org" <tee-dev@lists.linaro.org>,
"xen-devel@lists.xenproject.org" <xen-devel@lists.xenproject.org>,
Stefano Stabellini <sstabellini@kernel.org>,
Volodymyr Babchuk <Volodymyr_Babchuk@epam.com>
Subject: Re: [Xen-devel] [PATCH 4/5] xen/arm: optee: handle share buffer translation error
Date: Wed, 11 Sep 2019 18:32:28 +0000 [thread overview]
Message-ID: <87mufafzus.fsf@epam.com> (raw)
In-Reply-To: <53631114-2bb1-18a8-615d-3768facdcc78@arm.com>
Julien Grall writes:
> Hi Volodymyr,
>
> On 8/23/19 7:48 PM, Volodymyr Babchuk wrote:
>> There is a case possible, when OP-TEE asks guest to allocate shared
>> buffer, but Xen for some reason can't translate buffer's addresses. In
>> this situation we should do two things:
>>
>> 1. Tell guest to free allocated buffer, so there will be no memory
>> leak for guest.
>>
>> 2. Tell OP-TEE that buffer allocation failed.
>>
>> To ask guest to free allocated buffer we should perform the same
>> thing, as OP-TEE does - issue RPC request. This is done by filling
>> request buffer (luckily we can reuse the same buffer, that OP-TEE used
>> to issue original request) and then return to guest with special
>> return code.
>>
>> Then we need to handle next call from guest in a special way: as RPC
>> was issued by Xen, not by OP-TEE, it should be handled by Xen.
>> Basically, this is the mechanism to preempt OP-TEE mediator.
>>
>> The same mechanism can be used in the future to preempt mediator
>> during translation large (>512 pages) shared buffers.
>>
>> Signed-off-by: Volodymyr Babchuk <volodymyr_babchuk@epam.com>
>> ---
>> xen/arch/arm/tee/optee.c | 167 +++++++++++++++++++++++++++++++--------
>> 1 file changed, 136 insertions(+), 31 deletions(-)
>>
>> diff --git a/xen/arch/arm/tee/optee.c b/xen/arch/arm/tee/optee.c
>> index 3ce6e7fa55..4eebc60b62 100644
>> --- a/xen/arch/arm/tee/optee.c
>> +++ b/xen/arch/arm/tee/optee.c
>> @@ -96,6 +96,11 @@
>> OPTEE_SMC_SEC_CAP_UNREGISTERED_SHM | \
>> OPTEE_SMC_SEC_CAP_DYNAMIC_SHM)
>> +enum optee_call_state {
>> + OPTEEM_CALL_NORMAL = 0,
>
> enum always start counting at 0. Also, looking at the code, it does
> not seem you need to know the value. Right?
Yep. This is a bad habit. Will remove.
>
>> + OPTEEM_CALL_XEN_RPC,
>
> I am a bit confused, the enum is called optee_call_state but all the
> enum are prefixed with OPTEEM_CALL_. Why the discrepancy?
Because I'm bad at naming things :)
OPTEEM_CALL_STATE_XEN_RPC looks too long. But you are right, so I'll
rename the enum values. Unless, you have a better idea for this.
>
>> +};
>> +
>> static unsigned int __read_mostly max_optee_threads;
>> /*
>> @@ -112,6 +117,9 @@ struct optee_std_call {
>> paddr_t guest_arg_ipa;
>> int optee_thread_id;
>> int rpc_op;
>> + /* Saved buffer type for the last buffer allocate request */
>
> Looking at the code, it feels to me you are saving the buffer type for
> the current command and not the last. Did I miss anything?
Yes, right. Will rename.
>> + unsigned int rpc_buffer_type;
>> + enum optee_call_state state;
>> uint64_t rpc_data_cookie;
>> bool in_flight;
>> register_t rpc_params[2];
>> @@ -299,6 +307,7 @@ static struct optee_std_call *allocate_std_call(struct optee_domain *ctx)
>> call->optee_thread_id = -1;
>> call->in_flight = true;
>> + call->state = OPTEEM_CALL_NORMAL;
>> spin_lock(&ctx->lock);
>> list_add_tail(&call->list, &ctx->call_list);
>> @@ -1075,6 +1084,10 @@ static int handle_rpc_return(struct optee_domain *ctx,
>> ret = -ERESTART;
>> }
>> + /* Save the buffer type in case we will want to free it
>> */
>> + if ( shm_rpc->xen_arg->cmd == OPTEE_RPC_CMD_SHM_ALLOC )
>> + call->rpc_buffer_type = shm_rpc->xen_arg->params[0].u.value.a;
>> +
>> unmap_domain_page(shm_rpc->xen_arg);
>> }
>> @@ -1239,18 +1252,102 @@ err:
>> return;
>> }
>> +/*
>> + * Prepare RPC request to free shared buffer in the same way, as
>> + * OP-TEE does this.
>> + *
>> + * Return values:
>> + * true - successfully prepared RPC request
>> + * false - there was an error
>> + */
>> +static bool issue_rpc_cmd_free(struct optee_domain *ctx,
>> + struct cpu_user_regs *regs,
>> + struct optee_std_call *call,
>> + struct shm_rpc *shm_rpc,
>> + uint64_t cookie)
>> +{
>> + register_t r1, r2;
>> +
>> + /* In case if guest will forget to update it with meaningful value */
>> + shm_rpc->xen_arg->ret = TEEC_ERROR_GENERIC;
>> + shm_rpc->xen_arg->cmd = OPTEE_RPC_CMD_SHM_FREE;
>> + shm_rpc->xen_arg->num_params = 1;
>> + shm_rpc->xen_arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT;
>> + shm_rpc->xen_arg->params[0].u.value.a = call->rpc_buffer_type;
>> + shm_rpc->xen_arg->params[0].u.value.b = cookie;
>> +
>> + if ( access_guest_memory_by_ipa(current->domain,
>> + gfn_to_gaddr(shm_rpc->gfn),
>> + shm_rpc->xen_arg,
>> + OPTEE_MSG_GET_ARG_SIZE(1),
>> + true) )
>> + {
>> + /*
>> + * Well, this is quite bad. We have error in error path.
>> + * This can happen only if guest behaves badly, so all
>> + * we can do is to return error to OP-TEE and leave
>> + * guest's memory leaked.
>
> Could you expand a bit more what you mean by "guest's memory leaked"?
There will be memory leak somewhere in the guest. Yes, looks
like it is misleading...
What I mean, is that OP-TEE requests guest to allocate some
memory. Guest does not know, when OP-TEE finishes using this memory, so
guest will free the memory only by OP-TEE's request. We can't emulate
this request in current circumstances, so guest will keep part of own
memory reserved for OP-TEE infinitely.
> What the state of the page from Xen PoV?
From Xen point of view all will be perfectly fine.
> I.e. is there any reference
> taken by the OP-TEE mediator? Will the page be freed once the guest is
> destroyed?...
As I said, it has nothing to do with the page as Xen it sees. Mediator
will call put_page() prior to entering this function. So, no Xen
resources are used.
>
>> + */
>> + shm_rpc->xen_arg->ret = TEEC_ERROR_GENERIC;
>> + shm_rpc->xen_arg->num_params = 0;
>> +
>> + return false;
>> + }
>> +
>> + uint64_to_regpair(&r1, &r2, shm_rpc->cookie);
>> +
>> + call->state = OPTEEM_CALL_XEN_RPC;
>> + call->rpc_op = OPTEE_SMC_RPC_FUNC_CMD;
>> + call->rpc_params[0] = r1;
>> + call->rpc_params[1] = r2;
>> + call->optee_thread_id = get_user_reg(regs, 3);
>> +
>> + set_user_reg(regs, 0, OPTEE_SMC_RETURN_RPC_CMD);
>> + set_user_reg(regs, 1, r1);
>> + set_user_reg(regs, 2, r2);
>> +
>> + return true;
>> +}
>> +
>> +/* Handles return from Xen-issued RPC */
>> +static void handle_xen_rpc_return(struct optee_domain *ctx,
>> + struct cpu_user_regs *regs,
>> + struct optee_std_call *call,
>> + struct shm_rpc *shm_rpc)
>> +{
>> + call->state = OPTEEM_CALL_NORMAL;
>> +
>> + /*
>> + * Right now we have only one reason to be there - we asked guest
>> + * to free shared buffer and it did it. Now we can tell OP-TEE that
>> + * buffer allocation failed.
>> + */
>
> Should we add an ASSERT to ensure the command is the one we expect?
It is strange, that it is missing, actually. Looks like I forgot to add
it. But, looking at xen-error-handling, maybe BOG_ON() would be better?
>> +
>> + /*
>> + * We are not checking return value from a guest because we assume
>> + * that OPTEE_RPC_CMD_SHM_FREE newer fails.
>
> s/newer/never/
Oops. Thank you.
>> + */
>> +
>> + shm_rpc->xen_arg->ret = TEEC_ERROR_GENERIC;
>> + shm_rpc->xen_arg->num_params = 0;
>> +}
>> +
>> /*
>> * This function is called when guest is finished processing RPC
>> * request from OP-TEE and wished to resume the interrupted standard
>> * call.
>> + *
>> + * Return values:
>> + * false - there was an error, do not call OP-TEE
>> + * true - success, proceed as normal
>> */
>> -static void handle_rpc_cmd_alloc(struct optee_domain *ctx,
>> +static bool handle_rpc_cmd_alloc(struct optee_domain *ctx,
>> struct cpu_user_regs *regs,
>> struct optee_std_call *call,
>> struct shm_rpc *shm_rpc)
>> {
>> if ( shm_rpc->xen_arg->ret || shm_rpc->xen_arg->num_params != 1 )
>> - return;
>> + return true;
>> if ( shm_rpc->xen_arg->params[0].attr !=
>> (OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT |
>> OPTEE_MSG_ATTR_NONCONTIG) )
>> @@ -1258,7 +1355,7 @@ static void handle_rpc_cmd_alloc(struct optee_domain *ctx,
>> gdprintk(XENLOG_WARNING,
>> "Invalid attrs for shared mem buffer: %"PRIx64"\n",
>> shm_rpc->xen_arg->params[0].attr);
>> - return;
>> + return true;
>> }
>> /* Free pg list for buffer */
>> @@ -1274,21 +1371,14 @@ static void handle_rpc_cmd_alloc(struct optee_domain *ctx,
>> {
>> call->rpc_data_cookie = 0;
>> /*
>> - * Okay, so there was problem with guest's buffer and we need
>> - * to tell about this to OP-TEE.
>> - */
>> - shm_rpc->xen_arg->ret = TEEC_ERROR_GENERIC;
>> - shm_rpc->xen_arg->num_params = 0;
>> - /*
>> - * TODO: With current implementation, OP-TEE will not issue
>> - * RPC to free this buffer. Guest and OP-TEE will be out of
>> - * sync: guest believes that it provided buffer to OP-TEE,
>> - * while OP-TEE thinks of opposite. Ideally, we need to
>> - * emulate RPC with OPTEE_MSG_RPC_CMD_SHM_FREE command.
>> + * We are unable to translate guest's buffer, so we need tell guest
>> + * to free it, before returning error to OP-TEE.
>
> Do you mean "reporting" instead of "returning"?
Yes, I do.
> Also s/error/an error/
Sure. Thank you.
--
Volodymyr Babchuk at EPAM
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel
next prev parent reply other threads:[~2019-09-11 18:33 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-08-23 18:48 [Xen-devel] [PATCH 0/5] arch/arm: optee: fix TODOs and remove "experimental" status Volodymyr Babchuk
2019-08-23 18:48 ` [Xen-devel] [PATCH 1/5] xen/arm: optee: impose limit on shared buffer size Volodymyr Babchuk
2019-09-09 22:11 ` Julien Grall
2019-09-11 18:48 ` Volodymyr Babchuk
2019-09-12 19:32 ` Julien Grall
2019-09-12 19:45 ` Volodymyr Babchuk
2019-09-12 19:51 ` Julien Grall
2019-09-16 15:26 ` Volodymyr Babchuk
2019-09-17 10:49 ` Julien Grall
2019-09-17 12:28 ` Volodymyr Babchuk
2019-09-17 18:46 ` Julien Grall
2019-08-23 18:48 ` [Xen-devel] [PATCH 2/5] xen/arm: optee: check for preemption while freeing shared buffers Volodymyr Babchuk
2019-09-09 22:19 ` Julien Grall
2019-09-11 18:53 ` Volodymyr Babchuk
2019-09-12 19:39 ` Julien Grall
2019-09-12 19:47 ` Volodymyr Babchuk
2019-08-23 18:48 ` [Xen-devel] [PATCH 3/5] xen/arm: optee: limit number of " Volodymyr Babchuk
2019-08-23 18:48 ` [Xen-devel] [PATCH 4/5] xen/arm: optee: handle share buffer translation error Volodymyr Babchuk
2019-09-10 11:17 ` Julien Grall
2019-09-11 18:32 ` Volodymyr Babchuk [this message]
2019-09-12 18:55 ` Julien Grall
2019-08-23 18:48 ` [Xen-devel] [PATCH 5/5] xen/arm: optee: remove experimental status Volodymyr Babchuk
2019-08-23 19:05 ` Julien Grall
2019-08-23 19:20 ` Volodymyr Babchuk
2019-09-09 21:31 ` Julien Grall
2019-09-11 18:41 ` Volodymyr Babchuk
2019-09-12 19:00 ` Julien Grall
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87mufafzus.fsf@epam.com \
--to=volodymyr_babchuk@epam.com \
--cc=julien.grall@arm.com \
--cc=sstabellini@kernel.org \
--cc=tee-dev@lists.linaro.org \
--cc=xen-devel@lists.xenproject.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.