libavb: Don't pass androidboot.slot_suffix in generated kernel command-line.
It's not appropriate to do this since the boot loader's A/B stack will
likely do this. Also add new avb_strdupv() utility function so it's
easy to do this yourself and update UEFI example bootloader to use
this.
Bug: None
Test: New unit tests + all unit tests pass.
Test: Manually tested on UEFI based bootloader.
Change-Id: I9f9596b1f273330e80a38d857233167fefcce01b
diff --git a/examples/uefi/main.c b/examples/uefi/main.c
index 8d9c0ee..c5a0030 100644
--- a/examples/uefi/main.c
+++ b/examples/uefi/main.c
@@ -38,6 +38,7 @@
UEFIAvbBootKernelResult boot_result;
const char* requested_partitions[] = {"boot", NULL};
bool unlocked = true;
+ char* additional_cmdline = NULL;
InitializeLib(ImageHandle, SystemTable);
@@ -69,14 +70,24 @@
case AVB_AB_FLOW_RESULT_OK_WITH_VERIFICATION_ERROR:
avb_printv("slot_suffix: ", slot_data->ab_suffix, "\n", NULL);
avb_printv("cmdline: ", slot_data->cmdline, "\n", NULL);
- /* Pass 'skip_initramfs' since we're not booting into recovery mode. */
+ /* Pass 'skip_initramfs' since we're not booting into recovery
+ * mode. Also pass the selected slot in androidboot.slot_suffix.
+ */
+ additional_cmdline = avb_strdupv("skip_initramfs ",
+ "androidboot.slot_suffix=",
+ slot_data->ab_suffix,
+ NULL);
+ if (additional_cmdline == NULL) {
+ avb_fatal("Error allocating additional_cmdline.\n");
+ }
boot_result =
- uefi_avb_boot_kernel(ImageHandle, slot_data, "skip_initramfs");
+ uefi_avb_boot_kernel(ImageHandle, slot_data, additional_cmdline);
avb_fatalv("uefi_avb_boot_kernel() failed with error ",
uefi_avb_boot_kernel_result_to_string(boot_result),
"\n",
NULL);
avb_slot_verify_data_free(slot_data);
+ avb_free(additional_cmdline);
break;
case AVB_AB_FLOW_RESULT_ERROR_OOM:
avb_fatal("OOM error while doing A/B select flow.\n");
diff --git a/libavb/avb_slot_verify.c b/libavb/avb_slot_verify.c
index 296d831..f1d9de9 100644
--- a/libavb/avb_slot_verify.c
+++ b/libavb/avb_slot_verify.c
@@ -911,15 +911,6 @@
slot_data->cmdline = new_cmdline;
}
- /* Add androidboot.slot_suffix, if applicable. */
- if (avb_strlen(ab_suffix) > 0) {
- if (!cmdline_append_option(
- slot_data, "androidboot.slot_suffix", ab_suffix)) {
- ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
- goto fail;
- }
- }
-
/* Set androidboot.avb.device_state to "locked" or "unlocked". */
bool is_device_unlocked;
io_ret = ops->read_is_device_unlocked(ops, &is_device_unlocked);
diff --git a/libavb/avb_slot_verify.h b/libavb/avb_slot_verify.h
index 93c12ba..a601bd3 100644
--- a/libavb/avb_slot_verify.h
+++ b/libavb/avb_slot_verify.h
@@ -138,10 +138,6 @@
* depending on the result of the result of AvbOps's
* read_is_unlocked() function.
*
- * androidboot.slot_suffix: If |ab_suffix| as passed into
- * avb_slot_verify() is non-empty, this variable will be set to its
- * value.
- *
* androidboot.vbmeta.{hash_alg, size, digest}: Will be set to
* the digest of all images in |vbmeta_images|.
*
@@ -150,6 +146,9 @@
* will end up pointing to the vbmeta partition for the verified
* slot.
*
+ * Note that androidboot.slot_suffix is not set in |cmdline| - you
+ * will have to do pass this command-line option yourself.
+ *
* This struct may grow in the future without it being considered an
* ABI break.
*/
diff --git a/libavb/avb_util.c b/libavb/avb_util.c
index 5a57b62..ba0f278 100644
--- a/libavb/avb_util.c
+++ b/libavb/avb_util.c
@@ -24,6 +24,8 @@
#include "avb_util.h"
+#include <stdarg.h>
+
uint32_t avb_be32toh(uint32_t in) {
uint8_t* d = (uint8_t*)∈
uint32_t ret;
@@ -336,3 +338,46 @@
out:
return ret;
}
+
+/* We only support a limited amount of strings in avb_strdupv(). */
+#define STRDUPV_MAX_NUM_STRINGS 32
+
+char* avb_strdupv(const char* str, ...) {
+ va_list ap;
+ const char* strings[STRDUPV_MAX_NUM_STRINGS];
+ size_t lengths[STRDUPV_MAX_NUM_STRINGS];
+ size_t num_strings, n, total_length;
+ char *ret = NULL, *dest;
+
+ num_strings = 0;
+ total_length = 0;
+ va_start(ap, str);
+ do {
+ strings[num_strings] = str;
+ lengths[num_strings] = avb_strlen(str);
+ total_length += lengths[num_strings];
+ num_strings++;
+ if (num_strings == STRDUPV_MAX_NUM_STRINGS) {
+ avb_fatal("Too many strings passed to avb_strdupv().\n");
+ break;
+ }
+ str = va_arg(ap, const char*);
+ } while (str != NULL);
+ va_end(ap);
+
+ ret = avb_malloc(total_length + 1);
+ if (ret == NULL) {
+ goto out;
+ }
+
+ dest = ret;
+ for (n = 0; n < num_strings; n++) {
+ avb_memcpy(dest, strings[n], lengths[n]);
+ dest += lengths[n];
+ }
+ *dest = '\0';
+ avb_assert(dest == ret + total_length);
+
+out:
+ return ret;
+}
diff --git a/libavb/avb_util.h b/libavb/avb_util.h
index 352829a..1342de7 100644
--- a/libavb/avb_util.h
+++ b/libavb/avb_util.h
@@ -200,6 +200,13 @@
/* Duplicates a NUL-terminated string. Returns NULL on OOM. */
char* avb_strdup(const char* str) AVB_ATTR_WARN_UNUSED_RESULT;
+/* Duplicates a NULL-terminated array of NUL-terminated strings by
+ * concatening them. The returned string will be
+ * NUL-terminated. Returns NULL on OOM.
+ */
+char* avb_strdupv(const char* str,
+ ...) AVB_ATTR_WARN_UNUSED_RESULT AVB_ATTR_SENTINEL;
+
/* Finds the first occurrence of |needle| in the string |haystack|
* where both strings are NUL-terminated strings. The terminating NUL
* bytes are not compared.
diff --git a/libavb_ab/avb_ab_flow.h b/libavb_ab/avb_ab_flow.h
index 6f6a3d2..bc18744 100644
--- a/libavb_ab/avb_ab_flow.h
+++ b/libavb_ab/avb_ab_flow.h
@@ -189,6 +189,10 @@
* AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX for the slot in
* question.
*
+ * Note that androidboot.slot_suffix is not set in the |cmdline| field
+ * in |AvbSlotVerifyData| - you will have to do pass this command-line
+ * option yourself.
+ *
* If a slot was selected and it verified then AVB_AB_FLOW_RESULT_OK
* is returned.
*
diff --git a/test/avb_slot_verify_unittest.cc b/test/avb_slot_verify_unittest.cc
index 51cfb23..5df5cfd 100644
--- a/test/avb_slot_verify_unittest.cc
+++ b/test/avb_slot_verify_unittest.cc
@@ -69,7 +69,7 @@
EXPECT_NE(nullptr, slot_data);
EXPECT_EQ(
"androidboot.vbmeta.device=PARTUUID=1234-fake-guid-for:vbmeta_a "
- "androidboot.slot_suffix=_a androidboot.vbmeta.device_state=locked "
+ "androidboot.vbmeta.device_state=locked "
"androidboot.vbmeta.hash_alg=sha256 androidboot.vbmeta.size=1152 "
"androidboot.vbmeta.digest="
"4161a7e655eabe16c3fe714de5d43736e7c0a190cf08d36c946d2509ce071e4d",
@@ -97,7 +97,7 @@
EXPECT_NE(nullptr, slot_data);
EXPECT_EQ(
"androidboot.vbmeta.device=PARTUUID=1234-fake-guid-for:vbmeta_a "
- "androidboot.slot_suffix=_a androidboot.vbmeta.device_state=locked "
+ "androidboot.vbmeta.device_state=locked "
"androidboot.vbmeta.hash_alg=sha512 androidboot.vbmeta.size=1152 "
"androidboot.vbmeta.digest="
"cb913d2f1a884f4e04c1db5bb181f3133fd16ac02fb367a20ef0776c0b07b3656ad1f081"
@@ -128,7 +128,7 @@
EXPECT_NE(nullptr, slot_data);
EXPECT_EQ(
"androidboot.vbmeta.device=PARTUUID=1234-fake-guid-for:vbmeta_a "
- "androidboot.slot_suffix=_a androidboot.vbmeta.device_state=unlocked "
+ "androidboot.vbmeta.device_state=unlocked "
"androidboot.vbmeta.hash_alg=sha256 androidboot.vbmeta.size=1152 "
"androidboot.vbmeta.digest="
"4161a7e655eabe16c3fe714de5d43736e7c0a190cf08d36c946d2509ce071e4d",
@@ -428,7 +428,7 @@
"cmdline in vbmeta 1234-fake-guid-for:boot_a cmdline in hash footer "
"1234-fake-guid-for:system_a "
"androidboot.vbmeta.device=PARTUUID=1234-fake-guid-for:vbmeta_a "
- "androidboot.slot_suffix=_a androidboot.vbmeta.device_state=locked "
+ "androidboot.vbmeta.device_state=locked "
"androidboot.vbmeta.hash_alg=sha256 androidboot.vbmeta.size=1472 "
"androidboot.vbmeta.digest="
"34cdb59b955aa35d4da97701f304fabf7392eecca8c50ff1a0b7b6e1c9aaa1b8",
@@ -658,7 +658,7 @@
EXPECT_EQ(
"cmdline2 in hash footer cmdline2 in vbmeta "
"androidboot.vbmeta.device=PARTUUID=1234-fake-guid-for:vbmeta_a "
- "androidboot.slot_suffix=_a androidboot.vbmeta.device_state=locked "
+ "androidboot.vbmeta.device_state=locked "
"androidboot.vbmeta.hash_alg=sha256 androidboot.vbmeta.size=4416 "
"androidboot.vbmeta.digest="
"4a45faa9adfeb94e9154fe682c11fef1a1a3d829b67cbf1a12ac7f0aa4f8e2e4",
@@ -968,8 +968,7 @@
}
// This should match the two cmdlines with a space (U+0020) between
- // them - note that androidboot.slot_suffix is not set since we
- // don't have any slots in this setup.
+ // them.
EXPECT_EQ(
"cmdline2 in hash footer cmdline2 in vbmeta "
"androidboot.vbmeta.device=PARTUUID=1234-fake-guid-for:vbmeta "
@@ -1114,7 +1113,7 @@
EXPECT_NE(nullptr, slot_data);
EXPECT_EQ(
"androidboot.vbmeta.device=PARTUUID=1234-fake-guid-for:vbmeta_a "
- "androidboot.slot_suffix=_a androidboot.vbmeta.device_state=locked "
+ "androidboot.vbmeta.device_state=locked "
"androidboot.vbmeta.hash_alg=sha256 androidboot.vbmeta.size=2688 "
"androidboot.vbmeta.digest="
"5edcaa54f40382ee6a2fc3b86cdf383348b35ed07955e83ea32d84b69a97eaa0",
@@ -1214,7 +1213,7 @@
"restart_on_corruption ignore_zero_blocks\" root=0xfd00 "
"should_be_in_both=1 "
"androidboot.vbmeta.device=PARTUUID=1234-fake-guid-for:vbmeta_a "
- "androidboot.slot_suffix=_a androidboot.vbmeta.device_state=locked "
+ "androidboot.vbmeta.device_state=locked "
"androidboot.vbmeta.hash_alg=sha256 androidboot.vbmeta.size=1472 "
"androidboot.vbmeta.digest="
"32572f7a89fb44cc76e9e3adbc0cb5272d0604578b2179729aa52d2bba4061c3",
@@ -1223,7 +1222,7 @@
EXPECT_EQ(
"root=PARTUUID=1234-fake-guid-for:system_a should_be_in_both=1 "
"androidboot.vbmeta.device=PARTUUID=1234-fake-guid-for:vbmeta_a "
- "androidboot.slot_suffix=_a androidboot.vbmeta.device_state=locked "
+ "androidboot.vbmeta.device_state=locked "
"androidboot.vbmeta.hash_alg=sha256 androidboot.vbmeta.size=1472 "
"androidboot.vbmeta.digest="
"bb630c27d09e10117092d4444ea57a99bf44101c46cf5424cfb86928a0873249",
diff --git a/test/avb_util_unittest.cc b/test/avb_util_unittest.cc
index 0c8c375..4ee155d 100644
--- a/test/avb_util_unittest.cc
+++ b/test/avb_util_unittest.cc
@@ -470,6 +470,13 @@
std::string(avb_replace("$(FOO)$(FOO)", "$(FOO)", "LONGSTRING")));
}
+TEST(UtilTest, StrDupV) {
+ // We don't care about leaking avb_strdupv() result.
+ EXPECT_EQ("xyz", std::string(avb_strdupv("x", "y", "z", NULL)));
+ EXPECT_EQ("HelloWorld XYZ",
+ std::string(avb_strdupv("Hello", "World", " XYZ", NULL)));
+}
+
TEST(UtilTest, Crc32) {
/* Compare with output of crc32(1):
*