From: Frieder Schrempf <[email protected]>
The name of the BOOT_x_LEFT variable of a slot is written into a stack
buffer of BOOT_LEFT_LEN bytes with sprintf(). BOOT_LEFT_LEN leaves room
for a slot name of 32 characters, but not for the terminating NUL, and
longer names are not limited at all.
When booting, the slot names come from BOOT_ORDER in the environment,
which is only checked against the configured slots when the bootflow is
read. Setting BOOT_ORDER to a long name between 'bootflow scan' and
'bootflow boot' therefore overflows the buffer in find_active_slot().
Make room for the NUL, and write the name with snprintf() in a helper
that fails with -E2BIG if it does not fit.
Fixes: 7e5c2c782fb9 ("bootstd: Add implementation for bootmeth rauc")
Assisted-by: LLM
Signed-off-by: Frieder Schrempf <[email protected]>
---
boot/bootmeth_rauc.c | 34 +++++++++++++++++++++++++++-------
1 file changed, 27 insertions(+), 7 deletions(-)
diff --git a/boot/bootmeth_rauc.c b/boot/bootmeth_rauc.c
index 3442b9e99d4..fc073aadd21 100644
--- a/boot/bootmeth_rauc.c
+++ b/boot/bootmeth_rauc.c
@@ -22,8 +22,8 @@
#include <linux/stringify.h>
#include <asm/cache.h>
-/* Length of env var "BOOT_*_LEFT" */
-#define BOOT_LEFT_LEN (5 + 32 + 5)
+/* Length of env var "BOOT_*_LEFT", including the terminating NUL */
+#define BOOT_LEFT_LEN (5 + 32 + 5 + 1)
static const char * const script_names[] = { "boot.scr", "boot.scr.uimg", NULL
};
@@ -66,6 +66,15 @@ static void distro_rauc_priv_free(struct distro_rauc_priv
*priv)
free(priv);
}
+static int boot_left_name(char *buf, const char *slot_name)
+{
+ if (snprintf(buf, BOOT_LEFT_LEN, "BOOT_%s_LEFT", slot_name) >=
+ BOOT_LEFT_LEN)
+ return log_msg_ret("name", -E2BIG);
+
+ return 0;
+}
+
static struct distro_rauc_slot *get_slot(struct distro_rauc_priv *priv,
const char *slot_name)
{
@@ -167,7 +176,10 @@ static int distro_rauc_read_bootflow(struct udevice *dev,
struct bootflow *bflow
default_boot_order = CONFIG_BOOTMETH_RAUC_BOOT_ORDER;
default_boot_order_list = str_to_list(default_boot_order);
for (i = 0; default_boot_order_list[i]; i++) {
- sprintf(boot_left, "BOOT_%s_LEFT", default_boot_order_list[i]);
+ if (boot_left_name(boot_left, default_boot_order_list[i])) {
+ str_free_list(default_boot_order_list);
+ return log_msg_ret("env", -E2BIG);
+ }
if (!env_get(boot_left)) {
log_debug("%s did not exist yet, setting default
value\n",
boot_left);
@@ -333,7 +345,11 @@ static int find_active_slot(char **slot_name, ulong
*slot_tries)
return log_msg_ret("env", -ENOENT);
boot_order_list = str_to_list(boot_order);
for (i = 0; boot_order_list[i] && !slot_found; i++) {
- sprintf(boot_left, "BOOT_%s_LEFT", boot_order_list[i]);
+ ret = boot_left_name(boot_left, boot_order_list[i]);
+ if (ret) {
+ str_free_list(boot_order_list);
+ return ret;
+ }
tries = env_get_ulong(boot_left, 10, ULONG_MAX);
if (tries == ULONG_MAX) {
str_free_list(boot_order_list);
@@ -363,7 +379,11 @@ static int find_active_slot(char **slot_name, ulong
*slot_tries)
log_info("INFO: Resetting all slot tries to "
__stringify(CONFIG_BOOTMETH_RAUC_DEFAULT_TRIES) "\n");
boot_order_list =
str_to_list(CONFIG_BOOTMETH_RAUC_BOOT_ORDER);
for (i = 0; boot_order_list[i]; i++) {
- sprintf(boot_left, "BOOT_%s_LEFT",
boot_order_list[i]);
+ ret = boot_left_name(boot_left,
boot_order_list[i]);
+ if (ret) {
+ str_free_list(boot_order_list);
+ return ret;
+ }
ret = env_set_ulong(boot_left,
CONFIG_BOOTMETH_RAUC_DEFAULT_TRIES);
if (ret) {
str_free_list(boot_order_list);
@@ -459,8 +479,8 @@ static int distro_rauc_boot(struct udevice *dev, struct
bootflow *bflow)
log_debug("BOOT_ORDER: %s\n", boot_order);
boot_order_list = str_to_list(boot_order);
for (i = 0; boot_order_list[i]; i++) {
- sprintf(boot_left, "BOOT_%s_LEFT", boot_order_list[i]);
- log_debug("%s: %s\n", boot_left, env_get(boot_left));
+ if (!boot_left_name(boot_left, boot_order_list[i]))
+ log_debug("%s: %s\n", boot_left, env_get(boot_left));
}
str_free_list(boot_order_list);
--
2.56.0