Internal consumers need to inspect or use the downloaded data before deciding what to boot. Suppress autostart around their network commands and restore its exact value on every return. Route the TFTP helper, DHCP helper, PXE file callbacks, EFI device-tree download and lwIP net_loop shim through the download-only path. Keep the argv form so legacy IPv6 arguments are preserved.
Reuse the common protection from the automatic-update timeout helper instead of maintaining a separate autostart override. This protects script, EFI, PXE, update, DFU and bubt callers before command autostart is enabled for lwIP. Leave an already-disabled autostart value untouched, including a read-only setting. If autostart is enabled and cannot be suppressed, fail without starting the download. Signed-off-by: James Hilliard <[email protected]> --- boot/bootmeth_efi.c | 3 +-- boot/bootmeth_pxe.c | 3 +-- cmd/pxe.c | 2 +- include/net-common.h | 17 ++++++++++++-- net/net-common.c | 64 +++++++++++++++++++++++++++++++--------------------- 5 files changed, 56 insertions(+), 33 deletions(-) diff --git a/boot/bootmeth_efi.c b/boot/bootmeth_efi.c index e187dc39912..b315f41d870 100644 --- a/boot/bootmeth_efi.c +++ b/boot/bootmeth_efi.c @@ -221,7 +221,6 @@ static int distro_efi_read_bootflow_net(struct bootflow *bflow) { char file_addr[17], fname[256]; char *tftp_argv[] = {"tftp", file_addr, fname, NULL}; - struct cmd_tbl cmdtp = {}; /* dummy */ const char *addr_str, *fdt_addr_str, *bootfile_name; int ret, arch, size; ulong addr, fdt_addr; @@ -289,7 +288,7 @@ static int distro_efi_read_bootflow_net(struct bootflow *bflow) if (!bflow->fdt_fname) return log_msg_ret("fil", -ENOMEM); - if (!do_tftpb(&cmdtp, 0, 3, tftp_argv)) { + if (!tftpb_run_argv(3, tftp_argv)) { bflow->fdt_size = env_get_hex("filesize", 0); bflow->fdt_addr = fdt_addr; } else { diff --git a/boot/bootmeth_pxe.c b/boot/bootmeth_pxe.c index 7e999730e6a..27f254b9f93 100644 --- a/boot/bootmeth_pxe.c +++ b/boot/bootmeth_pxe.c @@ -102,7 +102,6 @@ static int extlinux_pxe_read_file(struct udevice *dev, struct bootflow *bflow, enum bootflow_img_t type, ulong *sizep) { char *tftp_argv[] = {"tftp", NULL, NULL, NULL}; - struct pxe_context *ctx = dev_get_priv(dev); char file_addr[17]; ulong size; int ret; @@ -111,7 +110,7 @@ static int extlinux_pxe_read_file(struct udevice *dev, struct bootflow *bflow, tftp_argv[1] = file_addr; tftp_argv[2] = (void *)file_path; - if (do_tftpb(ctx->cmdtp, 0, 3, tftp_argv)) + if (tftpb_run_argv(3, tftp_argv)) return -ENOENT; ret = pxe_get_file_size(&size); if (ret) diff --git a/cmd/pxe.c b/cmd/pxe.c index 3deae5e6d47..9635c834eb4 100644 --- a/cmd/pxe.c +++ b/cmd/pxe.c @@ -42,7 +42,7 @@ static int do_get_tftp(struct pxe_context *ctx, const char *file_path, num_args = 3; } - if (do_tftpb(ctx->cmdtp, 0, num_args, tftp_argv)) + if (tftpb_run_argv(num_args, tftp_argv)) return -ENOENT; ret = pxe_get_file_size(sizep); diff --git a/include/net-common.h b/include/net-common.h index 12c1689bf57..d5a95075ad7 100644 --- a/include/net-common.h +++ b/include/net-common.h @@ -504,7 +504,8 @@ int net_loop(enum proto_t protocol); * dhcp_run() - Run DHCP on the current ethernet device * * This temporarily sets autoload and restores its exact original value, - * including NFS and an unset variable. + * including NFS and an unset variable. Downloads never automatically boot; + * the caller owns the resulting image. The autostart variable is restored. * * @addr: Address to load the file into (0 if @autoload is false) * @fname: Filename of file to load (NULL if @autoload is false or to use the @@ -527,7 +528,7 @@ int dhcp_run(ulong addr, const char *fname, bool autoload); int do_dhcp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); /** - * tftpb_run() - Run TFTP on the current ethernet device + * tftpb_run() - Download via TFTP without automatically booting the image * * @addr: Address to load the file into * @fname: Filename of file to load (NULL to use the default filename) @@ -535,6 +536,18 @@ int do_dhcp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); */ int tftpb_run(ulong addr, const char *fname); +/** + * tftpb_run_argv() - Run TFTP arguments without automatically booting + * + * Preserves the exact autostart value on success and failure. This form also + * supports the legacy command's optional IPv6 argument. + * + * @argc: Number of command arguments + * @argv: Command arguments, including the command name + * Return: command status (see enum command_ret_t) + */ +int tftpb_run_argv(int argc, char *const argv[]); + /** * tftpb_run_timeout() - Download via TFTP with an initial server-probe timeout * diff --git a/net/net-common.c b/net/net-common.c index c5d13a23b09..85d97cb660c 100644 --- a/net/net-common.c +++ b/net/net-common.c @@ -64,11 +64,40 @@ void net_sntp_set_rtc(u32 seconds) tm.tm_hour, tm.tm_min, tm.tm_sec); } +#if defined(CONFIG_CMD_DHCP) || defined(CONFIG_CMD_TFTPBOOT) +/* Internal downloads return data to their caller; only commands may boot it. */ +static int netboot_run(int (*command)(struct cmd_tbl *, int, int, char *const []), + int argc, char *const argv[]) +{ + struct cmd_tbl cmdtp = {}; + const char *value; + char *saved; + int ret, restore; + + /* An already-disabled setting may be protected against writes. */ + if (!env_get_autostart()) + return command(&cmdtp, 0, argc, argv); + + value = env_get("autostart"); + saved = strdup(value); + if (!saved) + return CMD_RET_FAILURE; + if (env_set("autostart", "no")) { + free(saved); + return CMD_RET_FAILURE; + } + ret = command(&cmdtp, 0, argc, argv); + restore = env_set("autostart", saved); + free(saved); + + return ret ?: (restore ? CMD_RET_FAILURE : CMD_RET_SUCCESS); +} +#endif /* defined(CONFIG_CMD_DHCP) || defined(CONFIG_CMD_TFTPBOOT) */ + #if defined(CONFIG_CMD_DHCP) int dhcp_run(ulong addr, const char *fname, bool autoload) { char *dhcp_argv[] = {"dhcp", NULL, (char *)fname, NULL}; - struct cmd_tbl cmdtp = {}; /* dummy */ char file_addr[17]; const char *autoload_env = env_get("autoload"); char *saved_autoload = NULL; @@ -91,7 +120,7 @@ int dhcp_run(ulong addr, const char *fname, bool autoload) dhcp_argv[1] = file_addr; } - result = do_dhcp(&cmdtp, 0, !autoload ? 1 : fname ? 3 : 2, dhcp_argv); + result = netboot_run(do_dhcp, !autoload ? 1 : fname ? 3 : 2, dhcp_argv); ret = env_set("autoload", saved_autoload); free(saved_autoload); @@ -113,17 +142,21 @@ const struct tftp_request_timeout *tftp_get_request_timeout(void) return tftp_request_timeout; } +int tftpb_run_argv(int argc, char *const argv[]) +{ + return netboot_run(do_tftpb, argc, argv); +} + int tftpb_run(ulong addr, const char *fname) { char *tftp_argv[] = {"tftpboot", NULL, (char *)fname, NULL}; - struct cmd_tbl cmdtp = {}; /* dummy */ char file_addr[17] = {0}; log_debug("addr=%lx, fname=%s\n", addr, fname); sprintf(file_addr, "%lx", addr); tftp_argv[1] = file_addr; - int result = do_tftpb(&cmdtp, 0, fname ? 3 : 2, tftp_argv); + int result = tftpb_run_argv(fname ? 3 : 2, tftp_argv); if (result) return log_msg_ret("res", -ENOENT); @@ -136,37 +169,16 @@ int tftpb_run_timeout(ulong addr, const char *fname, ulong timeout_ms, { struct tftp_request_timeout timeout = { timeout_ms, max_retries }; const struct tftp_request_timeout *saved = tftp_request_timeout; - const char *autostart_env = env_get("autostart"); - char *saved_autostart = NULL; - int restore_ret = 0; int ret; if (!timeout_ms || timeout_ms > U32_MAX / 4 || max_retries < 0) return -EINVAL; - if (autostart_env) { - saved_autostart = strdup(autostart_env); - if (!saved_autostart) { - ret = -ENOMEM; - goto out_free; - } - } - - /* Updates need the downloaded data, not the command's automatic boot. */ - ret = env_set("autostart", "no"); - if (ret) - goto out_free; - tftp_request_timeout = &timeout; ret = tftpb_run(addr, fname); tftp_request_timeout = saved; - if (env_set("autostart", saved_autostart)) - restore_ret = -EINVAL; -out_free: - free(saved_autostart); - - return ret ?: restore_ret; + return ret; } #endif -- 2.53.0
