Update from upstream to 2.4.0 version
[platform/core/security/tef-optee_os.git] / core / arch / arm / kernel / pseudo_ta.c
1 /*
2  * Copyright (c) 2014, STMicroelectronics International N.V.
3  * Copyright (c) 2015, Linaro Limited
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright notice,
10  * this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright notice,
13  * this list of conditions and the following disclaimer in the documentation
14  * and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 #include <initcall.h>
29 #include <kernel/panic.h>
30 #include <kernel/pseudo_ta.h>
31 #include <kernel/tee_ta_manager.h>
32 #include <mm/core_memprot.h>
33 #include <mm/mobj.h>
34 #include <sm/tee_mon.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <trace.h>
38 #include <types_ext.h>
39
40 #ifdef CFG_SECURE_DATA_PATH
41 static bool client_is_secure(struct tee_ta_session *s)
42 {
43         /* rely on core entry to have constrained client IDs */
44         if (s->clnt_id.login == TEE_LOGIN_TRUSTED_APP)
45                 return true;
46
47         return false;
48 }
49
50 static bool validate_in_param(struct tee_ta_session *s, struct mobj *mobj)
51 {
52         /* for secure clients, core entry always holds valid memref objects */
53         if (client_is_secure(s))
54                 return true;
55
56         /* all non-secure memory references are hanlded by pTAs */
57         if (mobj_is_nonsec(mobj))
58                 return true;
59
60         return false;
61 }
62 #else
63 static bool validate_in_param(struct tee_ta_session *s __unused,
64                                 struct mobj *mobj __unused)
65 {
66         /* At this point, core has filled only valid accessible memref mobj */
67         return true;
68 }
69 #endif
70
71 /* Maps static TA params */
72 static TEE_Result copy_in_param(struct tee_ta_session *s __maybe_unused,
73                                 struct tee_ta_param *param,
74                                 TEE_Param tee_param[TEE_NUM_PARAMS])
75 {
76         size_t n;
77         void *va;
78
79         for (n = 0; n < TEE_NUM_PARAMS; n++) {
80                 switch (TEE_PARAM_TYPE_GET(param->types, n)) {
81                 case TEE_PARAM_TYPE_VALUE_INPUT:
82                 case TEE_PARAM_TYPE_VALUE_OUTPUT:
83                 case TEE_PARAM_TYPE_VALUE_INOUT:
84                         tee_param[n].value.a = param->u[n].val.a;
85                         tee_param[n].value.b = param->u[n].val.b;
86                         break;
87                 case TEE_PARAM_TYPE_MEMREF_INPUT:
88                 case TEE_PARAM_TYPE_MEMREF_OUTPUT:
89                 case TEE_PARAM_TYPE_MEMREF_INOUT:
90                         if (!validate_in_param(s, param->u[n].mem.mobj))
91                                 return TEE_ERROR_BAD_PARAMETERS;
92
93                         va = mobj_get_va(param->u[n].mem.mobj,
94                                          param->u[n].mem.offs);
95                         if (!va)
96                                 return TEE_ERROR_BAD_PARAMETERS;
97                         tee_param[n].memref.buffer = va;
98                         tee_param[n].memref.size = param->u[n].mem.size;
99                         break;
100                 default:
101                         memset(tee_param + n, 0, sizeof(TEE_Param));
102                         break;
103                 }
104         }
105
106         return TEE_SUCCESS;
107 }
108
109 static void update_out_param(TEE_Param tee_param[TEE_NUM_PARAMS],
110                              struct tee_ta_param *param)
111 {
112         size_t n;
113
114         for (n = 0; n < TEE_NUM_PARAMS; n++) {
115                 switch (TEE_PARAM_TYPE_GET(param->types, n)) {
116                 case TEE_PARAM_TYPE_VALUE_OUTPUT:
117                 case TEE_PARAM_TYPE_VALUE_INOUT:
118                         param->u[n].val.a = tee_param[n].value.a;
119                         param->u[n].val.b = tee_param[n].value.b;
120                         break;
121                 case TEE_PARAM_TYPE_MEMREF_OUTPUT:
122                 case TEE_PARAM_TYPE_MEMREF_INOUT:
123                         param->u[n].mem.size = tee_param[n].memref.size;
124                         break;
125                 default:
126                         break;
127                 }
128         }
129 }
130
131 static TEE_Result pseudo_ta_enter_open_session(struct tee_ta_session *s,
132                         struct tee_ta_param *param, TEE_ErrorOrigin *eo)
133 {
134         TEE_Result res = TEE_SUCCESS;
135         struct pseudo_ta_ctx *stc = to_pseudo_ta_ctx(s->ctx);
136         TEE_Param tee_param[TEE_NUM_PARAMS];
137
138         tee_ta_push_current_session(s);
139         *eo = TEE_ORIGIN_TRUSTED_APP;
140
141         if ((s->ctx->ref_count == 1) && stc->pseudo_ta->create_entry_point) {
142                 res = stc->pseudo_ta->create_entry_point();
143                 if (res != TEE_SUCCESS)
144                         goto out;
145         }
146
147         if (stc->pseudo_ta->open_session_entry_point) {
148                 res = copy_in_param(s, param, tee_param);
149                 if (res != TEE_SUCCESS) {
150                         *eo = TEE_ORIGIN_TEE;
151                         goto out;
152                 }
153
154                 res = stc->pseudo_ta->open_session_entry_point(param->types,
155                                                                 tee_param,
156                                                                 &s->user_ctx);
157                 update_out_param(tee_param, param);
158         }
159
160 out:
161         tee_ta_pop_current_session();
162         return res;
163 }
164
165 static TEE_Result pseudo_ta_enter_invoke_cmd(struct tee_ta_session *s,
166                         uint32_t cmd, struct tee_ta_param *param,
167                         TEE_ErrorOrigin *eo)
168 {
169         TEE_Result res;
170         struct pseudo_ta_ctx *stc = to_pseudo_ta_ctx(s->ctx);
171         TEE_Param tee_param[TEE_NUM_PARAMS];
172
173         tee_ta_push_current_session(s);
174         res = copy_in_param(s, param, tee_param);
175         if (res != TEE_SUCCESS) {
176                 *eo = TEE_ORIGIN_TEE;
177                 goto out;
178         }
179
180         *eo = TEE_ORIGIN_TRUSTED_APP;
181         res = stc->pseudo_ta->invoke_command_entry_point(s->user_ctx, cmd,
182                                                          param->types,
183                                                          tee_param);
184         update_out_param(tee_param, param);
185 out:
186         tee_ta_pop_current_session();
187         return res;
188 }
189
190 static void pseudo_ta_enter_close_session(struct tee_ta_session *s)
191 {
192         struct pseudo_ta_ctx *stc = to_pseudo_ta_ctx(s->ctx);
193
194         tee_ta_push_current_session(s);
195
196         if (stc->pseudo_ta->close_session_entry_point)
197                 stc->pseudo_ta->close_session_entry_point(s->user_ctx);
198
199         if ((s->ctx->ref_count == 1) && stc->pseudo_ta->destroy_entry_point)
200                 stc->pseudo_ta->destroy_entry_point();
201
202         tee_ta_pop_current_session();
203 }
204
205 static void pseudo_ta_destroy(struct tee_ta_ctx *ctx)
206 {
207         free(to_pseudo_ta_ctx(ctx));
208 }
209
210 static const struct tee_ta_ops pseudo_ta_ops = {
211         .enter_open_session = pseudo_ta_enter_open_session,
212         .enter_invoke_cmd = pseudo_ta_enter_invoke_cmd,
213         .enter_close_session = pseudo_ta_enter_close_session,
214         .destroy = pseudo_ta_destroy,
215 };
216
217
218 /* Defined in link script */
219 extern const struct pseudo_ta_head __start_ta_head_section;
220 extern const struct pseudo_ta_head __stop_ta_head_section;
221
222 /* Insures declared pseudo TAs conforms with core expectations */
223 static TEE_Result verify_pseudo_tas_conformance(void)
224 {
225         const struct pseudo_ta_head *start = &__start_ta_head_section;
226         const struct pseudo_ta_head *end = &__stop_ta_head_section;
227         const struct pseudo_ta_head *pta;
228
229         for (pta = start; pta < end; pta++) {
230                 const struct pseudo_ta_head *pta2;
231
232                 /* PTAs must all have a specific UUID */
233                 for (pta2 = pta + 1; pta2 < end; pta2++)
234                         if (!memcmp(&pta->uuid, &pta2->uuid, sizeof(TEE_UUID)))
235                                 goto err;
236
237                 if (!pta->name ||
238                     (pta->flags & PTA_MANDATORY_FLAGS) != PTA_MANDATORY_FLAGS ||
239                     pta->flags & ~PTA_ALLOWED_FLAGS ||
240                     !pta->invoke_command_entry_point)
241                         goto err;
242         }
243         return TEE_SUCCESS;
244 err:
245         DMSG("pseudo TA error at %p", (void *)pta);
246         panic("pta");
247 }
248
249 service_init(verify_pseudo_tas_conformance);
250
251 /*-----------------------------------------------------------------------------
252  * Initialises a session based on the UUID or ptr to the ta
253  * Returns ptr to the session (ta_session) and a TEE_Result
254  *---------------------------------------------------------------------------*/
255 TEE_Result tee_ta_init_pseudo_ta_session(const TEE_UUID *uuid,
256                         struct tee_ta_session *s)
257 {
258         struct pseudo_ta_ctx *stc = NULL;
259         struct tee_ta_ctx *ctx;
260         const struct pseudo_ta_head *ta;
261
262         DMSG("   Lookup for pseudo TA %pUl", (void *)uuid);
263
264         ta = &__start_ta_head_section;
265         while (true) {
266                 if (ta >= &__stop_ta_head_section)
267                         return TEE_ERROR_ITEM_NOT_FOUND;
268                 if (memcmp(&ta->uuid, uuid, sizeof(TEE_UUID)) == 0)
269                         break;
270                 ta++;
271         }
272
273         /* Load a new TA and create a session */
274         DMSG("      Open %s", ta->name);
275         stc = calloc(1, sizeof(struct pseudo_ta_ctx));
276         if (!stc)
277                 return TEE_ERROR_OUT_OF_MEMORY;
278         ctx = &stc->ctx;
279
280         ctx->ref_count = 1;
281         s->ctx = ctx;
282         ctx->flags = ta->flags;
283         stc->pseudo_ta = ta;
284         ctx->uuid = ta->uuid;
285         ctx->ops = &pseudo_ta_ops;
286         TAILQ_INSERT_TAIL(&tee_ctxes, ctx, link);
287
288         DMSG("      %s : %pUl", stc->pseudo_ta->name, (void *)&ctx->uuid);
289
290         return TEE_SUCCESS;
291 }