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 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 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 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 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 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 size_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 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 size_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 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 size_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 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 size_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 = TEE_SeekObjectData(h, 0, TEE_DATA_SEEK_SET); 243 if (res) 244 goto out; 245 246 res = TEE_WriteObjectData(h, &wlock_state, sizeof(wlock_state)); 247 out: 248 TEE_CloseObject(h); 249 return res; 250 } 251 252 static TEE_Result write_persist_value(uint32_t pt, 253 TEE_Param params[TEE_NUM_PARAMS]) 254 { 255 const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT, 256 TEE_PARAM_TYPE_MEMREF_INPUT, 257 TEE_PARAM_TYPE_NONE, 258 TEE_PARAM_TYPE_NONE); 259 const uint32_t flags = TEE_DATA_FLAG_ACCESS_READ | 260 TEE_DATA_FLAG_ACCESS_WRITE | 261 TEE_DATA_FLAG_OVERWRITE; 262 char name_full[TEE_OBJECT_ID_MAX_LEN] = { }; 263 TEE_ObjectHandle h = TEE_HANDLE_NULL; 264 TEE_Result res = TEE_SUCCESS; 265 uint32_t name_full_sz = 0; 266 uint32_t name_buf_sz = 0; 267 uint32_t value_sz = 0; 268 char *name_buf = NULL; 269 char *value = NULL; 270 271 if (pt != exp_pt) 272 return TEE_ERROR_BAD_PARAMETERS; 273 274 name_buf = params[0].memref.buffer; 275 name_buf_sz = params[0].memref.size; 276 value_sz = params[1].memref.size; 277 value = TEE_Malloc(value_sz, 0); 278 if (!value) 279 return TEE_ERROR_OUT_OF_MEMORY; 280 281 TEE_MemMove(value, params[1].memref.buffer, value_sz); 282 283 res = get_named_object_name(name_buf, name_buf_sz, 284 name_full, &name_full_sz); 285 if (res) 286 goto out; 287 288 res = TEE_CreatePersistentObject(storageid, name_full, 289 name_full_sz, 290 flags, NULL, value, 291 value_sz, &h); 292 if (res) 293 EMSG("Can't create named object value, res = 0x%x", res); 294 295 TEE_CloseObject(h); 296 out: 297 TEE_Free(value); 298 299 return res; 300 } 301 302 static TEE_Result read_persist_value(uint32_t pt, 303 TEE_Param params[TEE_NUM_PARAMS]) 304 { 305 const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT, 306 TEE_PARAM_TYPE_MEMREF_INOUT, 307 TEE_PARAM_TYPE_NONE, 308 TEE_PARAM_TYPE_NONE); 309 uint32_t flags = TEE_DATA_FLAG_ACCESS_READ | 310 TEE_DATA_FLAG_ACCESS_WRITE; 311 TEE_Result res = TEE_SUCCESS; 312 TEE_ObjectHandle h = TEE_HANDLE_NULL; 313 char name_full[TEE_OBJECT_ID_MAX_LEN]; 314 uint32_t name_full_sz = 0; 315 uint32_t name_buf_sz = 0; 316 char *name_buf = NULL; 317 uint32_t value_sz = 0; 318 char *value = NULL; 319 size_t count = 0; 320 321 if (pt != exp_pt) 322 return TEE_ERROR_BAD_PARAMETERS; 323 324 name_buf = params[0].memref.buffer; 325 name_buf_sz = params[0].memref.size; 326 value_sz = params[1].memref.size; 327 value = TEE_Malloc(value_sz, 0); 328 if (!value) 329 return TEE_ERROR_OUT_OF_MEMORY; 330 331 res = get_named_object_name(name_buf, name_buf_sz, 332 name_full, &name_full_sz); 333 if (res) 334 goto out_free; 335 336 res = TEE_OpenPersistentObject(storageid, name_full, 337 name_full_sz, flags, &h); 338 if (res) { 339 EMSG("Can't open named object value, res = 0x%x", res); 340 goto out_free; 341 } 342 343 res = TEE_ReadObjectData(h, value, value_sz, &count); 344 if (res) { 345 EMSG("Can't read named object value, res = 0x%x", res); 346 goto out; 347 } 348 349 TEE_MemMove(params[1].memref.buffer, value, 350 value_sz); 351 352 params[1].memref.size = count; 353 out: 354 TEE_CloseObject(h); 355 out_free: 356 TEE_Free(value); 357 358 return res; 359 } 360 361 TEE_Result TA_CreateEntryPoint(void) 362 { 363 return TEE_SUCCESS; 364 } 365 366 void TA_DestroyEntryPoint(void) 367 { 368 } 369 370 TEE_Result TA_OpenSessionEntryPoint(uint32_t pt __unused, 371 TEE_Param params[4] __unused, 372 void **session __unused) 373 { 374 return TEE_SUCCESS; 375 } 376 377 void TA_CloseSessionEntryPoint(void *sess __unused) 378 { 379 } 380 381 TEE_Result TA_InvokeCommandEntryPoint(void *sess __unused, uint32_t cmd, 382 uint32_t pt, 383 TEE_Param params[TEE_NUM_PARAMS]) 384 { 385 switch (cmd) { 386 case TA_AVB_CMD_READ_ROLLBACK_INDEX: 387 return read_rb_idx(pt, params); 388 case TA_AVB_CMD_WRITE_ROLLBACK_INDEX: 389 return write_rb_idx(pt, params); 390 case TA_AVB_CMD_READ_LOCK_STATE: 391 return read_lock_state(pt, params); 392 case TA_AVB_CMD_WRITE_LOCK_STATE: 393 return write_lock_state(pt, params); 394 case TA_AVB_CMD_READ_PERSIST_VALUE: 395 return read_persist_value(pt, params); 396 case TA_AVB_CMD_WRITE_PERSIST_VALUE: 397 return write_persist_value(pt, params); 398 default: 399 EMSG("Command ID 0x%x is not supported", cmd); 400 return TEE_ERROR_NOT_SUPPORTED; 401 } 402 } 403