avb_cmdline.c 13 KB

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