1897a1d94STom Rini // SPDX-License-Identifier: MIT
2d8f9d2afSIgor Opaniuk /*
3d8f9d2afSIgor Opaniuk * Copyright (C) 2016 The Android Open Source Project
4d8f9d2afSIgor Opaniuk */
5d8f9d2afSIgor Opaniuk
6d8f9d2afSIgor Opaniuk #include "avb_cmdline.h"
7d8f9d2afSIgor Opaniuk #include "avb_sha.h"
8d8f9d2afSIgor Opaniuk #include "avb_util.h"
9d8f9d2afSIgor Opaniuk #include "avb_version.h"
10d8f9d2afSIgor Opaniuk
11d8f9d2afSIgor Opaniuk #define NUM_GUIDS 3
12d8f9d2afSIgor Opaniuk
13d8f9d2afSIgor Opaniuk /* Substitutes all variables (e.g. $(ANDROID_SYSTEM_PARTUUID)) with
14d8f9d2afSIgor Opaniuk * values. Returns NULL on OOM, otherwise the cmdline with values
15d8f9d2afSIgor Opaniuk * replaced.
16d8f9d2afSIgor Opaniuk */
avb_sub_cmdline(AvbOps * ops,const char * cmdline,const char * ab_suffix,bool using_boot_for_vbmeta,const AvbCmdlineSubstList * additional_substitutions)17d8f9d2afSIgor Opaniuk char* avb_sub_cmdline(AvbOps* ops,
18d8f9d2afSIgor Opaniuk const char* cmdline,
19d8f9d2afSIgor Opaniuk const char* ab_suffix,
20d8f9d2afSIgor Opaniuk bool using_boot_for_vbmeta,
21d8f9d2afSIgor Opaniuk const AvbCmdlineSubstList* additional_substitutions) {
22d8f9d2afSIgor Opaniuk const char* part_name_str[NUM_GUIDS] = {"system", "boot", "vbmeta"};
23d8f9d2afSIgor Opaniuk const char* replace_str[NUM_GUIDS] = {"$(ANDROID_SYSTEM_PARTUUID)",
24d8f9d2afSIgor Opaniuk "$(ANDROID_BOOT_PARTUUID)",
25d8f9d2afSIgor Opaniuk "$(ANDROID_VBMETA_PARTUUID)"};
26d8f9d2afSIgor Opaniuk char* ret = NULL;
27d8f9d2afSIgor Opaniuk AvbIOResult io_ret;
28d8f9d2afSIgor Opaniuk size_t n;
29d8f9d2afSIgor Opaniuk
30d8f9d2afSIgor Opaniuk /* Special-case for when the top-level vbmeta struct is in the boot
31d8f9d2afSIgor Opaniuk * partition.
32d8f9d2afSIgor Opaniuk */
33d8f9d2afSIgor Opaniuk if (using_boot_for_vbmeta) {
34d8f9d2afSIgor Opaniuk part_name_str[2] = "boot";
35d8f9d2afSIgor Opaniuk }
36d8f9d2afSIgor Opaniuk
37d8f9d2afSIgor Opaniuk /* Replace unique partition GUIDs */
38d8f9d2afSIgor Opaniuk for (n = 0; n < NUM_GUIDS; n++) {
39d8f9d2afSIgor Opaniuk char part_name[AVB_PART_NAME_MAX_SIZE];
40d8f9d2afSIgor Opaniuk char guid_buf[37];
41d8f9d2afSIgor Opaniuk
42d8f9d2afSIgor Opaniuk if (!avb_str_concat(part_name,
43d8f9d2afSIgor Opaniuk sizeof part_name,
44d8f9d2afSIgor Opaniuk part_name_str[n],
45d8f9d2afSIgor Opaniuk avb_strlen(part_name_str[n]),
46d8f9d2afSIgor Opaniuk ab_suffix,
47d8f9d2afSIgor Opaniuk avb_strlen(ab_suffix))) {
48d8f9d2afSIgor Opaniuk avb_error("Partition name and suffix does not fit.\n");
49d8f9d2afSIgor Opaniuk goto fail;
50d8f9d2afSIgor Opaniuk }
51d8f9d2afSIgor Opaniuk
52d8f9d2afSIgor Opaniuk io_ret = ops->get_unique_guid_for_partition(
53d8f9d2afSIgor Opaniuk ops, part_name, guid_buf, sizeof guid_buf);
54d8f9d2afSIgor Opaniuk if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
55d8f9d2afSIgor Opaniuk goto fail;
56d8f9d2afSIgor Opaniuk } else if (io_ret != AVB_IO_RESULT_OK) {
57d8f9d2afSIgor Opaniuk avb_error("Error getting unique GUID for partition.\n");
58d8f9d2afSIgor Opaniuk goto fail;
59d8f9d2afSIgor Opaniuk }
60d8f9d2afSIgor Opaniuk
61d8f9d2afSIgor Opaniuk if (ret == NULL) {
62d8f9d2afSIgor Opaniuk ret = avb_replace(cmdline, replace_str[n], guid_buf);
63d8f9d2afSIgor Opaniuk } else {
64d8f9d2afSIgor Opaniuk char* new_ret = avb_replace(ret, replace_str[n], guid_buf);
65d8f9d2afSIgor Opaniuk avb_free(ret);
66d8f9d2afSIgor Opaniuk ret = new_ret;
67d8f9d2afSIgor Opaniuk }
68d8f9d2afSIgor Opaniuk if (ret == NULL) {
69d8f9d2afSIgor Opaniuk goto fail;
70d8f9d2afSIgor Opaniuk }
71d8f9d2afSIgor Opaniuk }
72d8f9d2afSIgor Opaniuk
73d8f9d2afSIgor Opaniuk avb_assert(ret != NULL);
74d8f9d2afSIgor Opaniuk
75d8f9d2afSIgor Opaniuk /* Replace any additional substitutions. */
76d8f9d2afSIgor Opaniuk if (additional_substitutions != NULL) {
77d8f9d2afSIgor Opaniuk for (n = 0; n < additional_substitutions->size; ++n) {
78d8f9d2afSIgor Opaniuk char* new_ret = avb_replace(ret,
79d8f9d2afSIgor Opaniuk additional_substitutions->tokens[n],
80d8f9d2afSIgor Opaniuk additional_substitutions->values[n]);
81d8f9d2afSIgor Opaniuk avb_free(ret);
82d8f9d2afSIgor Opaniuk ret = new_ret;
83d8f9d2afSIgor Opaniuk if (ret == NULL) {
84d8f9d2afSIgor Opaniuk goto fail;
85d8f9d2afSIgor Opaniuk }
86d8f9d2afSIgor Opaniuk }
87d8f9d2afSIgor Opaniuk }
88d8f9d2afSIgor Opaniuk
89d8f9d2afSIgor Opaniuk return ret;
90d8f9d2afSIgor Opaniuk
91d8f9d2afSIgor Opaniuk fail:
92d8f9d2afSIgor Opaniuk if (ret != NULL) {
93d8f9d2afSIgor Opaniuk avb_free(ret);
94d8f9d2afSIgor Opaniuk }
95d8f9d2afSIgor Opaniuk return NULL;
96d8f9d2afSIgor Opaniuk }
97d8f9d2afSIgor Opaniuk
cmdline_append_option(AvbSlotVerifyData * slot_data,const char * key,const char * value)98d8f9d2afSIgor Opaniuk static int cmdline_append_option(AvbSlotVerifyData* slot_data,
99d8f9d2afSIgor Opaniuk const char* key,
100d8f9d2afSIgor Opaniuk const char* value) {
101d8f9d2afSIgor Opaniuk size_t offset, key_len, value_len;
102d8f9d2afSIgor Opaniuk char* new_cmdline;
103d8f9d2afSIgor Opaniuk
104d8f9d2afSIgor Opaniuk key_len = avb_strlen(key);
105d8f9d2afSIgor Opaniuk value_len = avb_strlen(value);
106d8f9d2afSIgor Opaniuk
107d8f9d2afSIgor Opaniuk offset = 0;
108d8f9d2afSIgor Opaniuk if (slot_data->cmdline != NULL) {
109d8f9d2afSIgor Opaniuk offset = avb_strlen(slot_data->cmdline);
110d8f9d2afSIgor Opaniuk if (offset > 0) {
111d8f9d2afSIgor Opaniuk offset += 1;
112d8f9d2afSIgor Opaniuk }
113d8f9d2afSIgor Opaniuk }
114d8f9d2afSIgor Opaniuk
115d8f9d2afSIgor Opaniuk new_cmdline = avb_calloc(offset + key_len + value_len + 2);
116d8f9d2afSIgor Opaniuk if (new_cmdline == NULL) {
117d8f9d2afSIgor Opaniuk return 0;
118d8f9d2afSIgor Opaniuk }
119d8f9d2afSIgor Opaniuk if (offset > 0) {
120d8f9d2afSIgor Opaniuk avb_memcpy(new_cmdline, slot_data->cmdline, offset - 1);
121d8f9d2afSIgor Opaniuk new_cmdline[offset - 1] = ' ';
122d8f9d2afSIgor Opaniuk }
123d8f9d2afSIgor Opaniuk avb_memcpy(new_cmdline + offset, key, key_len);
124d8f9d2afSIgor Opaniuk new_cmdline[offset + key_len] = '=';
125d8f9d2afSIgor Opaniuk avb_memcpy(new_cmdline + offset + key_len + 1, value, value_len);
126d8f9d2afSIgor Opaniuk if (slot_data->cmdline != NULL) {
127d8f9d2afSIgor Opaniuk avb_free(slot_data->cmdline);
128d8f9d2afSIgor Opaniuk }
129d8f9d2afSIgor Opaniuk slot_data->cmdline = new_cmdline;
130d8f9d2afSIgor Opaniuk
131d8f9d2afSIgor Opaniuk return 1;
132d8f9d2afSIgor Opaniuk }
133d8f9d2afSIgor Opaniuk
134d8f9d2afSIgor Opaniuk #define AVB_MAX_DIGITS_UINT64 32
135d8f9d2afSIgor Opaniuk
136d8f9d2afSIgor Opaniuk /* Writes |value| to |digits| in base 10 followed by a NUL byte.
137d8f9d2afSIgor Opaniuk * Returns number of characters written excluding the NUL byte.
138d8f9d2afSIgor Opaniuk */
uint64_to_base10(uint64_t value,char digits[AVB_MAX_DIGITS_UINT64])139d8f9d2afSIgor Opaniuk static size_t uint64_to_base10(uint64_t value,
140d8f9d2afSIgor Opaniuk char digits[AVB_MAX_DIGITS_UINT64]) {
141d8f9d2afSIgor Opaniuk char rev_digits[AVB_MAX_DIGITS_UINT64];
142d8f9d2afSIgor Opaniuk size_t n, num_digits;
143d8f9d2afSIgor Opaniuk
144d8f9d2afSIgor Opaniuk for (num_digits = 0; num_digits < AVB_MAX_DIGITS_UINT64 - 1;) {
145d8f9d2afSIgor Opaniuk rev_digits[num_digits++] = avb_div_by_10(&value) + '0';
146d8f9d2afSIgor Opaniuk if (value == 0) {
147d8f9d2afSIgor Opaniuk break;
148d8f9d2afSIgor Opaniuk }
149d8f9d2afSIgor Opaniuk }
150d8f9d2afSIgor Opaniuk
151d8f9d2afSIgor Opaniuk for (n = 0; n < num_digits; n++) {
152d8f9d2afSIgor Opaniuk digits[n] = rev_digits[num_digits - 1 - n];
153d8f9d2afSIgor Opaniuk }
154d8f9d2afSIgor Opaniuk digits[n] = '\0';
155d8f9d2afSIgor Opaniuk return n;
156d8f9d2afSIgor Opaniuk }
157d8f9d2afSIgor Opaniuk
cmdline_append_version(AvbSlotVerifyData * slot_data,const char * key,uint64_t major_version,uint64_t minor_version)158d8f9d2afSIgor Opaniuk static int cmdline_append_version(AvbSlotVerifyData* slot_data,
159d8f9d2afSIgor Opaniuk const char* key,
160d8f9d2afSIgor Opaniuk uint64_t major_version,
161d8f9d2afSIgor Opaniuk uint64_t minor_version) {
162d8f9d2afSIgor Opaniuk char major_digits[AVB_MAX_DIGITS_UINT64];
163d8f9d2afSIgor Opaniuk char minor_digits[AVB_MAX_DIGITS_UINT64];
164d8f9d2afSIgor Opaniuk char combined[AVB_MAX_DIGITS_UINT64 * 2 + 1];
165d8f9d2afSIgor Opaniuk size_t num_major_digits, num_minor_digits;
166d8f9d2afSIgor Opaniuk
167d8f9d2afSIgor Opaniuk num_major_digits = uint64_to_base10(major_version, major_digits);
168d8f9d2afSIgor Opaniuk num_minor_digits = uint64_to_base10(minor_version, minor_digits);
169d8f9d2afSIgor Opaniuk avb_memcpy(combined, major_digits, num_major_digits);
170d8f9d2afSIgor Opaniuk combined[num_major_digits] = '.';
171d8f9d2afSIgor Opaniuk avb_memcpy(combined + num_major_digits + 1, minor_digits, num_minor_digits);
172d8f9d2afSIgor Opaniuk combined[num_major_digits + 1 + num_minor_digits] = '\0';
173d8f9d2afSIgor Opaniuk
174d8f9d2afSIgor Opaniuk return cmdline_append_option(slot_data, key, combined);
175d8f9d2afSIgor Opaniuk }
176d8f9d2afSIgor Opaniuk
cmdline_append_uint64_base10(AvbSlotVerifyData * slot_data,const char * key,uint64_t value)177d8f9d2afSIgor Opaniuk static int cmdline_append_uint64_base10(AvbSlotVerifyData* slot_data,
178d8f9d2afSIgor Opaniuk const char* key,
179d8f9d2afSIgor Opaniuk uint64_t value) {
180d8f9d2afSIgor Opaniuk char digits[AVB_MAX_DIGITS_UINT64];
181d8f9d2afSIgor Opaniuk uint64_to_base10(value, digits);
182d8f9d2afSIgor Opaniuk return cmdline_append_option(slot_data, key, digits);
183d8f9d2afSIgor Opaniuk }
184d8f9d2afSIgor Opaniuk
cmdline_append_hex(AvbSlotVerifyData * slot_data,const char * key,const uint8_t * data,size_t data_len)185d8f9d2afSIgor Opaniuk static int cmdline_append_hex(AvbSlotVerifyData* slot_data,
186d8f9d2afSIgor Opaniuk const char* key,
187d8f9d2afSIgor Opaniuk const uint8_t* data,
188d8f9d2afSIgor Opaniuk size_t data_len) {
189d8f9d2afSIgor Opaniuk int ret;
190d8f9d2afSIgor Opaniuk char* hex_data = avb_bin2hex(data, data_len);
191d8f9d2afSIgor Opaniuk if (hex_data == NULL) {
192d8f9d2afSIgor Opaniuk return 0;
193d8f9d2afSIgor Opaniuk }
194d8f9d2afSIgor Opaniuk ret = cmdline_append_option(slot_data, key, hex_data);
195d8f9d2afSIgor Opaniuk avb_free(hex_data);
196d8f9d2afSIgor Opaniuk return ret;
197d8f9d2afSIgor Opaniuk }
198d8f9d2afSIgor Opaniuk
avb_append_options(AvbOps * ops,AvbSlotVerifyData * slot_data,AvbVBMetaImageHeader * toplevel_vbmeta,AvbAlgorithmType algorithm_type,AvbHashtreeErrorMode hashtree_error_mode)199d8f9d2afSIgor Opaniuk AvbSlotVerifyResult avb_append_options(
200d8f9d2afSIgor Opaniuk AvbOps* ops,
201d8f9d2afSIgor Opaniuk AvbSlotVerifyData* slot_data,
202d8f9d2afSIgor Opaniuk AvbVBMetaImageHeader* toplevel_vbmeta,
203d8f9d2afSIgor Opaniuk AvbAlgorithmType algorithm_type,
204d8f9d2afSIgor Opaniuk AvbHashtreeErrorMode hashtree_error_mode) {
205d8f9d2afSIgor Opaniuk AvbSlotVerifyResult ret;
206d8f9d2afSIgor Opaniuk const char* verity_mode;
207d8f9d2afSIgor Opaniuk bool is_device_unlocked;
208d8f9d2afSIgor Opaniuk AvbIOResult io_ret;
209d8f9d2afSIgor Opaniuk
210d8f9d2afSIgor Opaniuk /* Add androidboot.vbmeta.device option. */
211d8f9d2afSIgor Opaniuk if (!cmdline_append_option(slot_data,
212d8f9d2afSIgor Opaniuk "androidboot.vbmeta.device",
213d8f9d2afSIgor Opaniuk "PARTUUID=$(ANDROID_VBMETA_PARTUUID)")) {
214d8f9d2afSIgor Opaniuk ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
215d8f9d2afSIgor Opaniuk goto out;
216d8f9d2afSIgor Opaniuk }
217d8f9d2afSIgor Opaniuk
218d8f9d2afSIgor Opaniuk /* Add androidboot.vbmeta.avb_version option. */
219d8f9d2afSIgor Opaniuk if (!cmdline_append_version(slot_data,
220d8f9d2afSIgor Opaniuk "androidboot.vbmeta.avb_version",
221d8f9d2afSIgor Opaniuk AVB_VERSION_MAJOR,
222d8f9d2afSIgor Opaniuk AVB_VERSION_MINOR)) {
223d8f9d2afSIgor Opaniuk ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
224d8f9d2afSIgor Opaniuk goto out;
225d8f9d2afSIgor Opaniuk }
226d8f9d2afSIgor Opaniuk
227d8f9d2afSIgor Opaniuk /* Set androidboot.avb.device_state to "locked" or "unlocked". */
228d8f9d2afSIgor Opaniuk io_ret = ops->read_is_device_unlocked(ops, &is_device_unlocked);
229d8f9d2afSIgor Opaniuk if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
230d8f9d2afSIgor Opaniuk ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
231d8f9d2afSIgor Opaniuk goto out;
232d8f9d2afSIgor Opaniuk } else if (io_ret != AVB_IO_RESULT_OK) {
233d8f9d2afSIgor Opaniuk avb_error("Error getting device state.\n");
234d8f9d2afSIgor Opaniuk ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
235d8f9d2afSIgor Opaniuk goto out;
236d8f9d2afSIgor Opaniuk }
237d8f9d2afSIgor Opaniuk if (!cmdline_append_option(slot_data,
238d8f9d2afSIgor Opaniuk "androidboot.vbmeta.device_state",
239d8f9d2afSIgor Opaniuk is_device_unlocked ? "unlocked" : "locked")) {
240d8f9d2afSIgor Opaniuk ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
241d8f9d2afSIgor Opaniuk goto out;
242d8f9d2afSIgor Opaniuk }
243d8f9d2afSIgor Opaniuk
244d8f9d2afSIgor Opaniuk /* Set androidboot.vbmeta.{hash_alg, size, digest} - use same hash
245d8f9d2afSIgor Opaniuk * function as is used to sign vbmeta.
246d8f9d2afSIgor Opaniuk */
247d8f9d2afSIgor Opaniuk switch (algorithm_type) {
248d8f9d2afSIgor Opaniuk /* Explicit fallthrough. */
249d8f9d2afSIgor Opaniuk case AVB_ALGORITHM_TYPE_NONE:
250d8f9d2afSIgor Opaniuk case AVB_ALGORITHM_TYPE_SHA256_RSA2048:
251d8f9d2afSIgor Opaniuk case AVB_ALGORITHM_TYPE_SHA256_RSA4096:
252d8f9d2afSIgor Opaniuk case AVB_ALGORITHM_TYPE_SHA256_RSA8192: {
253d8f9d2afSIgor Opaniuk size_t n, total_size = 0;
254d8f9d2afSIgor Opaniuk uint8_t vbmeta_digest[AVB_SHA256_DIGEST_SIZE];
255d8f9d2afSIgor Opaniuk avb_slot_verify_data_calculate_vbmeta_digest(
256d8f9d2afSIgor Opaniuk slot_data, AVB_DIGEST_TYPE_SHA256, vbmeta_digest);
257d8f9d2afSIgor Opaniuk for (n = 0; n < slot_data->num_vbmeta_images; n++) {
258d8f9d2afSIgor Opaniuk total_size += slot_data->vbmeta_images[n].vbmeta_size;
259d8f9d2afSIgor Opaniuk }
260d8f9d2afSIgor Opaniuk if (!cmdline_append_option(
261d8f9d2afSIgor Opaniuk slot_data, "androidboot.vbmeta.hash_alg", "sha256") ||
262d8f9d2afSIgor Opaniuk !cmdline_append_uint64_base10(
263d8f9d2afSIgor Opaniuk slot_data, "androidboot.vbmeta.size", total_size) ||
264d8f9d2afSIgor Opaniuk !cmdline_append_hex(slot_data,
265d8f9d2afSIgor Opaniuk "androidboot.vbmeta.digest",
266d8f9d2afSIgor Opaniuk vbmeta_digest,
267d8f9d2afSIgor Opaniuk AVB_SHA256_DIGEST_SIZE)) {
268d8f9d2afSIgor Opaniuk ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
269d8f9d2afSIgor Opaniuk goto out;
270d8f9d2afSIgor Opaniuk }
271d8f9d2afSIgor Opaniuk } break;
272d8f9d2afSIgor Opaniuk /* Explicit fallthrough. */
273d8f9d2afSIgor Opaniuk case AVB_ALGORITHM_TYPE_SHA512_RSA2048:
274d8f9d2afSIgor Opaniuk case AVB_ALGORITHM_TYPE_SHA512_RSA4096:
275d8f9d2afSIgor Opaniuk case AVB_ALGORITHM_TYPE_SHA512_RSA8192: {
276d8f9d2afSIgor Opaniuk size_t n, total_size = 0;
277d8f9d2afSIgor Opaniuk uint8_t vbmeta_digest[AVB_SHA512_DIGEST_SIZE];
278d8f9d2afSIgor Opaniuk avb_slot_verify_data_calculate_vbmeta_digest(
279d8f9d2afSIgor Opaniuk slot_data, AVB_DIGEST_TYPE_SHA512, vbmeta_digest);
280d8f9d2afSIgor Opaniuk for (n = 0; n < slot_data->num_vbmeta_images; n++) {
281d8f9d2afSIgor Opaniuk total_size += slot_data->vbmeta_images[n].vbmeta_size;
282d8f9d2afSIgor Opaniuk }
283d8f9d2afSIgor Opaniuk if (!cmdline_append_option(
284d8f9d2afSIgor Opaniuk slot_data, "androidboot.vbmeta.hash_alg", "sha512") ||
285d8f9d2afSIgor Opaniuk !cmdline_append_uint64_base10(
286d8f9d2afSIgor Opaniuk slot_data, "androidboot.vbmeta.size", total_size) ||
287d8f9d2afSIgor Opaniuk !cmdline_append_hex(slot_data,
288d8f9d2afSIgor Opaniuk "androidboot.vbmeta.digest",
289d8f9d2afSIgor Opaniuk vbmeta_digest,
290d8f9d2afSIgor Opaniuk AVB_SHA512_DIGEST_SIZE)) {
291d8f9d2afSIgor Opaniuk ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
292d8f9d2afSIgor Opaniuk goto out;
293d8f9d2afSIgor Opaniuk }
294d8f9d2afSIgor Opaniuk } break;
295d8f9d2afSIgor Opaniuk case _AVB_ALGORITHM_NUM_TYPES:
296d8f9d2afSIgor Opaniuk avb_assert_not_reached();
297d8f9d2afSIgor Opaniuk break;
298d8f9d2afSIgor Opaniuk }
299d8f9d2afSIgor Opaniuk
300d8f9d2afSIgor Opaniuk /* Set androidboot.veritymode and androidboot.vbmeta.invalidate_on_error */
301d8f9d2afSIgor Opaniuk if (toplevel_vbmeta->flags & AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED) {
302d8f9d2afSIgor Opaniuk verity_mode = "disabled";
303d8f9d2afSIgor Opaniuk } else {
304d8f9d2afSIgor Opaniuk const char* dm_verity_mode;
305d8f9d2afSIgor Opaniuk char* new_ret;
306d8f9d2afSIgor Opaniuk
307d8f9d2afSIgor Opaniuk switch (hashtree_error_mode) {
308d8f9d2afSIgor Opaniuk case AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE:
309d8f9d2afSIgor Opaniuk if (!cmdline_append_option(
310d8f9d2afSIgor Opaniuk slot_data, "androidboot.vbmeta.invalidate_on_error", "yes")) {
311d8f9d2afSIgor Opaniuk ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
312d8f9d2afSIgor Opaniuk goto out;
313d8f9d2afSIgor Opaniuk }
314d8f9d2afSIgor Opaniuk verity_mode = "enforcing";
315d8f9d2afSIgor Opaniuk dm_verity_mode = "restart_on_corruption";
316d8f9d2afSIgor Opaniuk break;
317d8f9d2afSIgor Opaniuk case AVB_HASHTREE_ERROR_MODE_RESTART:
318d8f9d2afSIgor Opaniuk verity_mode = "enforcing";
319d8f9d2afSIgor Opaniuk dm_verity_mode = "restart_on_corruption";
320d8f9d2afSIgor Opaniuk break;
321d8f9d2afSIgor Opaniuk case AVB_HASHTREE_ERROR_MODE_EIO:
322d8f9d2afSIgor Opaniuk verity_mode = "eio";
323d8f9d2afSIgor Opaniuk /* For now there's no option to specify the EIO mode. So
324d8f9d2afSIgor Opaniuk * just use 'ignore_zero_blocks' since that's already set
325d8f9d2afSIgor Opaniuk * and dm-verity-target.c supports specifying this multiple
326d8f9d2afSIgor Opaniuk * times.
327d8f9d2afSIgor Opaniuk */
328d8f9d2afSIgor Opaniuk dm_verity_mode = "ignore_zero_blocks";
329d8f9d2afSIgor Opaniuk break;
330d8f9d2afSIgor Opaniuk case AVB_HASHTREE_ERROR_MODE_LOGGING:
331d8f9d2afSIgor Opaniuk verity_mode = "logging";
332d8f9d2afSIgor Opaniuk dm_verity_mode = "ignore_corruption";
333d8f9d2afSIgor Opaniuk break;
334*ecc6f6beSIevgen Maliarenko default:
335*ecc6f6beSIevgen Maliarenko ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
336*ecc6f6beSIevgen Maliarenko goto out;
337d8f9d2afSIgor Opaniuk }
338d8f9d2afSIgor Opaniuk new_ret = avb_replace(
339d8f9d2afSIgor Opaniuk slot_data->cmdline, "$(ANDROID_VERITY_MODE)", dm_verity_mode);
340d8f9d2afSIgor Opaniuk avb_free(slot_data->cmdline);
341d8f9d2afSIgor Opaniuk slot_data->cmdline = new_ret;
342d8f9d2afSIgor Opaniuk if (slot_data->cmdline == NULL) {
343d8f9d2afSIgor Opaniuk ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
344d8f9d2afSIgor Opaniuk goto out;
345d8f9d2afSIgor Opaniuk }
346d8f9d2afSIgor Opaniuk }
347d8f9d2afSIgor Opaniuk if (!cmdline_append_option(
348d8f9d2afSIgor Opaniuk slot_data, "androidboot.veritymode", verity_mode)) {
349d8f9d2afSIgor Opaniuk ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
350d8f9d2afSIgor Opaniuk goto out;
351d8f9d2afSIgor Opaniuk }
352d8f9d2afSIgor Opaniuk
353d8f9d2afSIgor Opaniuk ret = AVB_SLOT_VERIFY_RESULT_OK;
354d8f9d2afSIgor Opaniuk
355d8f9d2afSIgor Opaniuk out:
356d8f9d2afSIgor Opaniuk
357d8f9d2afSIgor Opaniuk return ret;
358d8f9d2afSIgor Opaniuk }
359d8f9d2afSIgor Opaniuk
avb_new_cmdline_subst_list()360d8f9d2afSIgor Opaniuk AvbCmdlineSubstList* avb_new_cmdline_subst_list() {
361d8f9d2afSIgor Opaniuk return (AvbCmdlineSubstList*)avb_calloc(sizeof(AvbCmdlineSubstList));
362d8f9d2afSIgor Opaniuk }
363d8f9d2afSIgor Opaniuk
avb_free_cmdline_subst_list(AvbCmdlineSubstList * cmdline_subst)364d8f9d2afSIgor Opaniuk void avb_free_cmdline_subst_list(AvbCmdlineSubstList* cmdline_subst) {
365d8f9d2afSIgor Opaniuk size_t i;
366d8f9d2afSIgor Opaniuk for (i = 0; i < cmdline_subst->size; ++i) {
367d8f9d2afSIgor Opaniuk avb_free(cmdline_subst->tokens[i]);
368d8f9d2afSIgor Opaniuk avb_free(cmdline_subst->values[i]);
369d8f9d2afSIgor Opaniuk }
370d8f9d2afSIgor Opaniuk cmdline_subst->size = 0;
371d8f9d2afSIgor Opaniuk avb_free(cmdline_subst);
372d8f9d2afSIgor Opaniuk }
373d8f9d2afSIgor Opaniuk
avb_add_root_digest_substitution(const char * part_name,const uint8_t * digest,size_t digest_size,AvbCmdlineSubstList * out_cmdline_subst)374d8f9d2afSIgor Opaniuk AvbSlotVerifyResult avb_add_root_digest_substitution(
375d8f9d2afSIgor Opaniuk const char* part_name,
376d8f9d2afSIgor Opaniuk const uint8_t* digest,
377d8f9d2afSIgor Opaniuk size_t digest_size,
378d8f9d2afSIgor Opaniuk AvbCmdlineSubstList* out_cmdline_subst) {
379d8f9d2afSIgor Opaniuk const char* kDigestSubPrefix = "$(AVB_";
380d8f9d2afSIgor Opaniuk const char* kDigestSubSuffix = "_ROOT_DIGEST)";
381d8f9d2afSIgor Opaniuk size_t part_name_len = avb_strlen(part_name);
382d8f9d2afSIgor Opaniuk size_t list_index = out_cmdline_subst->size;
383d8f9d2afSIgor Opaniuk
384d8f9d2afSIgor Opaniuk avb_assert(part_name_len < AVB_PART_NAME_MAX_SIZE);
385d8f9d2afSIgor Opaniuk avb_assert(digest_size <= AVB_SHA512_DIGEST_SIZE);
386d8f9d2afSIgor Opaniuk if (part_name_len >= AVB_PART_NAME_MAX_SIZE ||
387d8f9d2afSIgor Opaniuk digest_size > AVB_SHA512_DIGEST_SIZE) {
388d8f9d2afSIgor Opaniuk return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
389d8f9d2afSIgor Opaniuk }
390d8f9d2afSIgor Opaniuk
391d8f9d2afSIgor Opaniuk if (out_cmdline_subst->size >= AVB_MAX_NUM_CMDLINE_SUBST) {
392d8f9d2afSIgor Opaniuk /* The list is full. Currently dynamic growth of this list is not supported.
393d8f9d2afSIgor Opaniuk */
394d8f9d2afSIgor Opaniuk return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
395d8f9d2afSIgor Opaniuk }
396d8f9d2afSIgor Opaniuk
397d8f9d2afSIgor Opaniuk /* Construct the token to replace in the command line based on the partition
398d8f9d2afSIgor Opaniuk * name. For partition 'foo', this will be '$(AVB_FOO_ROOT_DIGEST)'.
399d8f9d2afSIgor Opaniuk */
400d8f9d2afSIgor Opaniuk out_cmdline_subst->tokens[list_index] =
401d8f9d2afSIgor Opaniuk avb_strdupv(kDigestSubPrefix, part_name, kDigestSubSuffix, NULL);
402d8f9d2afSIgor Opaniuk if (out_cmdline_subst->tokens[list_index] == NULL) {
403d8f9d2afSIgor Opaniuk goto fail;
404d8f9d2afSIgor Opaniuk }
405d8f9d2afSIgor Opaniuk avb_uppercase(out_cmdline_subst->tokens[list_index]);
406d8f9d2afSIgor Opaniuk
407d8f9d2afSIgor Opaniuk /* The digest value is hex encoded when inserted in the command line. */
408d8f9d2afSIgor Opaniuk out_cmdline_subst->values[list_index] = avb_bin2hex(digest, digest_size);
409d8f9d2afSIgor Opaniuk if (out_cmdline_subst->values[list_index] == NULL) {
410d8f9d2afSIgor Opaniuk goto fail;
411d8f9d2afSIgor Opaniuk }
412d8f9d2afSIgor Opaniuk
413d8f9d2afSIgor Opaniuk out_cmdline_subst->size++;
414d8f9d2afSIgor Opaniuk return AVB_SLOT_VERIFY_RESULT_OK;
415d8f9d2afSIgor Opaniuk
416d8f9d2afSIgor Opaniuk fail:
417d8f9d2afSIgor Opaniuk if (out_cmdline_subst->tokens[list_index]) {
418d8f9d2afSIgor Opaniuk avb_free(out_cmdline_subst->tokens[list_index]);
419d8f9d2afSIgor Opaniuk }
420d8f9d2afSIgor Opaniuk if (out_cmdline_subst->values[list_index]) {
421d8f9d2afSIgor Opaniuk avb_free(out_cmdline_subst->values[list_index]);
422d8f9d2afSIgor Opaniuk }
423d8f9d2afSIgor Opaniuk return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
424d8f9d2afSIgor Opaniuk }
425