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