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 #define DEFAULT_LOCK_STATE 0 9 10 static const uint32_t storageid = TEE_STORAGE_PRIVATE_RPMB; 11 static const char obj_name[] = "rb_state"; 12 13 static TEE_Result get_slot_offset(size_t slot, size_t *offset) 14 { 15 if (slot >= TA_AVB_MAX_ROLLBACK_LOCATIONS) 16 return TEE_ERROR_BAD_PARAMETERS; 17 18 *offset = sizeof(uint32_t) /* lock_state */ + slot * sizeof(uint64_t); 19 return TEE_SUCCESS; 20 } 21 22 static TEE_Result create_state(uint32_t lock_state, TEE_ObjectHandle *h) 23 { 24 const uint32_t flags = TEE_DATA_FLAG_ACCESS_READ | 25 TEE_DATA_FLAG_ACCESS_WRITE | 26 TEE_DATA_FLAG_OVERWRITE; 27 28 return TEE_CreatePersistentObject(storageid, obj_name, sizeof(obj_name), 29 flags, NULL, &lock_state, 30 sizeof(lock_state), h); 31 } 32 33 static TEE_Result open_state(uint32_t default_lock_state, TEE_ObjectHandle *h) 34 { 35 uint32_t flags = TEE_DATA_FLAG_ACCESS_READ | TEE_DATA_FLAG_ACCESS_WRITE; 36 TEE_Result res; 37 38 res = TEE_OpenPersistentObject(storageid, obj_name, 39 sizeof(obj_name), flags, h); 40 if (!res) 41 return TEE_SUCCESS; 42 43 return create_state(default_lock_state, h); 44 } 45 46 static TEE_Result read_rb_idx(uint32_t pt, TEE_Param params[TEE_NUM_PARAMS]) 47 { 48 const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, 49 TEE_PARAM_TYPE_VALUE_OUTPUT, 50 TEE_PARAM_TYPE_NONE, 51 TEE_PARAM_TYPE_NONE); 52 size_t slot_offset; 53 uint64_t idx; 54 uint32_t count; 55 TEE_Result res; 56 TEE_ObjectHandle h; 57 58 if (pt != exp_pt) 59 return TEE_ERROR_BAD_PARAMETERS; 60 61 res = get_slot_offset(params[0].value.a, &slot_offset); 62 if (res) 63 return res; 64 65 res = open_state(DEFAULT_LOCK_STATE, &h); 66 if (res) 67 return res; 68 69 res = TEE_SeekObjectData(h, slot_offset, TEE_DATA_SEEK_SET); 70 if (res) 71 goto out; 72 73 res = TEE_ReadObjectData(h, &idx, sizeof(idx), &count); 74 if (res) 75 goto out; 76 if (count != sizeof(idx)) { 77 idx = 0; /* Not yet written slots are reported as 0 */ 78 79 if (count) { 80 /* 81 * Somehow the file didn't even hold a complete 82 * slot index entry. Write it as 0. 83 */ 84 res = TEE_SeekObjectData(h, slot_offset, 85 TEE_DATA_SEEK_SET); 86 if (res) 87 goto out; 88 res = TEE_WriteObjectData(h, &idx, sizeof(idx)); 89 if (res) 90 goto out; 91 } 92 } 93 94 params[1].value.a = idx >> 32; 95 params[1].value.b = idx; 96 out: 97 TEE_CloseObject(h); 98 return res; 99 } 100 101 static TEE_Result write_rb_idx(uint32_t pt, TEE_Param params[TEE_NUM_PARAMS]) 102 { 103 const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, 104 TEE_PARAM_TYPE_VALUE_INPUT, 105 TEE_PARAM_TYPE_NONE, 106 TEE_PARAM_TYPE_NONE); 107 size_t slot_offset; 108 uint64_t widx; 109 uint64_t idx; 110 uint32_t count; 111 TEE_Result res; 112 TEE_ObjectHandle h; 113 114 if (pt != exp_pt) 115 return TEE_ERROR_BAD_PARAMETERS; 116 117 res = get_slot_offset(params[0].value.a, &slot_offset); 118 if (res) 119 return res; 120 widx = ((uint64_t)params[1].value.a << 32) | params[1].value.b; 121 122 res = open_state(DEFAULT_LOCK_STATE, &h); 123 if (res) 124 return res; 125 126 res = TEE_SeekObjectData(h, slot_offset, TEE_DATA_SEEK_SET); 127 if (res) 128 goto out; 129 130 res = TEE_ReadObjectData(h, &idx, sizeof(idx), &count); 131 if (res) 132 goto out; 133 if (count != sizeof(idx)) 134 idx = 0; /* Not yet written slots are reported as 0 */ 135 136 if (widx < idx) { 137 res = TEE_ERROR_SECURITY; 138 goto out; 139 } 140 141 res = TEE_SeekObjectData(h, slot_offset, TEE_DATA_SEEK_SET); 142 if (res) 143 goto out; 144 145 res = TEE_WriteObjectData(h, &widx, sizeof(widx)); 146 out: 147 TEE_CloseObject(h); 148 return res; 149 } 150 151 static TEE_Result read_lock_state(uint32_t pt, TEE_Param params[TEE_NUM_PARAMS]) 152 { 153 const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_OUTPUT, 154 TEE_PARAM_TYPE_NONE, 155 TEE_PARAM_TYPE_NONE, 156 TEE_PARAM_TYPE_NONE); 157 uint32_t lock_state; 158 uint32_t count; 159 TEE_Result res; 160 TEE_ObjectHandle h; 161 162 if (pt != exp_pt) 163 return TEE_ERROR_BAD_PARAMETERS; 164 165 res = open_state(DEFAULT_LOCK_STATE, &h); 166 if (res) 167 return res; 168 169 res = TEE_ReadObjectData(h, &lock_state, sizeof(lock_state), &count); 170 if (res) 171 goto out; 172 if (count != sizeof(lock_state)) { 173 /* 174 * Client need write the lock state to recover, this can 175 * normally not happen. 176 */ 177 res = TEE_ERROR_CORRUPT_OBJECT; 178 goto out; 179 } 180 181 params[0].value.a = lock_state; 182 out: 183 TEE_CloseObject(h); 184 return res; 185 } 186 187 static TEE_Result write_lock_state(uint32_t pt, 188 TEE_Param params[TEE_NUM_PARAMS]) 189 { 190 const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, 191 TEE_PARAM_TYPE_NONE, 192 TEE_PARAM_TYPE_NONE, 193 TEE_PARAM_TYPE_NONE); 194 uint32_t wlock_state; 195 uint32_t lock_state; 196 uint32_t count; 197 TEE_Result res; 198 TEE_ObjectHandle h; 199 200 if (pt != exp_pt) 201 return TEE_ERROR_BAD_PARAMETERS; 202 203 wlock_state = params[0].value.a; 204 205 res = open_state(wlock_state, &h); 206 if (res) 207 return res; 208 209 res = TEE_ReadObjectData(h, &lock_state, sizeof(lock_state), &count); 210 if (res) 211 goto out; 212 if (count == sizeof(lock_state) && lock_state == wlock_state) 213 goto out; 214 215 res = create_state(wlock_state, &h); 216 out: 217 TEE_CloseObject(h); 218 return res; 219 } 220 221 TEE_Result TA_CreateEntryPoint(void) 222 { 223 return TEE_SUCCESS; 224 } 225 226 void TA_DestroyEntryPoint(void) 227 { 228 } 229 230 TEE_Result TA_OpenSessionEntryPoint(uint32_t pt __unused, 231 TEE_Param params[4] __unused, 232 void **session __unused) 233 { 234 return TEE_SUCCESS; 235 } 236 237 void TA_CloseSessionEntryPoint(void *sess __unused) 238 { 239 } 240 241 TEE_Result TA_InvokeCommandEntryPoint(void *sess __unused, uint32_t cmd, 242 uint32_t pt, 243 TEE_Param params[TEE_NUM_PARAMS]) 244 { 245 switch (cmd) { 246 case TA_AVB_CMD_READ_ROLLBACK_INDEX: 247 return read_rb_idx(pt, params); 248 case TA_AVB_CMD_WRITE_ROLLBACK_INDEX: 249 return write_rb_idx(pt, params); 250 case TA_AVB_CMD_READ_LOCK_STATE: 251 return read_lock_state(pt, params); 252 case TA_AVB_CMD_WRITE_LOCK_STATE: 253 return write_lock_state(pt, params); 254 default: 255 EMSG("Command ID 0x%x is not supported", cmd); 256 return TEE_ERROR_NOT_SUPPORTED; 257 } 258 } 259