LK 的 AVB 验证流程

1 load_vfy_boot函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
int load_vfy_boot(uint32_t bootimg_type, uint32_t addr)
{
#ifdef FEATURE_XBOOT
if(bootimg_type != BOOTIMG_TYPE_XFL) {
#endif
uint32_t img_vfy_time = 0;
AvbSlotVerifyResult ret = AVB_SLOT_VERIFY_RESULT_OK;
AvbSlotVerifyData *slot_data = NULL;
AvbSlotVerifyFlags avb_flag = AVB_SLOT_VERIFY_FLAGS_NONE;
uint32_t lock_state = LKS_DEFAULT;
img_vfy_time = get_timer(0);
g_boot_state = BOOT_STATE_RED;
if (load_bootimg_hdr(bootimg_type) != 0)
return -1;
/* heap initialization for avb */
avb_heap_sz = AVB_HEAP_SZ;
pal_log_debug("[avb] avb heap alloc size 0x%x\n", avb_heap_sz);
avb_heap = (void *)mblock_reserve_ext(&g_boot_arg->mblock_info,
avb_heap_sz,
4 * KB,
0xc0000000,
0,
"avb");
if (avb_heap == 0) {
pal_log_err("[avb] avb heap alloc fails\n");
avb_heap_sz = 0;
return -1;
} else
pal_log_debug("[avb] avb heap alloc 0x%x\n", (uint32_t)avb_heap);

if (boot_authentication(bootimg_type) == 0)
avb_flag = AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR;

switch (bootimg_type) {
case BOOTIMG_TYPE_BOOT:
case BOOTIMG_TYPE_RECOVERY:
// Both preloader and avb_ab_flow function decrease tries_remaining variable
// when successfully_boot is equal to 0, so it needs to increase tries_remaining
// here.

// Increase tries_remaining only in following three conditions
// 1. tries_remaining < AVB_AB_MAX_TRIES_REMAINING
// 2. tries_remaining > 0
// 3. successful_boot is equal to 0
increase_tries_remaining();
ret = avb_ab_flow(&ab_ops,
boot_partitions,
avb_flag,
AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE,
&slot_data);

pal_log_err("[avb] load_vfy_boot: avb_flag = %d\n", avb_flag);
if (avb_flag & AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR)
ret = AVB_SLOT_VERIFY_RESULT_OK;

if (ret != AVB_SLOT_VERIFY_RESULT_OK)
goto end;

break;
default:
ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
goto end;
}

if (ret == AVB_SLOT_VERIFY_RESULT_OK) {
ret = boot_post_processing(bootimg_type, slot_data);
if (ret)
goto end;
g_boot_state = BOOT_STATE_GREEN;
}

end:
pal_log_err("[avb] boot/recovery vfy time = %d ms\n",
(unsigned int)get_timer(img_vfy_time));

/* After this function call, memory is returned to lk.
* Please avoid using avb_heap after this function call
*/
mblock_create(&g_boot_arg->mblock_info,
&g_boot_arg->orig_dram_info,
(uint64_t)avb_heap & 0xffffffff,
(uint64_t)avb_heap_sz & 0xffffffff);

pal_log_err("[avb] load_vfy_boot: ret = %d\n", ret);

/* if device state is "unlocked," override
* boot state with "ORANGE."
*/
ret = get_lock_state(&lock_state);
if (ret == 0 && lock_state == LKS_UNLOCK)
g_boot_state = BOOT_STATE_ORANGE;

ret = (int)handle_vboot_state();

return ret;
#ifdef FEATURE_XBOOT
} else {
int status = 0;
char bootimg_name[16];
unsigned int kimg_load_addr = 0;
char vboot_cmdline[TMPBUF_SIZE] = {0};
char vboot_cmdline_ab[TMPBUF_SIZE] = {0};

if (load_bootimg_hdr(bootimg_type) != 0)
return -1;

if (g_is_64bit_kernel)
kimg_load_addr = (uint32_t)target_get_scratch_address();
else
kimg_load_addr = (uint32_t)get_kernel_target_addr();

/* load xflimg with suffix: xfl_a or xfl_b */
snprintf(bootimg_name, sizeof(bootimg_name), "xfl%s", get_suffix());

status = mboot_android_load_bootimg_hdr(bootimg_name, addr);
if (status < 0)
msg_header_error("Android Boot Image");

status = mboot_android_load_bootimg(bootimg_name, kimg_load_addr);
if (status < 0)
msg_img_error("Android Boot Image");
else
set_bootimg_loaded(kimg_load_addr);

cmdline_append("root=/dev/ram");

snprintf(vboot_cmdline_ab, TMPBUF_SIZE,
"androidboot.slot_suffix=%s androidboot.slot=%s",
get_suffix(), get_suffix() + 1);
cmdline_append(vboot_cmdline_ab);

dm_verity_handler();

return status;
}
#endif
}

