blob: 48ba8db51e59b1c54dd41fd6dce9bfd7f068da23 [file] [log] [blame]
Igor Opaniuk3af30e42018-06-03 21:56:38 +03001/*
2 * (C) Copyright 2018, Linaro Limited
3 *
4 * SPDX-License-Identifier: GPL-2.0+
5 */
6
7#include <avb_verify.h>
Igor Opaniuke9ee7392018-07-17 14:33:26 +03008#include <blk.h>
Simon Glass1eb69ae2019-11-14 12:57:39 -07009#include <cpu_func.h>
Igor Opaniuk3af30e42018-06-03 21:56:38 +030010#include <image.h>
11#include <malloc.h>
12#include <part.h>
Jens Wiklander6663e072018-09-25 16:40:20 +020013#include <tee.h>
14#include <tee/optee_ta_avb.h>
Igor Opaniuk3af30e42018-06-03 21:56:38 +030015
Eugeniu Rosca55d56d22018-08-14 02:43:06 +020016static const unsigned char avb_root_pub[1032] = {
Igor Opaniuk3af30e42018-06-03 21:56:38 +030017 0x0, 0x0, 0x10, 0x0, 0x55, 0xd9, 0x4, 0xad, 0xd8, 0x4,
18 0xaf, 0xe3, 0xd3, 0x84, 0x6c, 0x7e, 0xd, 0x89, 0x3d, 0xc2,
19 0x8c, 0xd3, 0x12, 0x55, 0xe9, 0x62, 0xc9, 0xf1, 0xf, 0x5e,
20 0xcc, 0x16, 0x72, 0xab, 0x44, 0x7c, 0x2c, 0x65, 0x4a, 0x94,
21 0xb5, 0x16, 0x2b, 0x0, 0xbb, 0x6, 0xef, 0x13, 0x7, 0x53,
22 0x4c, 0xf9, 0x64, 0xb9, 0x28, 0x7a, 0x1b, 0x84, 0x98, 0x88,
23 0xd8, 0x67, 0xa4, 0x23, 0xf9, 0xa7, 0x4b, 0xdc, 0x4a, 0xf,
24 0xf7, 0x3a, 0x18, 0xae, 0x54, 0xa8, 0x15, 0xfe, 0xb0, 0xad,
25 0xac, 0x35, 0xda, 0x3b, 0xad, 0x27, 0xbc, 0xaf, 0xe8, 0xd3,
26 0x2f, 0x37, 0x34, 0xd6, 0x51, 0x2b, 0x6c, 0x5a, 0x27, 0xd7,
27 0x96, 0x6, 0xaf, 0x6b, 0xb8, 0x80, 0xca, 0xfa, 0x30, 0xb4,
28 0xb1, 0x85, 0xb3, 0x4d, 0xaa, 0xaa, 0xc3, 0x16, 0x34, 0x1a,
29 0xb8, 0xe7, 0xc7, 0xfa, 0xf9, 0x9, 0x77, 0xab, 0x97, 0x93,
30 0xeb, 0x44, 0xae, 0xcf, 0x20, 0xbc, 0xf0, 0x80, 0x11, 0xdb,
31 0x23, 0xc, 0x47, 0x71, 0xb9, 0x6d, 0xd6, 0x7b, 0x60, 0x47,
32 0x87, 0x16, 0x56, 0x93, 0xb7, 0xc2, 0x2a, 0x9a, 0xb0, 0x4c,
33 0x1, 0xc, 0x30, 0xd8, 0x93, 0x87, 0xf0, 0xed, 0x6e, 0x8b,
34 0xbe, 0x30, 0x5b, 0xf6, 0xa6, 0xaf, 0xdd, 0x80, 0x7c, 0x45,
35 0x5e, 0x8f, 0x91, 0x93, 0x5e, 0x44, 0xfe, 0xb8, 0x82, 0x7,
36 0xee, 0x79, 0xca, 0xbf, 0x31, 0x73, 0x62, 0x58, 0xe3, 0xcd,
37 0xc4, 0xbc, 0xc2, 0x11, 0x1d, 0xa1, 0x4a, 0xbf, 0xfe, 0x27,
38 0x7d, 0xa1, 0xf6, 0x35, 0xa3, 0x5e, 0xca, 0xdc, 0x57, 0x2f,
39 0x3e, 0xf0, 0xc9, 0x5d, 0x86, 0x6a, 0xf8, 0xaf, 0x66, 0xa7,
40 0xed, 0xcd, 0xb8, 0xed, 0xa1, 0x5f, 0xba, 0x9b, 0x85, 0x1a,
41 0xd5, 0x9, 0xae, 0x94, 0x4e, 0x3b, 0xcf, 0xcb, 0x5c, 0xc9,
42 0x79, 0x80, 0xf7, 0xcc, 0xa6, 0x4a, 0xa8, 0x6a, 0xd8, 0xd3,
43 0x31, 0x11, 0xf9, 0xf6, 0x2, 0x63, 0x2a, 0x1a, 0x2d, 0xd1,
44 0x1a, 0x66, 0x1b, 0x16, 0x41, 0xbd, 0xbd, 0xf7, 0x4d, 0xc0,
45 0x4a, 0xe5, 0x27, 0x49, 0x5f, 0x7f, 0x58, 0xe3, 0x27, 0x2d,
46 0xe5, 0xc9, 0x66, 0xe, 0x52, 0x38, 0x16, 0x38, 0xfb, 0x16,
47 0xeb, 0x53, 0x3f, 0xe6, 0xfd, 0xe9, 0xa2, 0x5e, 0x25, 0x59,
48 0xd8, 0x79, 0x45, 0xff, 0x3, 0x4c, 0x26, 0xa2, 0x0, 0x5a,
49 0x8e, 0xc2, 0x51, 0xa1, 0x15, 0xf9, 0x7b, 0xf4, 0x5c, 0x81,
50 0x9b, 0x18, 0x47, 0x35, 0xd8, 0x2d, 0x5, 0xe9, 0xad, 0xf,
51 0x35, 0x74, 0x15, 0xa3, 0x8e, 0x8b, 0xcc, 0x27, 0xda, 0x7c,
52 0x5d, 0xe4, 0xfa, 0x4, 0xd3, 0x5, 0xb, 0xba, 0x3a, 0xb2,
53 0x49, 0x45, 0x2f, 0x47, 0xc7, 0xd, 0x41, 0x3f, 0x97, 0x80,
54 0x4d, 0x3f, 0xc1, 0xb5, 0xbb, 0x70, 0x5f, 0xa7, 0x37, 0xaf,
55 0x48, 0x22, 0x12, 0x45, 0x2e, 0xf5, 0xf, 0x87, 0x92, 0xe2,
56 0x84, 0x1, 0xf9, 0x12, 0xf, 0x14, 0x15, 0x24, 0xce, 0x89,
57 0x99, 0xee, 0xb9, 0xc4, 0x17, 0x70, 0x70, 0x15, 0xea, 0xbe,
58 0xc6, 0x6c, 0x1f, 0x62, 0xb3, 0xf4, 0x2d, 0x16, 0x87, 0xfb,
59 0x56, 0x1e, 0x45, 0xab, 0xae, 0x32, 0xe4, 0x5e, 0x91, 0xed,
60 0x53, 0x66, 0x5e, 0xbd, 0xed, 0xad, 0xe6, 0x12, 0x39, 0xd,
61 0x83, 0xc9, 0xe8, 0x6b, 0x6c, 0x2d, 0xa5, 0xee, 0xc4, 0x5a,
62 0x66, 0xae, 0x8c, 0x97, 0xd7, 0xd, 0x6c, 0x49, 0xc7, 0xf5,
63 0xc4, 0x92, 0x31, 0x8b, 0x9, 0xee, 0x33, 0xda, 0xa9, 0x37,
64 0xb6, 0x49, 0x18, 0xf8, 0xe, 0x60, 0x45, 0xc8, 0x33, 0x91,
65 0xef, 0x20, 0x57, 0x10, 0xbe, 0x78, 0x2d, 0x83, 0x26, 0xd6,
66 0xca, 0x61, 0xf9, 0x2f, 0xe0, 0xbf, 0x5, 0x30, 0x52, 0x5a,
67 0x12, 0x1c, 0x0, 0xa7, 0x5d, 0xcc, 0x7c, 0x2e, 0xc5, 0x95,
68 0x8b, 0xa3, 0x3b, 0xf0, 0x43, 0x2e, 0x5e, 0xdd, 0x0, 0xdb,
69 0xd, 0xb3, 0x37, 0x99, 0xa9, 0xcd, 0x9c, 0xb7, 0x43, 0xf7,
70 0x35, 0x44, 0x21, 0xc2, 0x82, 0x71, 0xab, 0x8d, 0xaa, 0xb4,
71 0x41, 0x11, 0xec, 0x1e, 0x8d, 0xfc, 0x14, 0x82, 0x92, 0x4e,
72 0x83, 0x6a, 0xa, 0x6b, 0x35, 0x5e, 0x5d, 0xe9, 0x5c, 0xcc,
73 0x8c, 0xde, 0x39, 0xd1, 0x4a, 0x5b, 0x5f, 0x63, 0xa9, 0x64,
74 0xe0, 0xa, 0xcb, 0xb, 0xb8, 0x5a, 0x7c, 0xc3, 0xb, 0xe6,
75 0xbe, 0xfe, 0x8b, 0xf, 0x7d, 0x34, 0x8e, 0x2, 0x66, 0x74,
76 0x1, 0x6c, 0xca, 0x76, 0xac, 0x7c, 0x67, 0x8, 0x2f, 0x3f,
77 0x1a, 0xa6, 0x2c, 0x60, 0xb3, 0xff, 0xda, 0x8d, 0xb8, 0x12,
78 0xc, 0x0, 0x7f, 0xcc, 0x50, 0xa1, 0x5c, 0x64, 0xa1, 0xe2,
79 0x5f, 0x32, 0x65, 0xc9, 0x9c, 0xbe, 0xd6, 0xa, 0x13, 0x87,
80 0x3c, 0x2a, 0x45, 0x47, 0xc, 0xca, 0x42, 0x82, 0xfa, 0x89,
81 0x65, 0xe7, 0x89, 0xb4, 0x8f, 0xf7, 0x1e, 0xe6, 0x23, 0xa5,
82 0xd0, 0x59, 0x37, 0x79, 0x92, 0xd7, 0xce, 0x3d, 0xfd, 0xe3,
83 0xa1, 0xb, 0xcf, 0x6c, 0x85, 0xa0, 0x65, 0xf3, 0x5c, 0xc6,
84 0x4a, 0x63, 0x5f, 0x6e, 0x3a, 0x3a, 0x2a, 0x8b, 0x6a, 0xb6,
85 0x2f, 0xbb, 0xf8, 0xb2, 0x4b, 0x62, 0xbc, 0x1a, 0x91, 0x25,
86 0x66, 0xe3, 0x69, 0xca, 0x60, 0x49, 0xb, 0xf6, 0x8a, 0xbe,
87 0x3e, 0x76, 0x53, 0xc2, 0x7a, 0xa8, 0x4, 0x17, 0x75, 0xf1,
88 0xf3, 0x3, 0x62, 0x1b, 0x85, 0xb2, 0xb0, 0xef, 0x80, 0x15,
89 0xb6, 0xd4, 0x4e, 0xdf, 0x71, 0xac, 0xdb, 0x2a, 0x4, 0xd4,
90 0xb4, 0x21, 0xba, 0x65, 0x56, 0x57, 0xe8, 0xfa, 0x84, 0xa2,
91 0x7d, 0x13, 0xe, 0xaf, 0xd7, 0x9a, 0x58, 0x2a, 0xa3, 0x81,
92 0x84, 0x8d, 0x9, 0xa0, 0x6a, 0xc1, 0xbb, 0xd9, 0xf5, 0x86,
93 0xac, 0xbd, 0x75, 0x61, 0x9, 0xe6, 0x8c, 0x3d, 0x77, 0xb2,
94 0xed, 0x30, 0x20, 0xe4, 0x0, 0x1d, 0x97, 0xe8, 0xbf, 0xc7,
95 0x0, 0x1b, 0x21, 0xb1, 0x16, 0xe7, 0x41, 0x67, 0x2e, 0xec,
96 0x38, 0xbc, 0xe5, 0x1b, 0xb4, 0x6, 0x23, 0x31, 0x71, 0x1c,
97 0x49, 0xcd, 0x76, 0x4a, 0x76, 0x36, 0x8d, 0xa3, 0x89, 0x8b,
98 0x4a, 0x7a, 0xf4, 0x87, 0xc8, 0x15, 0xf, 0x37, 0x39, 0xf6,
99 0x6d, 0x80, 0x19, 0xef, 0x5c, 0xa8, 0x66, 0xce, 0x1b, 0x16,
100 0x79, 0x21, 0xdf, 0xd7, 0x31, 0x30, 0xc4, 0x21, 0xdd, 0x34,
101 0x5b, 0xd2, 0x1a, 0x2b, 0x3e, 0x5d, 0xf7, 0xea, 0xca, 0x5,
102 0x8e, 0xb7, 0xcb, 0x49, 0x2e, 0xa0, 0xe3, 0xf4, 0xa7, 0x48,
103 0x19, 0x10, 0x9c, 0x4, 0xa7, 0xf4, 0x28, 0x74, 0xc8, 0x6f,
104 0x63, 0x20, 0x2b, 0x46, 0x24, 0x26, 0x19, 0x1d, 0xd1, 0x2c,
105 0x31, 0x6d, 0x5a, 0x29, 0xa2, 0x6, 0xa6, 0xb2, 0x41, 0xcc,
106 0xa, 0x27, 0x96, 0x9, 0x96, 0xac, 0x47, 0x65, 0x78, 0x68,
107 0x51, 0x98, 0xd6, 0xd8, 0xa6, 0x2d, 0xa0, 0xcf, 0xec, 0xe2,
108 0x74, 0xf2, 0x82, 0xe3, 0x97, 0xd9, 0x7e, 0xd4, 0xf8, 0xb,
109 0x70, 0x43, 0x3d, 0xb1, 0x7b, 0x97, 0x80, 0xd6, 0xcb, 0xd7,
110 0x19, 0xbc, 0x63, 0xb, 0xfd, 0x4d, 0x88, 0xfe, 0x67, 0xac,
111 0xb8, 0xcc, 0x50, 0xb7, 0x68, 0xb3, 0x5b, 0xd6, 0x1e, 0x25,
112 0xfc, 0x5f, 0x3c, 0x8d, 0xb1, 0x33, 0x7c, 0xb3, 0x49, 0x1,
113 0x3f, 0x71, 0x55, 0xe, 0x51, 0xba, 0x61, 0x26, 0xfa, 0xea,
114 0xe5, 0xb5, 0xe8, 0xaa, 0xcf, 0xcd, 0x96, 0x9f, 0xd6, 0xc1,
115 0x5f, 0x53, 0x91, 0xad, 0x5, 0xde, 0x20, 0xe7, 0x51, 0xda,
116 0x5b, 0x95, 0x67, 0xed, 0xf4, 0xee, 0x42, 0x65, 0x70, 0x13,
117 0xb, 0x70, 0x14, 0x1c, 0xc9, 0xe0, 0x19, 0xca, 0x5f, 0xf5,
118 0x1d, 0x70, 0x4b, 0x6c, 0x6, 0x74, 0xec, 0xb5, 0x2e, 0x77,
119 0xe1, 0x74, 0xa1, 0xa3, 0x99, 0xa0, 0x85, 0x9e, 0xf1, 0xac,
120 0xd8, 0x7e,
121};
122
123/**
124 * ============================================================================
Igor Opaniuk5d4fd872018-06-03 21:56:40 +0300125 * Boot states support (GREEN, YELLOW, ORANGE, RED) and dm_verity
126 * ============================================================================
127 */
128char *avb_set_state(AvbOps *ops, enum avb_boot_state boot_state)
129{
130 struct AvbOpsData *data;
131 char *cmdline = NULL;
132
133 if (!ops)
134 return NULL;
135
136 data = (struct AvbOpsData *)ops->user_data;
137 if (!data)
138 return NULL;
139
140 data->boot_state = boot_state;
141 switch (boot_state) {
142 case AVB_GREEN:
143 cmdline = "androidboot.verifiedbootstate=green";
144 break;
145 case AVB_YELLOW:
146 cmdline = "androidboot.verifiedbootstate=yellow";
147 break;
148 case AVB_ORANGE:
149 cmdline = "androidboot.verifiedbootstate=orange";
150 case AVB_RED:
151 break;
152 }
153
154 return cmdline;
155}
156
157char *append_cmd_line(char *cmdline_orig, char *cmdline_new)
158{
159 char *cmd_line;
160
161 if (!cmdline_new)
162 return cmdline_orig;
163
164 if (cmdline_orig)
165 cmd_line = cmdline_orig;
166 else
167 cmd_line = " ";
168
169 cmd_line = avb_strdupv(cmd_line, " ", cmdline_new, NULL);
170
171 return cmd_line;
172}
173
174static int avb_find_dm_args(char **args, char *str)
175{
176 int i;
177
178 if (!str)
179 return -1;
180
Eugeniu Rosca2e2067b2018-08-14 02:43:04 +0200181 for (i = 0; i < AVB_MAX_ARGS && args[i]; ++i) {
Igor Opaniuk5d4fd872018-06-03 21:56:40 +0300182 if (strstr(args[i], str))
183 return i;
184 }
185
186 return -1;
187}
188
189static char *avb_set_enforce_option(const char *cmdline, const char *option)
190{
191 char *cmdarg[AVB_MAX_ARGS];
192 char *newargs = NULL;
193 int i = 0;
194 int total_args;
195
196 memset(cmdarg, 0, sizeof(cmdarg));
197 cmdarg[i++] = strtok((char *)cmdline, " ");
198
199 do {
200 cmdarg[i] = strtok(NULL, " ");
201 if (!cmdarg[i])
202 break;
203
204 if (++i >= AVB_MAX_ARGS) {
205 printf("%s: Can't handle more then %d args\n",
206 __func__, i);
207 return NULL;
208 }
209 } while (true);
210
211 total_args = i;
212 i = avb_find_dm_args(&cmdarg[0], VERITY_TABLE_OPT_LOGGING);
213 if (i >= 0) {
214 cmdarg[i] = (char *)option;
215 } else {
216 i = avb_find_dm_args(&cmdarg[0], VERITY_TABLE_OPT_RESTART);
217 if (i < 0) {
218 printf("%s: No verity options found\n", __func__);
219 return NULL;
220 }
221
222 cmdarg[i] = (char *)option;
223 }
224
225 for (i = 0; i <= total_args; i++)
226 newargs = append_cmd_line(newargs, cmdarg[i]);
227
228 return newargs;
229}
230
231char *avb_set_ignore_corruption(const char *cmdline)
232{
233 char *newargs = NULL;
234
235 newargs = avb_set_enforce_option(cmdline, VERITY_TABLE_OPT_LOGGING);
236 if (newargs)
237 newargs = append_cmd_line(newargs,
238 "androidboot.veritymode=eio");
239
240 return newargs;
241}
242
243char *avb_set_enforce_verity(const char *cmdline)
244{
245 char *newargs;
246
247 newargs = avb_set_enforce_option(cmdline, VERITY_TABLE_OPT_RESTART);
248 if (newargs)
249 newargs = append_cmd_line(newargs,
250 "androidboot.veritymode=enforcing");
251 return newargs;
252}
253
254/**
255 * ============================================================================
Igor Opaniuk3af30e42018-06-03 21:56:38 +0300256 * IO(mmc) auxiliary functions
257 * ============================================================================
258 */
259static unsigned long mmc_read_and_flush(struct mmc_part *part,
260 lbaint_t start,
261 lbaint_t sectors,
262 void *buffer)
263{
264 unsigned long blks;
265 void *tmp_buf;
266 size_t buf_size;
267 bool unaligned = is_buf_unaligned(buffer);
268
269 if (start < part->info.start) {
270 printf("%s: partition start out of bounds\n", __func__);
271 return 0;
272 }
273 if ((start + sectors) > (part->info.start + part->info.size)) {
274 sectors = part->info.start + part->info.size - start;
275 printf("%s: read sector aligned to partition bounds (%ld)\n",
276 __func__, sectors);
277 }
278
279 /*
280 * Reading fails on unaligned buffers, so we have to
281 * use aligned temporary buffer and then copy to destination
282 */
283
284 if (unaligned) {
285 printf("Handling unaligned read buffer..\n");
286 tmp_buf = get_sector_buf();
287 buf_size = get_sector_buf_size();
288 if (sectors > buf_size / part->info.blksz)
289 sectors = buf_size / part->info.blksz;
290 } else {
291 tmp_buf = buffer;
292 }
293
Igor Opaniuke9ee7392018-07-17 14:33:26 +0300294 blks = blk_dread(part->mmc_blk,
295 start, sectors, tmp_buf);
Igor Opaniuk3af30e42018-06-03 21:56:38 +0300296 /* flush cache after read */
297 flush_cache((ulong)tmp_buf, sectors * part->info.blksz);
298
299 if (unaligned)
300 memcpy(buffer, tmp_buf, sectors * part->info.blksz);
301
302 return blks;
303}
304
305static unsigned long mmc_write(struct mmc_part *part, lbaint_t start,
306 lbaint_t sectors, void *buffer)
307{
308 void *tmp_buf;
309 size_t buf_size;
310 bool unaligned = is_buf_unaligned(buffer);
311
312 if (start < part->info.start) {
313 printf("%s: partition start out of bounds\n", __func__);
314 return 0;
315 }
316 if ((start + sectors) > (part->info.start + part->info.size)) {
317 sectors = part->info.start + part->info.size - start;
318 printf("%s: sector aligned to partition bounds (%ld)\n",
319 __func__, sectors);
320 }
321 if (unaligned) {
322 tmp_buf = get_sector_buf();
323 buf_size = get_sector_buf_size();
324 printf("Handling unaligned wrire buffer..\n");
325 if (sectors > buf_size / part->info.blksz)
326 sectors = buf_size / part->info.blksz;
327
328 memcpy(tmp_buf, buffer, sectors * part->info.blksz);
329 } else {
330 tmp_buf = buffer;
331 }
332
Igor Opaniuke9ee7392018-07-17 14:33:26 +0300333 return blk_dwrite(part->mmc_blk,
334 start, sectors, tmp_buf);
Igor Opaniuk3af30e42018-06-03 21:56:38 +0300335}
336
337static struct mmc_part *get_partition(AvbOps *ops, const char *partition)
338{
339 int ret;
340 u8 dev_num;
341 int part_num = 0;
342 struct mmc_part *part;
343 struct blk_desc *mmc_blk;
344
345 part = malloc(sizeof(struct mmc_part));
346 if (!part)
347 return NULL;
348
349 dev_num = get_boot_device(ops);
350 part->mmc = find_mmc_device(dev_num);
351 if (!part->mmc) {
352 printf("No MMC device at slot %x\n", dev_num);
Eugeniu Rosca047bc5c2018-08-14 02:43:07 +0200353 goto err;
Igor Opaniuk3af30e42018-06-03 21:56:38 +0300354 }
355
356 if (mmc_init(part->mmc)) {
357 printf("MMC initialization failed\n");
Eugeniu Rosca047bc5c2018-08-14 02:43:07 +0200358 goto err;
Igor Opaniuk3af30e42018-06-03 21:56:38 +0300359 }
360
361 ret = mmc_switch_part(part->mmc, part_num);
362 if (ret)
Eugeniu Rosca047bc5c2018-08-14 02:43:07 +0200363 goto err;
Igor Opaniuk3af30e42018-06-03 21:56:38 +0300364
365 mmc_blk = mmc_get_blk_desc(part->mmc);
366 if (!mmc_blk) {
367 printf("Error - failed to obtain block descriptor\n");
Eugeniu Rosca047bc5c2018-08-14 02:43:07 +0200368 goto err;
Igor Opaniuk3af30e42018-06-03 21:56:38 +0300369 }
370
371 ret = part_get_info_by_name(mmc_blk, partition, &part->info);
schspa04534112021-02-26 00:19:10 +0800372 if (ret < 0) {
Igor Opaniuk3af30e42018-06-03 21:56:38 +0300373 printf("Can't find partition '%s'\n", partition);
Eugeniu Rosca047bc5c2018-08-14 02:43:07 +0200374 goto err;
Igor Opaniuk3af30e42018-06-03 21:56:38 +0300375 }
376
377 part->dev_num = dev_num;
378 part->mmc_blk = mmc_blk;
379
380 return part;
Eugeniu Rosca047bc5c2018-08-14 02:43:07 +0200381err:
382 free(part);
383 return NULL;
Igor Opaniuk3af30e42018-06-03 21:56:38 +0300384}
385
386static AvbIOResult mmc_byte_io(AvbOps *ops,
387 const char *partition,
388 s64 offset,
389 size_t num_bytes,
390 void *buffer,
391 size_t *out_num_read,
392 enum mmc_io_type io_type)
393{
394 ulong ret;
395 struct mmc_part *part;
396 u64 start_offset, start_sector, sectors, residue;
397 u8 *tmp_buf;
398 size_t io_cnt = 0;
399
400 if (!partition || !buffer || io_type > IO_WRITE)
401 return AVB_IO_RESULT_ERROR_IO;
402
403 part = get_partition(ops, partition);
404 if (!part)
405 return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
406
Eugeniu Roscae1904f42018-08-14 02:43:09 +0200407 if (!part->info.blksz)
408 return AVB_IO_RESULT_ERROR_IO;
409
Igor Opaniuk3af30e42018-06-03 21:56:38 +0300410 start_offset = calc_offset(part, offset);
411 while (num_bytes) {
412 start_sector = start_offset / part->info.blksz;
413 sectors = num_bytes / part->info.blksz;
414 /* handle non block-aligned reads */
415 if (start_offset % part->info.blksz ||
416 num_bytes < part->info.blksz) {
417 tmp_buf = get_sector_buf();
418 if (start_offset % part->info.blksz) {
419 residue = part->info.blksz -
420 (start_offset % part->info.blksz);
421 if (residue > num_bytes)
422 residue = num_bytes;
423 } else {
424 residue = num_bytes;
425 }
426
427 if (io_type == IO_READ) {
428 ret = mmc_read_and_flush(part,
429 part->info.start +
430 start_sector,
431 1, tmp_buf);
432
433 if (ret != 1) {
434 printf("%s: read error (%ld, %lld)\n",
435 __func__, ret, start_sector);
436 return AVB_IO_RESULT_ERROR_IO;
437 }
438 /*
439 * if this is not aligned at sector start,
440 * we have to adjust the tmp buffer
441 */
442 tmp_buf += (start_offset % part->info.blksz);
443 memcpy(buffer, (void *)tmp_buf, residue);
444 } else {
445 ret = mmc_read_and_flush(part,
446 part->info.start +
447 start_sector,
448 1, tmp_buf);
449
450 if (ret != 1) {
451 printf("%s: read error (%ld, %lld)\n",
452 __func__, ret, start_sector);
453 return AVB_IO_RESULT_ERROR_IO;
454 }
455 memcpy((void *)tmp_buf +
456 start_offset % part->info.blksz,
457 buffer, residue);
458
459 ret = mmc_write(part, part->info.start +
460 start_sector, 1, tmp_buf);
461 if (ret != 1) {
462 printf("%s: write error (%ld, %lld)\n",
463 __func__, ret, start_sector);
464 return AVB_IO_RESULT_ERROR_IO;
465 }
466 }
467
468 io_cnt += residue;
469 buffer += residue;
470 start_offset += residue;
471 num_bytes -= residue;
472 continue;
473 }
474
475 if (sectors) {
476 if (io_type == IO_READ) {
477 ret = mmc_read_and_flush(part,
478 part->info.start +
479 start_sector,
480 sectors, buffer);
481 } else {
482 ret = mmc_write(part,
483 part->info.start +
484 start_sector,
485 sectors, buffer);
486 }
487
488 if (!ret) {
489 printf("%s: sector read error\n", __func__);
490 return AVB_IO_RESULT_ERROR_IO;
491 }
492
493 io_cnt += ret * part->info.blksz;
494 buffer += ret * part->info.blksz;
495 start_offset += ret * part->info.blksz;
496 num_bytes -= ret * part->info.blksz;
497 }
498 }
499
500 /* Set counter for read operation */
501 if (io_type == IO_READ && out_num_read)
502 *out_num_read = io_cnt;
503
504 return AVB_IO_RESULT_OK;
505}
506
507/**
508 * ============================================================================
509 * AVB 2.0 operations
510 * ============================================================================
511 */
512
513/**
514 * read_from_partition() - reads @num_bytes from @offset from partition
515 * identified by a string name
516 *
517 * @ops: contains AVB ops handlers
518 * @partition_name: partition name, NUL-terminated UTF-8 string
519 * @offset: offset from the beginning of partition
520 * @num_bytes: amount of bytes to read
521 * @buffer: destination buffer to store data
522 * @out_num_read:
523 *
524 * @return:
525 * AVB_IO_RESULT_OK, if partition was found and read operation succeed
526 * AVB_IO_RESULT_ERROR_IO, if i/o error occurred from the underlying i/o
527 * subsystem
528 * AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION, if there is no partition with
529 * the given name
530 */
531static AvbIOResult read_from_partition(AvbOps *ops,
532 const char *partition_name,
533 s64 offset_from_partition,
534 size_t num_bytes,
535 void *buffer,
536 size_t *out_num_read)
537{
538 return mmc_byte_io(ops, partition_name, offset_from_partition,
539 num_bytes, buffer, out_num_read, IO_READ);
540}
541
542/**
543 * write_to_partition() - writes N bytes to a partition identified by a string
544 * name
545 *
546 * @ops: AvbOps, contains AVB ops handlers
547 * @partition_name: partition name
548 * @offset_from_partition: offset from the beginning of partition
549 * @num_bytes: amount of bytes to write
550 * @buf: data to write
551 * @out_num_read:
552 *
553 * @return:
554 * AVB_IO_RESULT_OK, if partition was found and read operation succeed
555 * AVB_IO_RESULT_ERROR_IO, if input/output error occurred
556 * AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION, if partition, specified in
557 * @partition_name was not found
558 */
559static AvbIOResult write_to_partition(AvbOps *ops,
560 const char *partition_name,
561 s64 offset_from_partition,
562 size_t num_bytes,
563 const void *buffer)
564{
565 return mmc_byte_io(ops, partition_name, offset_from_partition,
566 num_bytes, (void *)buffer, NULL, IO_WRITE);
567}
568
569/**
570 * validate_vmbeta_public_key() - checks if the given public key used to sign
571 * the vbmeta partition is trusted
572 *
573 * @ops: AvbOps, contains AVB ops handlers
574 * @public_key_data: public key for verifying vbmeta partition signature
575 * @public_key_length: length of public key
576 * @public_key_metadata:
577 * @public_key_metadata_length:
578 * @out_key_is_trusted:
579 *
580 * @return:
581 * AVB_IO_RESULT_OK, if partition was found and read operation succeed
582 */
583static AvbIOResult validate_vbmeta_public_key(AvbOps *ops,
584 const u8 *public_key_data,
585 size_t public_key_length,
586 const u8
587 *public_key_metadata,
588 size_t
589 public_key_metadata_length,
590 bool *out_key_is_trusted)
591{
592 if (!public_key_length || !public_key_data || !out_key_is_trusted)
593 return AVB_IO_RESULT_ERROR_IO;
594
595 *out_key_is_trusted = false;
596 if (public_key_length != sizeof(avb_root_pub))
597 return AVB_IO_RESULT_ERROR_IO;
598
599 if (memcmp(avb_root_pub, public_key_data, public_key_length) == 0)
600 *out_key_is_trusted = true;
601
602 return AVB_IO_RESULT_OK;
603}
604
Jens Wiklander6663e072018-09-25 16:40:20 +0200605#ifdef CONFIG_OPTEE_TA_AVB
606static int get_open_session(struct AvbOpsData *ops_data)
607{
608 struct udevice *tee = NULL;
609
610 while (!ops_data->tee) {
611 const struct tee_optee_ta_uuid uuid = TA_AVB_UUID;
612 struct tee_open_session_arg arg;
613 int rc;
614
615 tee = tee_find_device(tee, NULL, NULL, NULL);
616 if (!tee)
617 return -ENODEV;
618
619 memset(&arg, 0, sizeof(arg));
620 tee_optee_ta_uuid_to_octets(arg.uuid, &uuid);
621 rc = tee_open_session(tee, &arg, 0, NULL);
Ivan Khoronzhuk3106e472023-01-27 22:02:14 +0200622 if (rc || arg.ret)
623 continue;
624
625 ops_data->tee = tee;
626 ops_data->session = arg.session;
Jens Wiklander6663e072018-09-25 16:40:20 +0200627 }
628
629 return 0;
630}
631
632static AvbIOResult invoke_func(struct AvbOpsData *ops_data, u32 func,
633 ulong num_param, struct tee_param *param)
634{
635 struct tee_invoke_arg arg;
636
637 if (get_open_session(ops_data))
638 return AVB_IO_RESULT_ERROR_IO;
639
640 memset(&arg, 0, sizeof(arg));
641 arg.func = func;
642 arg.session = ops_data->session;
643
644 if (tee_invoke_func(ops_data->tee, &arg, num_param, param))
645 return AVB_IO_RESULT_ERROR_IO;
646 switch (arg.ret) {
647 case TEE_SUCCESS:
648 return AVB_IO_RESULT_OK;
649 case TEE_ERROR_OUT_OF_MEMORY:
650 return AVB_IO_RESULT_ERROR_OOM;
Igor Opaniukfc1fe012019-04-09 15:38:14 +0200651 case TEE_ERROR_STORAGE_NO_SPACE:
652 return AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE;
653 case TEE_ERROR_ITEM_NOT_FOUND:
654 return AVB_IO_RESULT_ERROR_NO_SUCH_VALUE;
Jens Wiklander6663e072018-09-25 16:40:20 +0200655 case TEE_ERROR_TARGET_DEAD:
656 /*
657 * The TA has paniced, close the session to reload the TA
658 * for the next request.
659 */
660 tee_close_session(ops_data->tee, ops_data->session);
661 ops_data->tee = NULL;
662 return AVB_IO_RESULT_ERROR_IO;
663 default:
664 return AVB_IO_RESULT_ERROR_IO;
665 }
666}
667#endif
668
Igor Opaniuk3af30e42018-06-03 21:56:38 +0300669/**
670 * read_rollback_index() - gets the rollback index corresponding to the
671 * location of given by @out_rollback_index.
672 *
673 * @ops: contains AvbOps handlers
674 * @rollback_index_slot:
675 * @out_rollback_index: used to write a retrieved rollback index.
676 *
677 * @return
678 * AVB_IO_RESULT_OK, if the roolback index was retrieved
679 */
680static AvbIOResult read_rollback_index(AvbOps *ops,
681 size_t rollback_index_slot,
682 u64 *out_rollback_index)
683{
Jens Wiklander6663e072018-09-25 16:40:20 +0200684#ifndef CONFIG_OPTEE_TA_AVB
Igor Opaniuk3af30e42018-06-03 21:56:38 +0300685 /* For now we always return 0 as the stored rollback index. */
Igor Opaniuk5d4fd872018-06-03 21:56:40 +0300686 printf("%s not supported yet\n", __func__);
Igor Opaniuk3af30e42018-06-03 21:56:38 +0300687
688 if (out_rollback_index)
689 *out_rollback_index = 0;
690
691 return AVB_IO_RESULT_OK;
Jens Wiklander6663e072018-09-25 16:40:20 +0200692#else
693 AvbIOResult rc;
694 struct tee_param param[2];
695
696 if (rollback_index_slot >= TA_AVB_MAX_ROLLBACK_LOCATIONS)
697 return AVB_IO_RESULT_ERROR_NO_SUCH_VALUE;
698
699 memset(param, 0, sizeof(param));
700 param[0].attr = TEE_PARAM_ATTR_TYPE_VALUE_INPUT;
701 param[0].u.value.a = rollback_index_slot;
702 param[1].attr = TEE_PARAM_ATTR_TYPE_VALUE_OUTPUT;
703
704 rc = invoke_func(ops->user_data, TA_AVB_CMD_READ_ROLLBACK_INDEX,
705 ARRAY_SIZE(param), param);
706 if (rc)
707 return rc;
708
709 *out_rollback_index = (u64)param[1].u.value.a << 32 |
710 (u32)param[1].u.value.b;
711 return AVB_IO_RESULT_OK;
712#endif
Igor Opaniuk3af30e42018-06-03 21:56:38 +0300713}
714
715/**
716 * write_rollback_index() - sets the rollback index corresponding to the
717 * location of given by @out_rollback_index.
718 *
719 * @ops: contains AvbOps handlers
720 * @rollback_index_slot:
721 * @rollback_index: rollback index to write.
722 *
723 * @return
724 * AVB_IO_RESULT_OK, if the roolback index was retrieved
725 */
726static AvbIOResult write_rollback_index(AvbOps *ops,
727 size_t rollback_index_slot,
728 u64 rollback_index)
729{
Jens Wiklander6663e072018-09-25 16:40:20 +0200730#ifndef CONFIG_OPTEE_TA_AVB
Igor Opaniuk3af30e42018-06-03 21:56:38 +0300731 /* For now this is a no-op. */
Igor Opaniuk5d4fd872018-06-03 21:56:40 +0300732 printf("%s not supported yet\n", __func__);
Igor Opaniuk3af30e42018-06-03 21:56:38 +0300733
734 return AVB_IO_RESULT_OK;
Jens Wiklander6663e072018-09-25 16:40:20 +0200735#else
736 struct tee_param param[2];
737
738 if (rollback_index_slot >= TA_AVB_MAX_ROLLBACK_LOCATIONS)
739 return AVB_IO_RESULT_ERROR_NO_SUCH_VALUE;
740
741 memset(param, 0, sizeof(param));
742 param[0].attr = TEE_PARAM_ATTR_TYPE_VALUE_INPUT;
743 param[0].u.value.a = rollback_index_slot;
744 param[1].attr = TEE_PARAM_ATTR_TYPE_VALUE_INPUT;
745 param[1].u.value.a = (u32)(rollback_index >> 32);
746 param[1].u.value.b = (u32)rollback_index;
747
748 return invoke_func(ops->user_data, TA_AVB_CMD_WRITE_ROLLBACK_INDEX,
749 ARRAY_SIZE(param), param);
750#endif
Igor Opaniuk3af30e42018-06-03 21:56:38 +0300751}
752
753/**
754 * read_is_device_unlocked() - gets whether the device is unlocked
755 *
756 * @ops: contains AVB ops handlers
757 * @out_is_unlocked: device unlock state is stored here, true if unlocked,
758 * false otherwise
759 *
760 * @return:
761 * AVB_IO_RESULT_OK: state is retrieved successfully
762 * AVB_IO_RESULT_ERROR_IO: an error occurred
763 */
764static AvbIOResult read_is_device_unlocked(AvbOps *ops, bool *out_is_unlocked)
765{
Jens Wiklander6663e072018-09-25 16:40:20 +0200766#ifndef CONFIG_OPTEE_TA_AVB
Igor Opaniuk3af30e42018-06-03 21:56:38 +0300767 /* For now we always return that the device is unlocked. */
768
Igor Opaniuk5d4fd872018-06-03 21:56:40 +0300769 printf("%s not supported yet\n", __func__);
Igor Opaniuk3af30e42018-06-03 21:56:38 +0300770
771 *out_is_unlocked = true;
772
773 return AVB_IO_RESULT_OK;
Jens Wiklander6663e072018-09-25 16:40:20 +0200774#else
775 AvbIOResult rc;
776 struct tee_param param = { .attr = TEE_PARAM_ATTR_TYPE_VALUE_OUTPUT };
777
778 rc = invoke_func(ops->user_data, TA_AVB_CMD_READ_LOCK_STATE, 1, &param);
779 if (rc)
780 return rc;
781 *out_is_unlocked = !param.u.value.a;
782 return AVB_IO_RESULT_OK;
783#endif
Igor Opaniuk3af30e42018-06-03 21:56:38 +0300784}
785
786/**
787 * get_unique_guid_for_partition() - gets the GUID for a partition identified
788 * by a string name
789 *
790 * @ops: contains AVB ops handlers
791 * @partition: partition name (NUL-terminated UTF-8 string)
792 * @guid_buf: buf, used to copy in GUID string. Example of value:
793 * 527c1c6d-6361-4593-8842-3c78fcd39219
794 * @guid_buf_size: @guid_buf buffer size
795 *
796 * @return:
797 * AVB_IO_RESULT_OK, on success (GUID found)
798 * AVB_IO_RESULT_ERROR_IO, if incorrect buffer size (@guid_buf_size) was
799 * provided
800 * AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION, if partition was not found
801 */
802static AvbIOResult get_unique_guid_for_partition(AvbOps *ops,
803 const char *partition,
804 char *guid_buf,
805 size_t guid_buf_size)
806{
807 struct mmc_part *part;
808 size_t uuid_size;
809
810 part = get_partition(ops, partition);
811 if (!part)
812 return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
813
814 uuid_size = sizeof(part->info.uuid);
815 if (uuid_size > guid_buf_size)
816 return AVB_IO_RESULT_ERROR_IO;
817
818 memcpy(guid_buf, part->info.uuid, uuid_size);
819 guid_buf[uuid_size - 1] = 0;
820
821 return AVB_IO_RESULT_OK;
822}
823
824/**
Igor Opaniuk7a5fbfe2018-08-10 16:59:59 +0300825 * get_size_of_partition() - gets the size of a partition identified
826 * by a string name
827 *
828 * @ops: contains AVB ops handlers
829 * @partition: partition name (NUL-terminated UTF-8 string)
830 * @out_size_num_bytes: returns the value of a partition size
831 *
832 * @return:
833 * AVB_IO_RESULT_OK, on success (GUID found)
834 * AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE, out_size_num_bytes is NULL
835 * AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION, if partition was not found
836 */
837static AvbIOResult get_size_of_partition(AvbOps *ops,
838 const char *partition,
839 u64 *out_size_num_bytes)
840{
841 struct mmc_part *part;
842
843 if (!out_size_num_bytes)
844 return AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE;
845
846 part = get_partition(ops, partition);
847 if (!part)
848 return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
849
850 *out_size_num_bytes = part->info.blksz * part->info.size;
851
852 return AVB_IO_RESULT_OK;
853}
854
Sam Protsenkof254bd02019-07-31 19:59:08 +0300855#ifdef CONFIG_OPTEE_TA_AVB
Igor Opaniukfc1fe012019-04-09 15:38:14 +0200856static AvbIOResult read_persistent_value(AvbOps *ops,
857 const char *name,
858 size_t buffer_size,
859 u8 *out_buffer,
860 size_t *out_num_bytes_read)
861{
862 AvbIOResult rc;
863 struct tee_shm *shm_name;
864 struct tee_shm *shm_buf;
865 struct tee_param param[2];
866 struct udevice *tee;
867 size_t name_size = strlen(name) + 1;
868
869 if (get_open_session(ops->user_data))
870 return AVB_IO_RESULT_ERROR_IO;
871
872 tee = ((struct AvbOpsData *)ops->user_data)->tee;
873
874 rc = tee_shm_alloc(tee, name_size,
875 TEE_SHM_ALLOC, &shm_name);
876 if (rc)
877 return AVB_IO_RESULT_ERROR_OOM;
878
879 rc = tee_shm_alloc(tee, buffer_size,
880 TEE_SHM_ALLOC, &shm_buf);
881 if (rc) {
882 rc = AVB_IO_RESULT_ERROR_OOM;
883 goto free_name;
884 }
885
886 memcpy(shm_name->addr, name, name_size);
887
888 memset(param, 0, sizeof(param));
889 param[0].attr = TEE_PARAM_ATTR_TYPE_MEMREF_INPUT;
890 param[0].u.memref.shm = shm_name;
891 param[0].u.memref.size = name_size;
892 param[1].attr = TEE_PARAM_ATTR_TYPE_MEMREF_INOUT;
893 param[1].u.memref.shm = shm_buf;
894 param[1].u.memref.size = buffer_size;
895
896 rc = invoke_func(ops->user_data, TA_AVB_CMD_READ_PERSIST_VALUE,
897 2, param);
898 if (rc)
899 goto out;
900
901 if (param[1].u.memref.size > buffer_size) {
902 rc = AVB_IO_RESULT_ERROR_NO_SUCH_VALUE;
903 goto out;
904 }
905
906 *out_num_bytes_read = param[1].u.memref.size;
907
908 memcpy(out_buffer, shm_buf->addr, *out_num_bytes_read);
909
910out:
911 tee_shm_free(shm_buf);
912free_name:
913 tee_shm_free(shm_name);
914
915 return rc;
916}
917
918static AvbIOResult write_persistent_value(AvbOps *ops,
919 const char *name,
920 size_t value_size,
921 const u8 *value)
922{
923 AvbIOResult rc;
924 struct tee_shm *shm_name;
925 struct tee_shm *shm_buf;
926 struct tee_param param[2];
927 struct udevice *tee;
928 size_t name_size = strlen(name) + 1;
929
930 if (get_open_session(ops->user_data))
931 return AVB_IO_RESULT_ERROR_IO;
932
933 tee = ((struct AvbOpsData *)ops->user_data)->tee;
934
935 if (!value_size)
936 return AVB_IO_RESULT_ERROR_NO_SUCH_VALUE;
937
938 rc = tee_shm_alloc(tee, name_size,
939 TEE_SHM_ALLOC, &shm_name);
940 if (rc)
941 return AVB_IO_RESULT_ERROR_OOM;
942
943 rc = tee_shm_alloc(tee, value_size,
944 TEE_SHM_ALLOC, &shm_buf);
945 if (rc) {
946 rc = AVB_IO_RESULT_ERROR_OOM;
947 goto free_name;
948 }
949
950 memcpy(shm_name->addr, name, name_size);
951 memcpy(shm_buf->addr, value, value_size);
952
953 memset(param, 0, sizeof(param));
954 param[0].attr = TEE_PARAM_ATTR_TYPE_MEMREF_INPUT;
955 param[0].u.memref.shm = shm_name;
956 param[0].u.memref.size = name_size;
957 param[1].attr = TEE_PARAM_ATTR_TYPE_MEMREF_INPUT;
958 param[1].u.memref.shm = shm_buf;
959 param[1].u.memref.size = value_size;
960
961 rc = invoke_func(ops->user_data, TA_AVB_CMD_WRITE_PERSIST_VALUE,
962 2, param);
963 if (rc)
964 goto out;
965
966out:
967 tee_shm_free(shm_buf);
968free_name:
969 tee_shm_free(shm_name);
970
971 return rc;
972}
Sam Protsenkof254bd02019-07-31 19:59:08 +0300973#endif
974
Igor Opaniuk7a5fbfe2018-08-10 16:59:59 +0300975/**
Igor Opaniuk3af30e42018-06-03 21:56:38 +0300976 * ============================================================================
977 * AVB2.0 AvbOps alloc/initialisation/free
978 * ============================================================================
979 */
980AvbOps *avb_ops_alloc(int boot_device)
981{
982 struct AvbOpsData *ops_data;
983
984 ops_data = avb_calloc(sizeof(struct AvbOpsData));
985 if (!ops_data)
986 return NULL;
987
988 ops_data->ops.user_data = ops_data;
989
990 ops_data->ops.read_from_partition = read_from_partition;
991 ops_data->ops.write_to_partition = write_to_partition;
992 ops_data->ops.validate_vbmeta_public_key = validate_vbmeta_public_key;
993 ops_data->ops.read_rollback_index = read_rollback_index;
994 ops_data->ops.write_rollback_index = write_rollback_index;
995 ops_data->ops.read_is_device_unlocked = read_is_device_unlocked;
996 ops_data->ops.get_unique_guid_for_partition =
997 get_unique_guid_for_partition;
Igor Opaniukfc1fe012019-04-09 15:38:14 +0200998#ifdef CONFIG_OPTEE_TA_AVB
999 ops_data->ops.write_persistent_value = write_persistent_value;
1000 ops_data->ops.read_persistent_value = read_persistent_value;
1001#endif
Igor Opaniuk7a5fbfe2018-08-10 16:59:59 +03001002 ops_data->ops.get_size_of_partition = get_size_of_partition;
Igor Opaniuk3af30e42018-06-03 21:56:38 +03001003 ops_data->mmc_dev = boot_device;
1004
1005 return &ops_data->ops;
1006}
1007
1008void avb_ops_free(AvbOps *ops)
1009{
1010 struct AvbOpsData *ops_data;
1011
Eugeniu Rosca47e41632018-08-14 02:43:08 +02001012 if (!ops)
Igor Opaniuk3af30e42018-06-03 21:56:38 +03001013 return;
1014
1015 ops_data = ops->user_data;
1016
Jens Wiklander6663e072018-09-25 16:40:20 +02001017 if (ops_data) {
1018#ifdef CONFIG_OPTEE_TA_AVB
1019 if (ops_data->tee)
1020 tee_close_session(ops_data->tee, ops_data->session);
1021#endif
Igor Opaniuk3af30e42018-06-03 21:56:38 +03001022 avb_free(ops_data);
Jens Wiklander6663e072018-09-25 16:40:20 +02001023 }
Igor Opaniuk3af30e42018-06-03 21:56:38 +03001024}