xref: /optee_os/ta/avb/entry.c (revision b8bb0afa738e6038bbd92b57742aa2526df9f20a)
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