xref: /rk3399_rockchip-uboot/lib/avb/libavb_user/avb_ops_user.c (revision 39d40ad54eb2274a86419000e0e087673f86508a)
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Permission is hereby granted, free of charge, to any person
5  * obtaining a copy of this software and associated documentation
6  * files (the "Software"), to deal in the Software without
7  * restriction, including without limitation the rights to use, copy,
8  * modify, merge, publish, distribute, sublicense, and/or sell copies
9  * of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
24 
25 #include <common.h>
26 #include <image.h>
27 #include <android_image.h>
28 #include <malloc.h>
29 #include <mapmem.h>
30 #include <errno.h>
31 #include <command.h>
32 #include <mmc.h>
33 #include <blk.h>
34 #include <part.h>
35 #include <stdio.h>
36 #include <android_avb/avb_ops_user.h>
37 #include <android_avb/libavb_ab.h>
38 #include <android_avb/avb_atx_validate.h>
39 #include <android_avb/avb_atx_types.h>
40 #include <optee_include/OpteeClientInterface.h>
41 #include <optee_include/tee_api_defines.h>
42 #include <android_avb/avb_vbmeta_image.h>
43 #include <android_avb/avb_atx_validate.h>
44 #include <boot_rkimg.h>
45 
46 static void byte_to_block(int64_t *offset,
47 			  size_t *num_bytes,
48 			  lbaint_t *offset_blk,
49 			  lbaint_t *blkcnt)
50 {
51 	*offset_blk = (lbaint_t)(*offset / 512);
52 	if (*num_bytes % 512 == 0) {
53 		if (*offset % 512 == 0)
54 			*blkcnt = (lbaint_t)(*num_bytes / 512);
55 		else
56 			*blkcnt = (lbaint_t)(*num_bytes / 512) + 1;
57 	} else {
58 		if (*offset % 512 == 0) {
59 			*blkcnt = (lbaint_t)(*num_bytes / 512) + 1;
60 		} else {
61 			if ((*offset % 512) + (*num_bytes % 512) < 512 ||
62 			    (*offset % 512) + (*num_bytes % 512) == 512) {
63 				*blkcnt = (lbaint_t)(*num_bytes / 512) + 1;
64 			} else {
65 				*blkcnt = (lbaint_t)(*num_bytes / 512) + 2;
66 			}
67 		}
68 	}
69 }
70 
71 static AvbIOResult get_size_of_partition(AvbOps *ops,
72 					 const char *partition,
73 					 uint64_t *out_size_in_bytes)
74 {
75 	struct blk_desc *dev_desc;
76 	disk_partition_t part_info;
77 
78 	dev_desc = rockchip_get_bootdev();
79 	if (!dev_desc) {
80 		printf("%s: Could not find device\n", __func__);
81 		return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
82 	}
83 
84 	if (part_get_info_by_name(dev_desc, partition, &part_info) < 0)
85 		return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
86 
87 	*out_size_in_bytes = (part_info.size) * 512;
88 	return AVB_IO_RESULT_OK;
89 }
90 
91 static AvbIOResult read_from_partition(AvbOps *ops,
92 				       const char *partition,
93 				       int64_t offset,
94 				       size_t num_bytes,
95 				       void *buffer,
96 				       size_t *out_num_read)
97 {
98 	struct blk_desc *dev_desc;
99 	lbaint_t offset_blk, blkcnt;
100 	disk_partition_t part_info;
101 	uint64_t partition_size;
102 
103 	if (offset < 0) {
104 		if (get_size_of_partition(ops, partition, &partition_size))
105 			return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
106 
107 		if (-offset > partition_size)
108 			return AVB_IO_RESULT_ERROR_RANGE_OUTSIDE_PARTITION;
109 
110 		offset = partition_size - (-offset);
111 	}
112 
113 	byte_to_block(&offset, &num_bytes, &offset_blk, &blkcnt);
114 	dev_desc = rockchip_get_bootdev();
115 	if (!dev_desc) {
116 		printf("%s: Could not find device\n", __func__);
117 		return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
118 	}
119 
120 	if (part_get_info_by_name(dev_desc, partition, &part_info) < 0) {
121 		printf("Could not find \"%s\" partition\n", partition);
122 		return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
123 	}
124 
125 	if ((offset % 512 == 0) && (num_bytes % 512 == 0)) {
126 		blk_dread(dev_desc, part_info.start + offset_blk,
127 			  blkcnt, buffer);
128 		*out_num_read = blkcnt * 512;
129 	} else {
130 		char *buffer_temp;
131 
132 		buffer_temp = malloc(512 * blkcnt);
133 		if (!buffer_temp) {
134 			printf("malloc error!\n");
135 			return AVB_IO_RESULT_ERROR_OOM;
136 		}
137 		blk_dread(dev_desc, part_info.start + offset_blk,
138 			  blkcnt, buffer_temp);
139 		memcpy(buffer, buffer_temp + (offset % 512), num_bytes);
140 		*out_num_read = num_bytes;
141 		free(buffer_temp);
142 	}
143 
144 	return AVB_IO_RESULT_OK;
145 }
146 
147 static AvbIOResult write_to_partition(AvbOps *ops,
148 				      const char *partition,
149 				      int64_t offset,
150 				      size_t num_bytes,
151 				      const void *buffer)
152 {
153 	struct blk_desc *dev_desc;
154 	char *buffer_temp;
155 	disk_partition_t part_info;
156 	lbaint_t offset_blk, blkcnt;
157 
158 	byte_to_block(&offset, &num_bytes, &offset_blk, &blkcnt);
159 	buffer_temp = malloc(512 * blkcnt);
160 	if (!buffer_temp) {
161 		printf("malloc error!\n");
162 		return AVB_IO_RESULT_ERROR_OOM;
163 	}
164 	memset(buffer_temp, 0, 512 * blkcnt);
165 	dev_desc = rockchip_get_bootdev();
166 	if (!dev_desc) {
167 		printf("%s: Could not find device\n", __func__);
168 		return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
169 	}
170 
171 	if (part_get_info_by_name(dev_desc, partition, &part_info) < 0) {
172 		printf("Could not find \"%s\" partition\n", partition);
173 		return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
174 	}
175 
176 	if ((offset % 512 != 0) && (num_bytes % 512) != 0)
177 		blk_dread(dev_desc, part_info.start + offset_blk,
178 			  blkcnt, buffer_temp);
179 
180 	memcpy(buffer_temp, buffer + (offset % 512), num_bytes);
181 	blk_dwrite(dev_desc, part_info.start + offset_blk, blkcnt, buffer);
182 	free(buffer_temp);
183 
184 	return AVB_IO_RESULT_OK;
185 }
186 
187 static AvbIOResult
188 validate_vbmeta_public_key(AvbOps *ops,
189 			   const uint8_t *public_key_data,
190 			   size_t public_key_length,
191 			   const uint8_t *public_key_metadata,
192 			   size_t public_key_metadata_length,
193 			   bool *out_is_trusted)
194 {
195 /* remain AVB_VBMETA_PUBLIC_KEY_VALIDATE to compatible legacy code */
196 #if defined(CONFIG_AVB_VBMETA_PUBLIC_KEY_VALIDATE) || \
197     defined(AVB_VBMETA_PUBLIC_KEY_VALIDATE)
198 	if (out_is_trusted) {
199 		avb_atx_validate_vbmeta_public_key(ops,
200 						   public_key_data,
201 						   public_key_length,
202 						   public_key_metadata,
203 						   public_key_metadata_length,
204 						   out_is_trusted);
205 	}
206 #else
207 	if (out_is_trusted)
208 		*out_is_trusted = true;
209 #endif
210 	return AVB_IO_RESULT_OK;
211 }
212 
213 static AvbIOResult read_rollback_index(AvbOps *ops,
214 				       size_t rollback_index_location,
215 				       uint64_t *out_rollback_index)
216 {
217 	if (out_rollback_index) {
218 #ifdef CONFIG_OPTEE_CLIENT
219 		int ret;
220 
221 		ret = trusty_read_rollback_index(rollback_index_location,
222 						 out_rollback_index);
223 		switch (ret) {
224 		case TEE_SUCCESS:
225 			ret = AVB_IO_RESULT_OK;
226 			break;
227 		case TEE_ERROR_GENERIC:
228 		case TEE_ERROR_NO_DATA:
229 		case TEE_ERROR_ITEM_NOT_FOUND:
230 			*out_rollback_index = 0;
231 			ret = trusty_write_rollback_index(rollback_index_location,
232 							  *out_rollback_index);
233 			if (ret) {
234 				printf("%s: init rollback index error\n",
235 				       __FILE__);
236 				ret = AVB_IO_RESULT_ERROR_IO;
237 			} else {
238 				ret =
239 				trusty_read_rollback_index(rollback_index_location,
240 							   out_rollback_index);
241 				if (ret)
242 					ret = AVB_IO_RESULT_ERROR_IO;
243 				else
244 					ret = AVB_IO_RESULT_OK;
245 			}
246 			break;
247 		default:
248 			ret = AVB_IO_RESULT_ERROR_IO;
249 			printf("%s: trusty_read_rollback_index failed",
250 			       __FILE__);
251 		}
252 
253 		return ret;
254 #else
255 		*out_rollback_index = 0;
256 
257 		return AVB_IO_RESULT_OK;
258 #endif
259 	}
260 
261 	return AVB_IO_RESULT_ERROR_IO;
262 }
263 
264 static AvbIOResult write_rollback_index(AvbOps *ops,
265 					size_t rollback_index_location,
266 					uint64_t rollback_index)
267 {
268 #ifdef CONFIG_OPTEE_CLIENT
269 	if (trusty_write_rollback_index(rollback_index_location,
270 					rollback_index)) {
271 		printf("%s: Fail to write rollback index\n", __FILE__);
272 		return AVB_IO_RESULT_ERROR_IO;
273 	}
274 	return AVB_IO_RESULT_OK;
275 #endif
276 	return AVB_IO_RESULT_ERROR_IO;
277 }
278 
279 static AvbIOResult read_is_device_unlocked(AvbOps *ops, bool *out_is_unlocked)
280 {
281 	if (out_is_unlocked) {
282 #ifdef CONFIG_OPTEE_CLIENT
283 		uint8_t vboot_flag = 0;
284 		int ret;
285 
286 		ret = trusty_read_lock_state((uint8_t *)out_is_unlocked);
287 		switch (ret) {
288 		case TEE_SUCCESS:
289 			ret = AVB_IO_RESULT_OK;
290 			break;
291 		case TEE_ERROR_GENERIC:
292 		case TEE_ERROR_NO_DATA:
293 		case TEE_ERROR_ITEM_NOT_FOUND:
294 			if (trusty_read_vbootkey_enable_flag(&vboot_flag)) {
295 				printf("Can't read vboot flag\n");
296 				return AVB_IO_RESULT_ERROR_IO;
297 			}
298 
299 			if (vboot_flag)
300 				*out_is_unlocked = 0;
301 			else
302 				*out_is_unlocked = 1;
303 
304 			if (trusty_write_lock_state(*out_is_unlocked)) {
305 				printf("%s: init lock state error\n", __FILE__);
306 				ret = AVB_IO_RESULT_ERROR_IO;
307 			} else {
308 				ret =
309 				trusty_read_lock_state((uint8_t *)out_is_unlocked);
310 				if (ret == 0)
311 					ret = AVB_IO_RESULT_OK;
312 				else
313 					ret = AVB_IO_RESULT_ERROR_IO;
314 			}
315 			break;
316 		default:
317 			ret = AVB_IO_RESULT_ERROR_IO;
318 			printf("%s: trusty_read_lock_state failed\n", __FILE__);
319 		}
320 		return ret;
321 #else
322 		*out_is_unlocked = 1;
323 
324 		return AVB_IO_RESULT_OK;
325 #endif
326 	}
327 	return AVB_IO_RESULT_ERROR_IO;
328 }
329 
330 static AvbIOResult write_is_device_unlocked(AvbOps *ops, bool *out_is_unlocked)
331 {
332 	if (out_is_unlocked) {
333 #ifdef CONFIG_OPTEE_CLIENT
334 		if (trusty_write_lock_state(*out_is_unlocked)) {
335 			printf("%s: Fail to write lock state\n", __FILE__);
336 			return AVB_IO_RESULT_ERROR_IO;
337 		}
338 		return AVB_IO_RESULT_OK;
339 #endif
340 	}
341 	return AVB_IO_RESULT_ERROR_IO;
342 }
343 
344 static AvbIOResult get_unique_guid_for_partition(AvbOps *ops,
345 						 const char *partition,
346 						 char *guid_buf,
347 						 size_t guid_buf_size)
348 {
349 #if CONFIG_IS_ENABLED(PARTITION_UUIDS)
350 	struct blk_desc *dev_desc;
351 	disk_partition_t part_info;
352 
353 	dev_desc = rockchip_get_bootdev();
354 	if (!dev_desc) {
355 		printf("%s: Could not find device\n", __func__);
356 		return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
357 	}
358 
359 	if (part_get_info_by_name(dev_desc, partition, &part_info) < 0) {
360 		printf("Could not find \"%s\" partition\n", partition);
361 		return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
362 	}
363 
364 	if (guid_buf && guid_buf_size > 0)
365 		memcpy(guid_buf, part_info.uuid, guid_buf_size);
366 
367 	return AVB_IO_RESULT_OK;
368 #else
369 	printf("WARN: Get partition uuid requires CONFIG_PARTITION_UUIDS enabled\n");
370 	return AVB_IO_RESULT_ERROR_NO_SUCH_VALUE;
371 #endif
372 }
373 
374 /* read permanent attributes from rpmb */
375 AvbIOResult avb_read_perm_attr(AvbAtxOps *atx_ops,
376 			       AvbAtxPermanentAttributes *attributes)
377 {
378 	if (attributes) {
379 #ifdef CONFIG_OPTEE_CLIENT
380 		trusty_read_permanent_attributes((uint8_t *)attributes,
381 						 sizeof(struct AvbAtxPermanentAttributes));
382 		return AVB_IO_RESULT_OK;
383 #endif
384 	}
385 
386 	return -1;
387 }
388 
389 /*read permanent attributes hash from efuse */
390 AvbIOResult avb_read_perm_attr_hash(AvbAtxOps *atx_ops,
391 				    uint8_t hash[AVB_SHA256_DIGEST_SIZE])
392 {
393 #ifndef CONFIG_ROCKCHIP_PRELOADER_PUB_KEY
394 #ifdef CONFIG_OPTEE_CLIENT
395 	if (trusty_read_attribute_hash((uint32_t *)hash,
396 				       AVB_SHA256_DIGEST_SIZE / 4))
397 		return -1;
398 #else
399 	printf("Please open the macro!\n");
400 	return -1;
401 #endif
402 #endif
403 	return AVB_IO_RESULT_OK;
404 }
405 
406 static void avb_set_key_version(AvbAtxOps *atx_ops,
407 				size_t rollback_index_location,
408 				uint64_t key_version)
409 {
410 #ifdef CONFIG_OPTEE_CLIENT
411 	uint64_t key_version_temp = 0;
412 
413 	if (trusty_read_rollback_index(rollback_index_location, &key_version_temp))
414 		printf("%s: Fail to read rollback index\n", __FILE__);
415 	if (key_version_temp == key_version)
416 		return;
417 	if (trusty_write_rollback_index(rollback_index_location, key_version))
418 		printf("%s: Fail to write rollback index\n", __FILE__);
419 #endif
420 }
421 
422 AvbIOResult rk_get_random(AvbAtxOps *atx_ops,
423 			  size_t num_bytes,
424 			  uint8_t *output)
425 {
426 	int i;
427 	unsigned int seed;
428 
429 	seed = (unsigned int)get_timer(0);
430 	for (i = 0; i < num_bytes; i++) {
431 		srand(seed);
432 		output[i] = (uint8_t)(rand());
433 		seed = (unsigned int)(output[i]);
434 	}
435 
436 	return 0;
437 }
438 
439 #ifdef CONFIG_ANDROID_BOOT_IMAGE
440 static AvbIOResult get_preloaded_partition(AvbOps* ops,
441 					   const char* partition,
442 					   size_t num_bytes,
443 					   uint8_t** out_pointer,
444 					   size_t* out_num_bytes_preloaded,
445 					   int allow_verification_error)
446 {
447 	struct preloaded_partition *preload_info = NULL;
448 	struct AvbOpsData *data = ops->user_data;
449 	struct blk_desc *dev_desc;
450 	disk_partition_t part_info;
451 	ulong load_addr;
452 	AvbIOResult ret;
453 	int full_preload = 0;
454 
455 	dev_desc = rockchip_get_bootdev();
456 	if (!dev_desc)
457 		return AVB_IO_RESULT_ERROR_IO;
458 
459 	if (part_get_info_by_name(dev_desc, partition, &part_info) < 0) {
460 		printf("Could not find \"%s\" partition\n", partition);
461 		return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
462 	}
463 
464 	/* Record partition name(either boot or recovery) */
465 	if (!strncmp(partition, ANDROID_PARTITION_BOOT, 4) ||
466 	    !strncmp(partition, ANDROID_PARTITION_RECOVERY, 8)) {
467 		data->boot_partition = strdup(partition);
468 #ifdef CONFIG_ANDROID_AB
469 		*((char *)data->boot_partition + strlen(partition) - 2) = '\0';
470 #endif
471 	}
472 
473 	if (!allow_verification_error) {
474 		if (!strncmp(partition, ANDROID_PARTITION_BOOT, 4) ||
475 		    !strncmp(partition, ANDROID_PARTITION_RECOVERY, 8))
476 			preload_info = &data->boot;
477 		else if (!strncmp(partition, ANDROID_PARTITION_VENDOR_BOOT, 11))
478 			preload_info = &data->vendor_boot;
479 		else if (!strncmp(partition, ANDROID_PARTITION_INIT_BOOT, 9))
480 			preload_info = &data->init_boot;
481 		else if (!strncmp(partition, ANDROID_PARTITION_RESOURCE, 8))
482 			preload_info = &data->resource;
483 
484 		if (!preload_info) {
485 			printf("Error: unknown full load partition '%s'\n", partition);
486 			return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
487 		}
488 
489 		printf("preloaded(s): %sfull image from '%s' at 0x%08lx - 0x%08lx\n",
490 		       preload_info->size ? "pre-" : "", partition,
491 		       (ulong)preload_info->addr,
492 		       (ulong)preload_info->addr + num_bytes);
493 
494 		/* If the partition hasn't yet been preloaded, do it now.*/
495 		if (preload_info->size == 0) {
496 			ret = ops->read_from_partition(ops, partition,
497 						       0, num_bytes,
498 						       preload_info->addr,
499 						       &preload_info->size);
500 			if (ret != AVB_IO_RESULT_OK)
501 				return ret;
502 		}
503 		*out_pointer = preload_info->addr;
504 		*out_num_bytes_preloaded = preload_info->size;
505 		ret = AVB_IO_RESULT_OK;
506 	} else {
507 		if (!strncmp(partition, ANDROID_PARTITION_INIT_BOOT, 9) ||
508 		    !strncmp(partition, ANDROID_PARTITION_VENDOR_BOOT, 11) ||
509 		    !strncmp(partition, ANDROID_PARTITION_BOOT, 4) ||
510 		    !strncmp(partition, ANDROID_PARTITION_RECOVERY, 8) ||
511 		    !strncmp(partition, ANDROID_PARTITION_RESOURCE, 8)) {
512 			/* If already full preloaded, just use it */
513 			if (!strncmp(partition, ANDROID_PARTITION_BOOT, 4) ||
514 			    !strncmp(partition, ANDROID_PARTITION_RECOVERY, 8)) {
515 				preload_info = &data->boot;
516 				if (preload_info->size) {
517 					*out_pointer = preload_info->addr;
518 					*out_num_bytes_preloaded = num_bytes;
519 					full_preload = 1;
520 				}
521 			}
522 			printf("preloaded: %s image from '%s\n",
523 			       full_preload ? "pre-full" : "distribute", partition);
524 		} else {
525 			printf("Error: unknown preloaded partition '%s'\n", partition);
526 			return AVB_IO_RESULT_ERROR_OOM;
527 		}
528 
529 		/*
530 		 * Already preloaded during boot/recovery loading,
531 		 * here we just return a dummy buffer.
532 		 */
533 		if (!strncmp(partition, ANDROID_PARTITION_INIT_BOOT, 9) ||
534 		    !strncmp(partition, ANDROID_PARTITION_VENDOR_BOOT, 11) ||
535 		    !strncmp(partition, ANDROID_PARTITION_RESOURCE, 8)) {
536 			*out_pointer = (u8 *)avb_malloc(ARCH_DMA_MINALIGN);
537 			*out_num_bytes_preloaded = num_bytes; /* return what it expects */
538 			return AVB_IO_RESULT_OK;
539 		}
540 
541 		/* If already full preloaded, there is nothing to do and just return */
542 		if (full_preload)
543 			return AVB_IO_RESULT_OK;
544 
545 		/*
546 		 * only boot/recovery partition can reach here
547 		 * and init/vendor_boot are loaded at this round.
548 		 */
549 		load_addr = env_get_ulong("kernel_addr_r", 16, 0);
550 		if (!load_addr)
551 			return AVB_IO_RESULT_ERROR_NO_SUCH_VALUE;
552 
553 		ret = android_image_load_by_partname(dev_desc, partition, &load_addr);
554 		if (!ret) {
555 			*out_pointer = (u8 *)load_addr;
556 			*out_num_bytes_preloaded = num_bytes; /* return what it expects */
557 			ret = AVB_IO_RESULT_OK;
558 		} else {
559 			ret = AVB_IO_RESULT_ERROR_IO;
560 		}
561 	}
562 
563 	return ret;
564 }
565 #endif
566 
567 AvbIOResult validate_public_key_for_partition(AvbOps *ops,
568 					      const char *partition,
569 					      const uint8_t *public_key_data,
570 					      size_t public_key_length,
571 					      const uint8_t *public_key_metadata,
572 					      size_t public_key_metadata_length,
573 					      bool *out_is_trusted,
574 					      uint32_t *out_rollback_index_location)
575 {
576 /* remain AVB_VBMETA_PUBLIC_KEY_VALIDATE to compatible legacy code */
577 #if defined(CONFIG_AVB_VBMETA_PUBLIC_KEY_VALIDATE) || \
578     defined(AVB_VBMETA_PUBLIC_KEY_VALIDATE)
579 	if (out_is_trusted) {
580 		avb_atx_validate_vbmeta_public_key(ops,
581 						   public_key_data,
582 						   public_key_length,
583 						   public_key_metadata,
584 						   public_key_metadata_length,
585 						   out_is_trusted);
586 	}
587 #else
588 	if (out_is_trusted)
589 		*out_is_trusted = true;
590 #endif
591 	*out_rollback_index_location = 0;
592 	return AVB_IO_RESULT_OK;
593 }
594 
595 AvbOps *avb_ops_user_new(void)
596 {
597 	AvbOps *ops = NULL;
598 	struct AvbOpsData *ops_data = NULL;
599 
600 	ops = calloc(1, sizeof(AvbOps));
601 	if (!ops) {
602 		printf("Error allocating memory for AvbOps.\n");
603 		goto out;
604 	}
605 	ops->ab_ops = calloc(1, sizeof(AvbABOps));
606 	if (!ops->ab_ops) {
607 		printf("Error allocating memory for AvbABOps.\n");
608 		free(ops);
609 		goto out;
610 	}
611 
612 	ops->atx_ops = calloc(1, sizeof(AvbAtxOps));
613 	if (!ops->atx_ops) {
614 		printf("Error allocating memory for AvbAtxOps.\n");
615 		free(ops->ab_ops);
616 		free(ops);
617 		goto out;
618 	}
619 
620 	ops_data = calloc(1, sizeof(struct AvbOpsData));
621 	if (!ops_data) {
622 		printf("Error allocating memory for AvbOpsData.\n");
623 		free(ops->atx_ops);
624 		free(ops->ab_ops);
625 		free(ops);
626 		goto out;
627 	}
628 
629 	ops->ab_ops->ops = ops;
630 	ops->atx_ops->ops = ops;
631 	ops_data->ops = ops;
632 	ops->user_data = ops_data;
633 
634 	ops->read_from_partition = read_from_partition;
635 	ops->write_to_partition = write_to_partition;
636 	ops->validate_vbmeta_public_key = validate_vbmeta_public_key;
637 	ops->read_rollback_index = read_rollback_index;
638 	ops->write_rollback_index = write_rollback_index;
639 	ops->read_is_device_unlocked = read_is_device_unlocked;
640 	ops->write_is_device_unlocked = write_is_device_unlocked;
641 	ops->get_unique_guid_for_partition = get_unique_guid_for_partition;
642 	ops->get_size_of_partition = get_size_of_partition;
643 #ifdef CONFIG_ANDROID_BOOT_IMAGE
644 	ops->get_preloaded_partition = get_preloaded_partition;
645 #endif
646 	ops->validate_public_key_for_partition = validate_public_key_for_partition;
647 	ops->ab_ops->read_ab_metadata = avb_ab_data_read;
648 	ops->ab_ops->write_ab_metadata = avb_ab_data_write;
649 	ops->atx_ops->read_permanent_attributes = avb_read_perm_attr;
650 	ops->atx_ops->read_permanent_attributes_hash = avb_read_perm_attr_hash;
651 	ops->atx_ops->set_key_version = avb_set_key_version;
652 	ops->atx_ops->get_random = rk_get_random;
653 
654 	return ops;
655 out:
656 	return NULL;
657 }
658 
659 void avb_ops_user_free(AvbOps *ops)
660 {
661 	free(ops->user_data);
662 	free(ops->ab_ops);
663 	free(ops->atx_ops);
664 	free(ops);
665 }
666