1 // SPDX-License-Identifier: BSD-2-Clause
2 /* Copyright (c) 2018, Linaro Limited */
3
4 #include <ta_avb.h>
5 #include <tee_internal_api.h>
6 #include <tee_internal_api_extensions.h>
7
8 #include <string.h>
9
10 #define DEFAULT_LOCK_STATE 0
11
12 static const uint32_t storageid = TEE_STORAGE_PRIVATE_RPMB;
13 static const char rb_obj_name[] = "rb_state";
14 static const char *named_value_prefix = "named_value_";
15
get_slot_offset(size_t slot,size_t * offset)16 static TEE_Result get_slot_offset(size_t slot, size_t *offset)
17 {
18 if (slot >= TA_AVB_MAX_ROLLBACK_LOCATIONS)
19 return TEE_ERROR_BAD_PARAMETERS;
20
21 *offset = sizeof(uint32_t) /* lock_state */ + slot * sizeof(uint64_t);
22 return TEE_SUCCESS;
23 }
24
create_rb_state(uint32_t lock_state,TEE_ObjectHandle * h)25 static TEE_Result create_rb_state(uint32_t lock_state, TEE_ObjectHandle *h)
26 {
27 const uint32_t flags = TEE_DATA_FLAG_ACCESS_READ |
28 TEE_DATA_FLAG_ACCESS_WRITE |
29 TEE_DATA_FLAG_OVERWRITE;
30
31 return TEE_CreatePersistentObject(storageid, rb_obj_name,
32 sizeof(rb_obj_name), flags, NULL,
33 &lock_state, sizeof(lock_state), h);
34 }
35
open_rb_state(uint32_t default_lock_state,TEE_ObjectHandle * h)36 static TEE_Result open_rb_state(uint32_t default_lock_state,
37 TEE_ObjectHandle *h)
38 {
39 uint32_t flags = TEE_DATA_FLAG_ACCESS_READ |
40 TEE_DATA_FLAG_ACCESS_WRITE;
41 TEE_Result res;
42
43 res = TEE_OpenPersistentObject(storageid, rb_obj_name,
44 sizeof(rb_obj_name), flags, h);
45 if (!res)
46 return TEE_SUCCESS;
47
48 return create_rb_state(default_lock_state, h);
49 }
50
get_named_object_name(char * name_orig,uint32_t name_orig_size,char * name,uint32_t * name_size)51 static TEE_Result get_named_object_name(char *name_orig,
52 uint32_t name_orig_size,
53 char *name, uint32_t *name_size)
54 {
55 size_t pref_len = strlen(named_value_prefix);
56
57 if (name_orig_size + pref_len >
58 TEE_OBJECT_ID_MAX_LEN)
59 return TEE_ERROR_BAD_PARAMETERS;
60
61 /* Start with prefix */
62 TEE_MemMove(name, named_value_prefix, pref_len);
63
64 /* Concatenate provided object name */
65 TEE_MemMove(name + pref_len, name_orig, name_orig_size);
66
67 *name_size = name_orig_size + pref_len;
68
69 return TEE_SUCCESS;
70 }
71
read_rb_idx(uint32_t pt,TEE_Param params[TEE_NUM_PARAMS])72 static TEE_Result read_rb_idx(uint32_t pt, TEE_Param params[TEE_NUM_PARAMS])
73 {
74 const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
75 TEE_PARAM_TYPE_VALUE_OUTPUT,
76 TEE_PARAM_TYPE_NONE,
77 TEE_PARAM_TYPE_NONE);
78 size_t slot_offset;
79 uint64_t idx;
80 size_t count;
81 TEE_Result res;
82 TEE_ObjectHandle h;
83
84 if (pt != exp_pt)
85 return TEE_ERROR_BAD_PARAMETERS;
86
87 res = get_slot_offset(params[0].value.a, &slot_offset);
88 if (res)
89 return res;
90
91 res = open_rb_state(DEFAULT_LOCK_STATE, &h);
92 if (res)
93 return res;
94
95 res = TEE_SeekObjectData(h, slot_offset, TEE_DATA_SEEK_SET);
96 if (res)
97 goto out;
98
99 res = TEE_ReadObjectData(h, &idx, sizeof(idx), &count);
100 if (res)
101 goto out;
102 if (count != sizeof(idx)) {
103 idx = 0; /* Not yet written slots are reported as 0 */
104
105 if (count) {
106 /*
107 * Somehow the file didn't even hold a complete
108 * slot index entry. Write it as 0.
109 */
110 res = TEE_SeekObjectData(h, slot_offset,
111 TEE_DATA_SEEK_SET);
112 if (res)
113 goto out;
114 res = TEE_WriteObjectData(h, &idx, sizeof(idx));
115 if (res)
116 goto out;
117 }
118 }
119
120 params[1].value.a = idx >> 32;
121 params[1].value.b = idx;
122 out:
123 TEE_CloseObject(h);
124 return res;
125 }
126
write_rb_idx(uint32_t pt,TEE_Param params[TEE_NUM_PARAMS])127 static TEE_Result write_rb_idx(uint32_t pt, TEE_Param params[TEE_NUM_PARAMS])
128 {
129 const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
130 TEE_PARAM_TYPE_VALUE_INPUT,
131 TEE_PARAM_TYPE_NONE,
132 TEE_PARAM_TYPE_NONE);
133 size_t slot_offset;
134 uint64_t widx;
135 uint64_t idx;
136 size_t count;
137 TEE_Result res;
138 TEE_ObjectHandle h;
139
140 if (pt != exp_pt)
141 return TEE_ERROR_BAD_PARAMETERS;
142
143 res = get_slot_offset(params[0].value.a, &slot_offset);
144 if (res)
145 return res;
146 widx = ((uint64_t)params[1].value.a << 32) | params[1].value.b;
147
148 res = open_rb_state(DEFAULT_LOCK_STATE, &h);
149 if (res)
150 return res;
151
152 res = TEE_SeekObjectData(h, slot_offset, TEE_DATA_SEEK_SET);
153 if (res)
154 goto out;
155
156 res = TEE_ReadObjectData(h, &idx, sizeof(idx), &count);
157 if (res)
158 goto out;
159 if (count != sizeof(idx))
160 idx = 0; /* Not yet written slots are reported as 0 */
161
162 if (widx < idx) {
163 res = TEE_ERROR_SECURITY;
164 goto out;
165 }
166
167 res = TEE_SeekObjectData(h, slot_offset, TEE_DATA_SEEK_SET);
168 if (res)
169 goto out;
170
171 res = TEE_WriteObjectData(h, &widx, sizeof(widx));
172 out:
173 TEE_CloseObject(h);
174 return res;
175 }
176
read_lock_state(uint32_t pt,TEE_Param params[TEE_NUM_PARAMS])177 static TEE_Result read_lock_state(uint32_t pt, TEE_Param params[TEE_NUM_PARAMS])
178 {
179 const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_OUTPUT,
180 TEE_PARAM_TYPE_NONE,
181 TEE_PARAM_TYPE_NONE,
182 TEE_PARAM_TYPE_NONE);
183 uint32_t lock_state;
184 size_t count;
185 TEE_Result res;
186 TEE_ObjectHandle h;
187
188 if (pt != exp_pt)
189 return TEE_ERROR_BAD_PARAMETERS;
190
191 res = open_rb_state(DEFAULT_LOCK_STATE, &h);
192 if (res)
193 return res;
194
195 res = TEE_ReadObjectData(h, &lock_state, sizeof(lock_state), &count);
196 if (res)
197 goto out;
198 if (count != sizeof(lock_state)) {
199 /*
200 * Client need write the lock state to recover, this can
201 * normally not happen.
202 */
203 res = TEE_ERROR_CORRUPT_OBJECT;
204 goto out;
205 }
206
207 params[0].value.a = lock_state;
208 out:
209 TEE_CloseObject(h);
210 return res;
211 }
212
write_lock_state(uint32_t pt,TEE_Param params[TEE_NUM_PARAMS])213 static TEE_Result write_lock_state(uint32_t pt,
214 TEE_Param params[TEE_NUM_PARAMS])
215 {
216 const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
217 TEE_PARAM_TYPE_NONE,
218 TEE_PARAM_TYPE_NONE,
219 TEE_PARAM_TYPE_NONE);
220 uint32_t wlock_state;
221 uint32_t lock_state;
222 size_t count;
223 TEE_Result res;
224 TEE_ObjectHandle h;
225
226 if (pt != exp_pt)
227 return TEE_ERROR_BAD_PARAMETERS;
228
229 wlock_state = params[0].value.a;
230
231 res = open_rb_state(wlock_state, &h);
232 if (res)
233 return res;
234
235 res = TEE_ReadObjectData(h, &lock_state, sizeof(lock_state), &count);
236 if (res)
237 goto out;
238 if (count == sizeof(lock_state) && lock_state == wlock_state)
239 goto out;
240
241 res = TEE_SeekObjectData(h, 0, TEE_DATA_SEEK_SET);
242 if (res)
243 goto out;
244
245 res = TEE_WriteObjectData(h, &wlock_state, sizeof(wlock_state));
246 out:
247 TEE_CloseObject(h);
248 return res;
249 }
250
write_persist_value(uint32_t pt,TEE_Param params[TEE_NUM_PARAMS])251 static TEE_Result write_persist_value(uint32_t pt,
252 TEE_Param params[TEE_NUM_PARAMS])
253 {
254 const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
255 TEE_PARAM_TYPE_MEMREF_INPUT,
256 TEE_PARAM_TYPE_NONE,
257 TEE_PARAM_TYPE_NONE);
258 const uint32_t flags = TEE_DATA_FLAG_ACCESS_READ |
259 TEE_DATA_FLAG_ACCESS_WRITE |
260 TEE_DATA_FLAG_OVERWRITE;
261 char name_full[TEE_OBJECT_ID_MAX_LEN] = { };
262 TEE_ObjectHandle h = TEE_HANDLE_NULL;
263 TEE_Result res = TEE_SUCCESS;
264 uint32_t name_full_sz = 0;
265 uint32_t name_buf_sz = 0;
266 uint32_t value_sz = 0;
267 char *name_buf = NULL;
268 char *value = NULL;
269
270 if (pt != exp_pt)
271 return TEE_ERROR_BAD_PARAMETERS;
272
273 name_buf = params[0].memref.buffer;
274 name_buf_sz = params[0].memref.size;
275 value_sz = params[1].memref.size;
276 value = TEE_Malloc(value_sz, 0);
277 if (!value)
278 return TEE_ERROR_OUT_OF_MEMORY;
279
280 TEE_MemMove(value, params[1].memref.buffer, value_sz);
281
282 res = get_named_object_name(name_buf, name_buf_sz,
283 name_full, &name_full_sz);
284 if (res)
285 goto out;
286
287 res = TEE_CreatePersistentObject(storageid, name_full,
288 name_full_sz,
289 flags, NULL, value,
290 value_sz, &h);
291 if (res)
292 EMSG("Can't create named object value, res = 0x%x", res);
293
294 TEE_CloseObject(h);
295 out:
296 TEE_Free(value);
297
298 return res;
299 }
300
read_persist_value(uint32_t pt,TEE_Param params[TEE_NUM_PARAMS])301 static TEE_Result read_persist_value(uint32_t pt,
302 TEE_Param params[TEE_NUM_PARAMS])
303 {
304 const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
305 TEE_PARAM_TYPE_MEMREF_INOUT,
306 TEE_PARAM_TYPE_NONE,
307 TEE_PARAM_TYPE_NONE);
308 uint32_t flags = TEE_DATA_FLAG_ACCESS_READ |
309 TEE_DATA_FLAG_ACCESS_WRITE;
310 TEE_Result res = TEE_SUCCESS;
311 TEE_ObjectHandle h = TEE_HANDLE_NULL;
312 char name_full[TEE_OBJECT_ID_MAX_LEN];
313 uint32_t name_full_sz = 0;
314 uint32_t name_buf_sz = 0;
315 char *name_buf = NULL;
316 uint32_t value_sz = 0;
317 char *value = NULL;
318 size_t count = 0;
319
320 if (pt != exp_pt)
321 return TEE_ERROR_BAD_PARAMETERS;
322
323 name_buf = params[0].memref.buffer;
324 name_buf_sz = params[0].memref.size;
325 value_sz = params[1].memref.size;
326 value = TEE_Malloc(value_sz, 0);
327 if (!value)
328 return TEE_ERROR_OUT_OF_MEMORY;
329
330 res = get_named_object_name(name_buf, name_buf_sz,
331 name_full, &name_full_sz);
332 if (res)
333 goto out_free;
334
335 res = TEE_OpenPersistentObject(storageid, name_full,
336 name_full_sz, flags, &h);
337 if (res) {
338 EMSG("Can't open named object value, res = 0x%x", res);
339 goto out_free;
340 }
341
342 res = TEE_ReadObjectData(h, value, value_sz, &count);
343 if (res) {
344 EMSG("Can't read named object value, res = 0x%x", res);
345 goto out;
346 }
347
348 TEE_MemMove(params[1].memref.buffer, value,
349 value_sz);
350
351 params[1].memref.size = count;
352 out:
353 TEE_CloseObject(h);
354 out_free:
355 TEE_Free(value);
356
357 return res;
358 }
359
TA_CreateEntryPoint(void)360 TEE_Result TA_CreateEntryPoint(void)
361 {
362 return TEE_SUCCESS;
363 }
364
TA_DestroyEntryPoint(void)365 void TA_DestroyEntryPoint(void)
366 {
367 }
368
TA_OpenSessionEntryPoint(uint32_t pt __unused,TEE_Param params[4]__unused,void ** session __unused)369 TEE_Result TA_OpenSessionEntryPoint(uint32_t pt __unused,
370 TEE_Param params[4] __unused,
371 void **session __unused)
372 {
373 return TEE_SUCCESS;
374 }
375
TA_CloseSessionEntryPoint(void * sess __unused)376 void TA_CloseSessionEntryPoint(void *sess __unused)
377 {
378 }
379
TA_InvokeCommandEntryPoint(void * sess __unused,uint32_t cmd,uint32_t pt,TEE_Param params[TEE_NUM_PARAMS])380 TEE_Result TA_InvokeCommandEntryPoint(void *sess __unused, uint32_t cmd,
381 uint32_t pt,
382 TEE_Param params[TEE_NUM_PARAMS])
383 {
384 switch (cmd) {
385 case TA_AVB_CMD_READ_ROLLBACK_INDEX:
386 return read_rb_idx(pt, params);
387 case TA_AVB_CMD_WRITE_ROLLBACK_INDEX:
388 return write_rb_idx(pt, params);
389 case TA_AVB_CMD_READ_LOCK_STATE:
390 return read_lock_state(pt, params);
391 case TA_AVB_CMD_WRITE_LOCK_STATE:
392 return write_lock_state(pt, params);
393 case TA_AVB_CMD_READ_PERSIST_VALUE:
394 return read_persist_value(pt, params);
395 case TA_AVB_CMD_WRITE_PERSIST_VALUE:
396 return write_persist_value(pt, params);
397 default:
398 EMSG("Command ID 0x%x is not supported", cmd);
399 return TEE_ERROR_NOT_SUPPORTED;
400 }
401 }
402