137a7bc39SJason Zhu /*
237a7bc39SJason Zhu * Copyright (C) 2016 The Android Open Source Project
337a7bc39SJason Zhu *
437a7bc39SJason Zhu * Permission is hereby granted, free of charge, to any person
537a7bc39SJason Zhu * obtaining a copy of this software and associated documentation
637a7bc39SJason Zhu * files (the "Software"), to deal in the Software without
737a7bc39SJason Zhu * restriction, including without limitation the rights to use, copy,
837a7bc39SJason Zhu * modify, merge, publish, distribute, sublicense, and/or sell copies
937a7bc39SJason Zhu * of the Software, and to permit persons to whom the Software is
1037a7bc39SJason Zhu * furnished to do so, subject to the following conditions:
1137a7bc39SJason Zhu *
1237a7bc39SJason Zhu * The above copyright notice and this permission notice shall be
1337a7bc39SJason Zhu * included in all copies or substantial portions of the Software.
1437a7bc39SJason Zhu *
1537a7bc39SJason Zhu * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1637a7bc39SJason Zhu * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1737a7bc39SJason Zhu * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
1837a7bc39SJason Zhu * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
1937a7bc39SJason Zhu * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
2037a7bc39SJason Zhu * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
2137a7bc39SJason Zhu * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2237a7bc39SJason Zhu * SOFTWARE.
2337a7bc39SJason Zhu */
2437a7bc39SJason Zhu
2537a7bc39SJason Zhu #include <android_avb/avb_cmdline.h>
2637a7bc39SJason Zhu #include <android_avb/avb_sha.h>
2737a7bc39SJason Zhu #include <android_avb/avb_util.h>
2837a7bc39SJason Zhu #include <android_avb/avb_version.h>
2937a7bc39SJason Zhu
3037a7bc39SJason Zhu #define NUM_GUIDS 3
3137a7bc39SJason Zhu
3237a7bc39SJason Zhu /* Substitutes all variables (e.g. $(ANDROID_SYSTEM_PARTUUID)) with
3337a7bc39SJason Zhu * values. Returns NULL on OOM, otherwise the cmdline with values
3437a7bc39SJason Zhu * replaced.
3537a7bc39SJason Zhu */
avb_sub_cmdline(AvbOps * ops,const char * cmdline,const char * ab_suffix,bool using_boot_for_vbmeta,const AvbCmdlineSubstList * additional_substitutions)36ab608f80SJason Zhu char* avb_sub_cmdline(AvbOps* ops,
37ab608f80SJason Zhu const char* cmdline,
38ab608f80SJason Zhu const char* ab_suffix,
39ab608f80SJason Zhu bool using_boot_for_vbmeta,
40ab608f80SJason Zhu const AvbCmdlineSubstList* additional_substitutions) {
4137a7bc39SJason Zhu const char* part_name_str[NUM_GUIDS] = {"system", "boot", "vbmeta"};
4237a7bc39SJason Zhu const char* replace_str[NUM_GUIDS] = {"$(ANDROID_SYSTEM_PARTUUID)",
4337a7bc39SJason Zhu "$(ANDROID_BOOT_PARTUUID)",
4437a7bc39SJason Zhu "$(ANDROID_VBMETA_PARTUUID)"};
4537a7bc39SJason Zhu char* ret = NULL;
4637a7bc39SJason Zhu AvbIOResult io_ret;
4737a7bc39SJason Zhu size_t n;
4837a7bc39SJason Zhu
4937a7bc39SJason Zhu /* Special-case for when the top-level vbmeta struct is in the boot
5037a7bc39SJason Zhu * partition.
5137a7bc39SJason Zhu */
5237a7bc39SJason Zhu if (using_boot_for_vbmeta) {
5337a7bc39SJason Zhu part_name_str[2] = "boot";
5437a7bc39SJason Zhu }
5537a7bc39SJason Zhu
5637a7bc39SJason Zhu /* Replace unique partition GUIDs */
5737a7bc39SJason Zhu for (n = 0; n < NUM_GUIDS; n++) {
5837a7bc39SJason Zhu char part_name[AVB_PART_NAME_MAX_SIZE];
5937a7bc39SJason Zhu char guid_buf[37];
6037a7bc39SJason Zhu
61*69fdc596SJason Zhu /* Don't attempt to query the partition guid unless its search string is
62*69fdc596SJason Zhu * present in the command line. Note: the original cmdline is used here,
63*69fdc596SJason Zhu * not the replaced one. See b/116010959.
64*69fdc596SJason Zhu */
65*69fdc596SJason Zhu if (avb_strstr(cmdline, replace_str[n]) == NULL) {
66*69fdc596SJason Zhu continue;
67*69fdc596SJason Zhu }
68*69fdc596SJason Zhu
6937a7bc39SJason Zhu if (!avb_str_concat(part_name,
7037a7bc39SJason Zhu sizeof part_name,
7137a7bc39SJason Zhu part_name_str[n],
7237a7bc39SJason Zhu avb_strlen(part_name_str[n]),
7337a7bc39SJason Zhu ab_suffix,
7437a7bc39SJason Zhu avb_strlen(ab_suffix))) {
7537a7bc39SJason Zhu avb_error("Partition name and suffix does not fit.\n");
7637a7bc39SJason Zhu goto fail;
7737a7bc39SJason Zhu }
7837a7bc39SJason Zhu
7937a7bc39SJason Zhu io_ret = ops->get_unique_guid_for_partition(
8037a7bc39SJason Zhu ops, part_name, guid_buf, sizeof guid_buf);
8137a7bc39SJason Zhu if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
82ab608f80SJason Zhu goto fail;
8337a7bc39SJason Zhu } else if (io_ret != AVB_IO_RESULT_OK) {
8437a7bc39SJason Zhu avb_error("Error getting unique GUID for partition.\n");
8537a7bc39SJason Zhu goto fail;
8637a7bc39SJason Zhu }
8737a7bc39SJason Zhu
8837a7bc39SJason Zhu if (ret == NULL) {
8937a7bc39SJason Zhu ret = avb_replace(cmdline, replace_str[n], guid_buf);
9037a7bc39SJason Zhu } else {
9137a7bc39SJason Zhu char* new_ret = avb_replace(ret, replace_str[n], guid_buf);
9237a7bc39SJason Zhu avb_free(ret);
9337a7bc39SJason Zhu ret = new_ret;
9437a7bc39SJason Zhu }
9537a7bc39SJason Zhu if (ret == NULL) {
9637a7bc39SJason Zhu goto fail;
9737a7bc39SJason Zhu }
9837a7bc39SJason Zhu }
9937a7bc39SJason Zhu
100*69fdc596SJason Zhu /* It's possible there is no _PARTUUID for replacement above.
101*69fdc596SJason Zhu * Duplicate cmdline to ret for additional substitutions below.
102*69fdc596SJason Zhu */
103*69fdc596SJason Zhu if (ret == NULL) {
104*69fdc596SJason Zhu ret = avb_strdup(cmdline);
105*69fdc596SJason Zhu if (ret == NULL) {
106*69fdc596SJason Zhu goto fail;
107*69fdc596SJason Zhu }
108*69fdc596SJason Zhu }
109ab608f80SJason Zhu
110ab608f80SJason Zhu /* Replace any additional substitutions. */
111ab608f80SJason Zhu if (additional_substitutions != NULL) {
112ab608f80SJason Zhu for (n = 0; n < additional_substitutions->size; ++n) {
113ab608f80SJason Zhu char* new_ret = avb_replace(ret,
114ab608f80SJason Zhu additional_substitutions->tokens[n],
115ab608f80SJason Zhu additional_substitutions->values[n]);
116ab608f80SJason Zhu avb_free(ret);
117ab608f80SJason Zhu ret = new_ret;
118ab608f80SJason Zhu if (ret == NULL) {
119ab608f80SJason Zhu goto fail;
120ab608f80SJason Zhu }
121ab608f80SJason Zhu }
122ab608f80SJason Zhu }
123ab608f80SJason Zhu
12437a7bc39SJason Zhu return ret;
12537a7bc39SJason Zhu
12637a7bc39SJason Zhu fail:
12737a7bc39SJason Zhu if (ret != NULL) {
12837a7bc39SJason Zhu avb_free(ret);
12937a7bc39SJason Zhu }
13037a7bc39SJason Zhu return NULL;
13137a7bc39SJason Zhu }
13237a7bc39SJason Zhu
cmdline_append_option(AvbSlotVerifyData * slot_data,const char * key,const char * value)13337a7bc39SJason Zhu static int cmdline_append_option(AvbSlotVerifyData* slot_data,
13437a7bc39SJason Zhu const char* key,
13537a7bc39SJason Zhu const char* value) {
13637a7bc39SJason Zhu size_t offset, key_len, value_len;
13737a7bc39SJason Zhu char* new_cmdline;
13837a7bc39SJason Zhu
13937a7bc39SJason Zhu key_len = avb_strlen(key);
14037a7bc39SJason Zhu value_len = avb_strlen(value);
14137a7bc39SJason Zhu
14237a7bc39SJason Zhu offset = 0;
14337a7bc39SJason Zhu if (slot_data->cmdline != NULL) {
14437a7bc39SJason Zhu offset = avb_strlen(slot_data->cmdline);
14537a7bc39SJason Zhu if (offset > 0) {
14637a7bc39SJason Zhu offset += 1;
14737a7bc39SJason Zhu }
14837a7bc39SJason Zhu }
14937a7bc39SJason Zhu
15037a7bc39SJason Zhu new_cmdline = avb_calloc(offset + key_len + value_len + 2);
15137a7bc39SJason Zhu if (new_cmdline == NULL) {
15237a7bc39SJason Zhu return 0;
15337a7bc39SJason Zhu }
15437a7bc39SJason Zhu if (offset > 0) {
15537a7bc39SJason Zhu avb_memcpy(new_cmdline, slot_data->cmdline, offset - 1);
15637a7bc39SJason Zhu new_cmdline[offset - 1] = ' ';
15737a7bc39SJason Zhu }
15837a7bc39SJason Zhu avb_memcpy(new_cmdline + offset, key, key_len);
15937a7bc39SJason Zhu new_cmdline[offset + key_len] = '=';
16037a7bc39SJason Zhu avb_memcpy(new_cmdline + offset + key_len + 1, value, value_len);
16137a7bc39SJason Zhu if (slot_data->cmdline != NULL) {
16237a7bc39SJason Zhu avb_free(slot_data->cmdline);
16337a7bc39SJason Zhu }
16437a7bc39SJason Zhu slot_data->cmdline = new_cmdline;
16537a7bc39SJason Zhu
16637a7bc39SJason Zhu return 1;
16737a7bc39SJason Zhu }
16837a7bc39SJason Zhu
16937a7bc39SJason Zhu #define AVB_MAX_DIGITS_UINT64 32
17037a7bc39SJason Zhu
17137a7bc39SJason Zhu /* Writes |value| to |digits| in base 10 followed by a NUL byte.
17237a7bc39SJason Zhu * Returns number of characters written excluding the NUL byte.
17337a7bc39SJason Zhu */
uint64_to_base10(uint64_t value,char digits[AVB_MAX_DIGITS_UINT64])17437a7bc39SJason Zhu static size_t uint64_to_base10(uint64_t value,
17537a7bc39SJason Zhu char digits[AVB_MAX_DIGITS_UINT64]) {
17637a7bc39SJason Zhu char rev_digits[AVB_MAX_DIGITS_UINT64];
17737a7bc39SJason Zhu size_t n, num_digits;
17837a7bc39SJason Zhu
17937a7bc39SJason Zhu for (num_digits = 0; num_digits < AVB_MAX_DIGITS_UINT64 - 1;) {
18037a7bc39SJason Zhu rev_digits[num_digits++] = avb_div_by_10(&value) + '0';
18137a7bc39SJason Zhu if (value == 0) {
18237a7bc39SJason Zhu break;
18337a7bc39SJason Zhu }
18437a7bc39SJason Zhu }
18537a7bc39SJason Zhu
18637a7bc39SJason Zhu for (n = 0; n < num_digits; n++) {
18737a7bc39SJason Zhu digits[n] = rev_digits[num_digits - 1 - n];
18837a7bc39SJason Zhu }
18937a7bc39SJason Zhu digits[n] = '\0';
19037a7bc39SJason Zhu return n;
19137a7bc39SJason Zhu }
19237a7bc39SJason Zhu
cmdline_append_version(AvbSlotVerifyData * slot_data,const char * key,uint64_t major_version,uint64_t minor_version)19337a7bc39SJason Zhu static int cmdline_append_version(AvbSlotVerifyData* slot_data,
19437a7bc39SJason Zhu const char* key,
19537a7bc39SJason Zhu uint64_t major_version,
19637a7bc39SJason Zhu uint64_t minor_version) {
19737a7bc39SJason Zhu char major_digits[AVB_MAX_DIGITS_UINT64];
19837a7bc39SJason Zhu char minor_digits[AVB_MAX_DIGITS_UINT64];
19937a7bc39SJason Zhu char combined[AVB_MAX_DIGITS_UINT64 * 2 + 1];
20037a7bc39SJason Zhu size_t num_major_digits, num_minor_digits;
20137a7bc39SJason Zhu
20237a7bc39SJason Zhu num_major_digits = uint64_to_base10(major_version, major_digits);
20337a7bc39SJason Zhu num_minor_digits = uint64_to_base10(minor_version, minor_digits);
20437a7bc39SJason Zhu avb_memcpy(combined, major_digits, num_major_digits);
20537a7bc39SJason Zhu combined[num_major_digits] = '.';
20637a7bc39SJason Zhu avb_memcpy(combined + num_major_digits + 1, minor_digits, num_minor_digits);
20737a7bc39SJason Zhu combined[num_major_digits + 1 + num_minor_digits] = '\0';
20837a7bc39SJason Zhu
20937a7bc39SJason Zhu return cmdline_append_option(slot_data, key, combined);
21037a7bc39SJason Zhu }
21137a7bc39SJason Zhu
cmdline_append_uint64_base10(AvbSlotVerifyData * slot_data,const char * key,uint64_t value)21237a7bc39SJason Zhu static int cmdline_append_uint64_base10(AvbSlotVerifyData* slot_data,
21337a7bc39SJason Zhu const char* key,
21437a7bc39SJason Zhu uint64_t value) {
21537a7bc39SJason Zhu char digits[AVB_MAX_DIGITS_UINT64];
21637a7bc39SJason Zhu uint64_to_base10(value, digits);
21737a7bc39SJason Zhu return cmdline_append_option(slot_data, key, digits);
21837a7bc39SJason Zhu }
21937a7bc39SJason Zhu
cmdline_append_hex(AvbSlotVerifyData * slot_data,const char * key,const uint8_t * data,size_t data_len)22037a7bc39SJason Zhu static int cmdline_append_hex(AvbSlotVerifyData* slot_data,
22137a7bc39SJason Zhu const char* key,
22237a7bc39SJason Zhu const uint8_t* data,
22337a7bc39SJason Zhu size_t data_len) {
22437a7bc39SJason Zhu int ret;
225ab608f80SJason Zhu char* hex_data = avb_bin2hex(data, data_len);
22637a7bc39SJason Zhu if (hex_data == NULL) {
22737a7bc39SJason Zhu return 0;
22837a7bc39SJason Zhu }
22937a7bc39SJason Zhu ret = cmdline_append_option(slot_data, key, hex_data);
23037a7bc39SJason Zhu avb_free(hex_data);
23137a7bc39SJason Zhu return ret;
23237a7bc39SJason Zhu }
23337a7bc39SJason Zhu
avb_append_options(AvbOps * ops,AvbSlotVerifyFlags flags,AvbSlotVerifyData * slot_data,AvbVBMetaImageHeader * toplevel_vbmeta,AvbAlgorithmType algorithm_type,AvbHashtreeErrorMode hashtree_error_mode,AvbHashtreeErrorMode resolved_hashtree_error_mode)23437a7bc39SJason Zhu AvbSlotVerifyResult avb_append_options(
23537a7bc39SJason Zhu AvbOps* ops,
236*69fdc596SJason Zhu AvbSlotVerifyFlags flags,
23737a7bc39SJason Zhu AvbSlotVerifyData* slot_data,
23837a7bc39SJason Zhu AvbVBMetaImageHeader* toplevel_vbmeta,
23937a7bc39SJason Zhu AvbAlgorithmType algorithm_type,
240*69fdc596SJason Zhu AvbHashtreeErrorMode hashtree_error_mode,
241*69fdc596SJason Zhu AvbHashtreeErrorMode resolved_hashtree_error_mode) {
24237a7bc39SJason Zhu AvbSlotVerifyResult ret;
24337a7bc39SJason Zhu const char* verity_mode = NULL;
24437a7bc39SJason Zhu bool is_device_unlocked;
24537a7bc39SJason Zhu AvbIOResult io_ret;
24637a7bc39SJason Zhu
247*69fdc596SJason Zhu /* Add androidboot.vbmeta.device option... except if not using a vbmeta
248*69fdc596SJason Zhu * partition since it doesn't make sense in that case.
249*69fdc596SJason Zhu */
250*69fdc596SJason Zhu if (!(flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION)) {
25137a7bc39SJason Zhu if (!cmdline_append_option(slot_data,
25237a7bc39SJason Zhu "androidboot.vbmeta.device",
25337a7bc39SJason Zhu "PARTUUID=$(ANDROID_VBMETA_PARTUUID)")) {
25437a7bc39SJason Zhu ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
25537a7bc39SJason Zhu goto out;
25637a7bc39SJason Zhu }
257*69fdc596SJason Zhu }
25837a7bc39SJason Zhu
25937a7bc39SJason Zhu /* Add androidboot.vbmeta.avb_version option. */
26037a7bc39SJason Zhu if (!cmdline_append_version(slot_data,
26137a7bc39SJason Zhu "androidboot.vbmeta.avb_version",
26237a7bc39SJason Zhu AVB_VERSION_MAJOR,
26337a7bc39SJason Zhu AVB_VERSION_MINOR)) {
26437a7bc39SJason Zhu ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
26537a7bc39SJason Zhu goto out;
26637a7bc39SJason Zhu }
26737a7bc39SJason Zhu
26837a7bc39SJason Zhu /* Set androidboot.avb.device_state to "locked" or "unlocked". */
26937a7bc39SJason Zhu io_ret = ops->read_is_device_unlocked(ops, &is_device_unlocked);
27037a7bc39SJason Zhu if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
27137a7bc39SJason Zhu ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
27237a7bc39SJason Zhu goto out;
27337a7bc39SJason Zhu } else if (io_ret != AVB_IO_RESULT_OK) {
27437a7bc39SJason Zhu avb_error("Error getting device state.\n");
27537a7bc39SJason Zhu ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
27637a7bc39SJason Zhu goto out;
27737a7bc39SJason Zhu }
27837a7bc39SJason Zhu if (!cmdline_append_option(slot_data,
27937a7bc39SJason Zhu "androidboot.vbmeta.device_state",
28037a7bc39SJason Zhu is_device_unlocked ? "unlocked" : "locked")) {
28137a7bc39SJason Zhu ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
28237a7bc39SJason Zhu goto out;
28337a7bc39SJason Zhu }
28437a7bc39SJason Zhu
28537a7bc39SJason Zhu /* Set androidboot.vbmeta.{hash_alg, size, digest} - use same hash
28637a7bc39SJason Zhu * function as is used to sign vbmeta.
28737a7bc39SJason Zhu */
28837a7bc39SJason Zhu switch (algorithm_type) {
28937a7bc39SJason Zhu /* Explicit fallthrough. */
29037a7bc39SJason Zhu case AVB_ALGORITHM_TYPE_NONE:
29137a7bc39SJason Zhu case AVB_ALGORITHM_TYPE_SHA256_RSA2048:
29237a7bc39SJason Zhu case AVB_ALGORITHM_TYPE_SHA256_RSA4096:
29337a7bc39SJason Zhu case AVB_ALGORITHM_TYPE_SHA256_RSA8192: {
29437a7bc39SJason Zhu size_t n, total_size = 0;
295ab608f80SJason Zhu uint8_t vbmeta_digest[AVB_SHA256_DIGEST_SIZE];
296ab608f80SJason Zhu avb_slot_verify_data_calculate_vbmeta_digest(
297ab608f80SJason Zhu slot_data, AVB_DIGEST_TYPE_SHA256, vbmeta_digest);
29837a7bc39SJason Zhu for (n = 0; n < slot_data->num_vbmeta_images; n++) {
29937a7bc39SJason Zhu total_size += slot_data->vbmeta_images[n].vbmeta_size;
30037a7bc39SJason Zhu }
30137a7bc39SJason Zhu if (!cmdline_append_option(
30237a7bc39SJason Zhu slot_data, "androidboot.vbmeta.hash_alg", "sha256") ||
30337a7bc39SJason Zhu !cmdline_append_uint64_base10(
30437a7bc39SJason Zhu slot_data, "androidboot.vbmeta.size", total_size) ||
30537a7bc39SJason Zhu !cmdline_append_hex(slot_data,
30637a7bc39SJason Zhu "androidboot.vbmeta.digest",
307ab608f80SJason Zhu vbmeta_digest,
30837a7bc39SJason Zhu AVB_SHA256_DIGEST_SIZE)) {
30937a7bc39SJason Zhu ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
31037a7bc39SJason Zhu goto out;
31137a7bc39SJason Zhu }
31237a7bc39SJason Zhu } break;
31337a7bc39SJason Zhu /* Explicit fallthrough. */
31437a7bc39SJason Zhu case AVB_ALGORITHM_TYPE_SHA512_RSA2048:
31537a7bc39SJason Zhu case AVB_ALGORITHM_TYPE_SHA512_RSA4096:
31637a7bc39SJason Zhu case AVB_ALGORITHM_TYPE_SHA512_RSA8192: {
31737a7bc39SJason Zhu size_t n, total_size = 0;
318ab608f80SJason Zhu uint8_t vbmeta_digest[AVB_SHA512_DIGEST_SIZE];
319ab608f80SJason Zhu avb_slot_verify_data_calculate_vbmeta_digest(
320ab608f80SJason Zhu slot_data, AVB_DIGEST_TYPE_SHA512, vbmeta_digest);
32137a7bc39SJason Zhu for (n = 0; n < slot_data->num_vbmeta_images; n++) {
32237a7bc39SJason Zhu total_size += slot_data->vbmeta_images[n].vbmeta_size;
32337a7bc39SJason Zhu }
32437a7bc39SJason Zhu if (!cmdline_append_option(
32537a7bc39SJason Zhu slot_data, "androidboot.vbmeta.hash_alg", "sha512") ||
32637a7bc39SJason Zhu !cmdline_append_uint64_base10(
32737a7bc39SJason Zhu slot_data, "androidboot.vbmeta.size", total_size) ||
32837a7bc39SJason Zhu !cmdline_append_hex(slot_data,
32937a7bc39SJason Zhu "androidboot.vbmeta.digest",
330ab608f80SJason Zhu vbmeta_digest,
33137a7bc39SJason Zhu AVB_SHA512_DIGEST_SIZE)) {
33237a7bc39SJason Zhu ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
33337a7bc39SJason Zhu goto out;
33437a7bc39SJason Zhu }
33537a7bc39SJason Zhu } break;
33637a7bc39SJason Zhu case _AVB_ALGORITHM_NUM_TYPES:
33737a7bc39SJason Zhu avb_assert_not_reached();
33837a7bc39SJason Zhu break;
33937a7bc39SJason Zhu }
34037a7bc39SJason Zhu
34137a7bc39SJason Zhu /* Set androidboot.veritymode and androidboot.vbmeta.invalidate_on_error */
34237a7bc39SJason Zhu if (toplevel_vbmeta->flags & AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED) {
34337a7bc39SJason Zhu verity_mode = "disabled";
34437a7bc39SJason Zhu } else {
34537a7bc39SJason Zhu const char* dm_verity_mode = NULL;
34637a7bc39SJason Zhu char* new_ret;
34737a7bc39SJason Zhu
348*69fdc596SJason Zhu switch (resolved_hashtree_error_mode) {
34937a7bc39SJason Zhu case AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE:
35037a7bc39SJason Zhu if (!cmdline_append_option(
35137a7bc39SJason Zhu slot_data, "androidboot.vbmeta.invalidate_on_error", "yes")) {
35237a7bc39SJason Zhu ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
35337a7bc39SJason Zhu goto out;
35437a7bc39SJason Zhu }
35537a7bc39SJason Zhu verity_mode = "enforcing";
35637a7bc39SJason Zhu dm_verity_mode = "restart_on_corruption";
35737a7bc39SJason Zhu break;
35837a7bc39SJason Zhu case AVB_HASHTREE_ERROR_MODE_RESTART:
35937a7bc39SJason Zhu verity_mode = "enforcing";
36037a7bc39SJason Zhu dm_verity_mode = "restart_on_corruption";
36137a7bc39SJason Zhu break;
36237a7bc39SJason Zhu case AVB_HASHTREE_ERROR_MODE_EIO:
36337a7bc39SJason Zhu verity_mode = "eio";
36437a7bc39SJason Zhu /* For now there's no option to specify the EIO mode. So
36537a7bc39SJason Zhu * just use 'ignore_zero_blocks' since that's already set
36637a7bc39SJason Zhu * and dm-verity-target.c supports specifying this multiple
36737a7bc39SJason Zhu * times.
36837a7bc39SJason Zhu */
36937a7bc39SJason Zhu dm_verity_mode = "ignore_zero_blocks";
37037a7bc39SJason Zhu break;
37137a7bc39SJason Zhu case AVB_HASHTREE_ERROR_MODE_LOGGING:
37237a7bc39SJason Zhu verity_mode = "logging";
37337a7bc39SJason Zhu dm_verity_mode = "ignore_corruption";
37437a7bc39SJason Zhu break;
375*69fdc596SJason Zhu case AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO:
376*69fdc596SJason Zhu // Should never get here because MANAGED_RESTART_AND_EIO is
377*69fdc596SJason Zhu // remapped by avb_manage_hashtree_error_mode().
378*69fdc596SJason Zhu avb_assert_not_reached();
379*69fdc596SJason Zhu break;
38037a7bc39SJason Zhu }
38137a7bc39SJason Zhu new_ret = avb_replace(
38237a7bc39SJason Zhu slot_data->cmdline, "$(ANDROID_VERITY_MODE)", dm_verity_mode);
38337a7bc39SJason Zhu avb_free(slot_data->cmdline);
38437a7bc39SJason Zhu slot_data->cmdline = new_ret;
38537a7bc39SJason Zhu if (slot_data->cmdline == NULL) {
38637a7bc39SJason Zhu ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
38737a7bc39SJason Zhu goto out;
38837a7bc39SJason Zhu }
38937a7bc39SJason Zhu }
39037a7bc39SJason Zhu if (!cmdline_append_option(
39137a7bc39SJason Zhu slot_data, "androidboot.veritymode", verity_mode)) {
39237a7bc39SJason Zhu ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
39337a7bc39SJason Zhu goto out;
39437a7bc39SJason Zhu }
395*69fdc596SJason Zhu if (hashtree_error_mode == AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO) {
396*69fdc596SJason Zhu if (!cmdline_append_option(
397*69fdc596SJason Zhu slot_data, "androidboot.veritymode.managed", "yes")) {
398*69fdc596SJason Zhu ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
399*69fdc596SJason Zhu goto out;
400*69fdc596SJason Zhu }
401*69fdc596SJason Zhu }
40237a7bc39SJason Zhu
40337a7bc39SJason Zhu ret = AVB_SLOT_VERIFY_RESULT_OK;
40437a7bc39SJason Zhu
40537a7bc39SJason Zhu out:
40637a7bc39SJason Zhu
40737a7bc39SJason Zhu return ret;
40837a7bc39SJason Zhu }
40937a7bc39SJason Zhu
avb_new_cmdline_subst_list()410ab608f80SJason Zhu AvbCmdlineSubstList* avb_new_cmdline_subst_list() {
411ab608f80SJason Zhu return (AvbCmdlineSubstList*)avb_calloc(sizeof(AvbCmdlineSubstList));
412ab608f80SJason Zhu }
413ab608f80SJason Zhu
avb_free_cmdline_subst_list(AvbCmdlineSubstList * cmdline_subst)414ab608f80SJason Zhu void avb_free_cmdline_subst_list(AvbCmdlineSubstList* cmdline_subst) {
415ab608f80SJason Zhu size_t i;
416ab608f80SJason Zhu for (i = 0; i < cmdline_subst->size; ++i) {
417ab608f80SJason Zhu avb_free(cmdline_subst->tokens[i]);
418ab608f80SJason Zhu avb_free(cmdline_subst->values[i]);
419ab608f80SJason Zhu }
420ab608f80SJason Zhu cmdline_subst->size = 0;
421ab608f80SJason Zhu avb_free(cmdline_subst);
422ab608f80SJason Zhu }
423ab608f80SJason Zhu
avb_add_root_digest_substitution(const char * part_name,const uint8_t * digest,size_t digest_size,AvbCmdlineSubstList * out_cmdline_subst)424ab608f80SJason Zhu AvbSlotVerifyResult avb_add_root_digest_substitution(
425ab608f80SJason Zhu const char* part_name,
426ab608f80SJason Zhu const uint8_t* digest,
427ab608f80SJason Zhu size_t digest_size,
428ab608f80SJason Zhu AvbCmdlineSubstList* out_cmdline_subst) {
429ab608f80SJason Zhu const char* kDigestSubPrefix = "$(AVB_";
430ab608f80SJason Zhu const char* kDigestSubSuffix = "_ROOT_DIGEST)";
431ab608f80SJason Zhu size_t part_name_len = avb_strlen(part_name);
432ab608f80SJason Zhu size_t list_index = out_cmdline_subst->size;
433ab608f80SJason Zhu
434ab608f80SJason Zhu avb_assert(part_name_len < AVB_PART_NAME_MAX_SIZE);
435ab608f80SJason Zhu avb_assert(digest_size <= AVB_SHA512_DIGEST_SIZE);
436ab608f80SJason Zhu if (part_name_len >= AVB_PART_NAME_MAX_SIZE ||
437ab608f80SJason Zhu digest_size > AVB_SHA512_DIGEST_SIZE) {
438ab608f80SJason Zhu return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
439ab608f80SJason Zhu }
440ab608f80SJason Zhu
441ab608f80SJason Zhu if (out_cmdline_subst->size >= AVB_MAX_NUM_CMDLINE_SUBST) {
442ab608f80SJason Zhu /* The list is full. Currently dynamic growth of this list is not supported.
443ab608f80SJason Zhu */
444ab608f80SJason Zhu return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
445ab608f80SJason Zhu }
446ab608f80SJason Zhu
447ab608f80SJason Zhu /* Construct the token to replace in the command line based on the partition
448ab608f80SJason Zhu * name. For partition 'foo', this will be '$(AVB_FOO_ROOT_DIGEST)'.
449ab608f80SJason Zhu */
450ab608f80SJason Zhu out_cmdline_subst->tokens[list_index] =
451ab608f80SJason Zhu avb_strdupv(kDigestSubPrefix, part_name, kDigestSubSuffix, NULL);
452ab608f80SJason Zhu if (out_cmdline_subst->tokens[list_index] == NULL) {
453ab608f80SJason Zhu goto fail;
454ab608f80SJason Zhu }
455ab608f80SJason Zhu avb_uppercase(out_cmdline_subst->tokens[list_index]);
456ab608f80SJason Zhu
457ab608f80SJason Zhu /* The digest value is hex encoded when inserted in the command line. */
458ab608f80SJason Zhu out_cmdline_subst->values[list_index] = avb_bin2hex(digest, digest_size);
459ab608f80SJason Zhu if (out_cmdline_subst->values[list_index] == NULL) {
460ab608f80SJason Zhu goto fail;
461ab608f80SJason Zhu }
462ab608f80SJason Zhu
463ab608f80SJason Zhu out_cmdline_subst->size++;
464ab608f80SJason Zhu return AVB_SLOT_VERIFY_RESULT_OK;
465ab608f80SJason Zhu
466ab608f80SJason Zhu fail:
467ab608f80SJason Zhu if (out_cmdline_subst->tokens[list_index]) {
468ab608f80SJason Zhu avb_free(out_cmdline_subst->tokens[list_index]);
469ab608f80SJason Zhu }
470ab608f80SJason Zhu if (out_cmdline_subst->values[list_index]) {
471ab608f80SJason Zhu avb_free(out_cmdline_subst->values[list_index]);
472ab608f80SJason Zhu }
473ab608f80SJason Zhu return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
474ab608f80SJason Zhu }
475