2. “[avb] img_auth_required = 0”

bootable/bootloader/lk/platform/common/boot/avb20/load_vfy_boot_ab.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
static uint32_t boot_authentication(uint32_t bootimg_type)
{
#ifdef SECURITY_SW_SUPPORT
uint32_t policy_entry_idx = 0;
uint32_t img_auth_required = 0;
if (bootimg_type == BOOTIMG_TYPE_BOOT)
policy_entry_idx = get_policy_entry_idx(boot_partitions[0]);
else if (bootimg_type == BOOTIMG_TYPE_RECOVERY)
policy_entry_idx = get_policy_entry_idx(recovery_partitions[0]);
else {
pal_log_err("[avb] invalid boot image type\n");
return 1;
}
img_auth_required = get_vfy_policy(policy_entry_idx);
pal_log_err("[avb] img_auth_required = %d\n", img_auth_required);
return img_auth_required;
#else
pal_log_err("[avb] img_auth_required = 0\n");
return 0;
#endif
}

3. “[AVB20] lock_state = 0x1”

bootable/bootloader/lk/platform/common/avb/avb_hal/avb_hal.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
AvbIOResult avb_hal_read_is_device_unlocked(AvbOps *ops, bool *out_is_unlocked)
{
uint32_t ret = 0;
uint32_t lock_state = LKS_DEFAULT;
if (out_is_unlocked == NULL)
return AVB_IO_RESULT_ERROR_IO;
*out_is_unlocked = FALSE;
ret = get_lock_state(&lock_state);
if (ret != 0)
return AVB_IO_RESULT_ERROR_IO;
if ((lock_state == LKS_DEFAULT) || (lock_state == LKS_MP_DEFAULT) ||
lock_state == LKS_LOCK)
*out_is_unlocked = FALSE;
else
*out_is_unlocked = TRUE;
pal_log_err("[AVB20] lock_state = 0x%x\n", lock_state);
return AVB_IO_RESULT_OK;
}

4. “ERROR: Failed to allocate memory.”

bootable/bootloader/lk/platform/common/avb/libavb/avb_util.c

1
2
3
4
5
6
7
8
void* avb_malloc(size_t size) {
void* ret = avb_malloc_(size);
if (ret == NULL) {
avb_error("Failed to allocate memory.\n");
return NULL;
}
return ret;
}

5. “[AVB20] molloc: heap size not enough”

bootable/bootloader/lk/platform/common/avb/libavb/avb_sysdeps_posix.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void *avb_malloc_(size_t size)
{
uint32_t given_size = 0;
uint32_t ret_addr = 0;
uint32_t heap_max_size = avb_heap_sz;
/* the size is bytes */
if (size == 0) {
pal_log_err("[%s] malloc: try to allocate size zero\n", MOD);
return NULL;
}
if (size > heap_max_size) {
pal_log_err("[%s] malloc: heap size too small\n", MOD);
return NULL;
}
if ((g_avb_heap_cur_alloc + size) > heap_max_size) {
pal_log_err("[%s] malloc: heap size not enough\n", MOD);
return NULL;
}
/* alignment to 4 bytes */
given_size = ((size + 3) / 4) * 4;
ret_addr = avb_heap + g_avb_heap_cur_alloc;
g_avb_heap_cur_alloc += given_size;
return (void *)ret_addr;
}

6. “[avb] boot/recovery vfy time = 1168 ms”, “[avb] ret = 2”

bootable/bootloader/lk/platform/common/boot/avb20/load_vfy_boot_ab.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
int load_vfy_boot(uint32_t bootimg_type, uint32_t addr)
{
#ifdef FEATURE_XBOOT
if(bootimg_type != BOOTIMG_TYPE_XFL) {
#endif
...
end:
pal_log_err("[avb] boot/recovery vfy time = %d ms\n",
(unsigned int)get_timer(img_vfy_time));
/* After this function call, memory is returned to lk.
* Please avoid using avb_heap after this function call
*/
mblock_create(&g_boot_arg->mblock_info,
&g_boot_arg->orig_dram_info,
(uint64_t)avb_heap & 0xffffffff,
(uint64_t)avb_heap_sz & 0xffffffff);
pal_log_err("[avb] ret = %d\n", ret);
/* if device state is "unlocked," override
* boot state with "ORANGE."
*/
ret = get_lock_state(&lock_state);
if (ret == 0 && lock_state == LKS_UNLOCK)
g_boot_state = BOOT_STATE_ORANGE;
ret = (int)handle_vboot_state();
return ret;#ifdef FEATURE_XBOOT
} else {
...
}
#endif
}