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 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 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 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 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 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 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 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 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 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 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 360 TEE_Result TA_CreateEntryPoint(void) 361 { 362 return TEE_SUCCESS; 363 } 364 365 void TA_DestroyEntryPoint(void) 366 { 367 } 368 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 376 void TA_CloseSessionEntryPoint(void *sess __unused) 377 { 378 } 379 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