diff options
-rw-r--r-- | arch/sandbox/Kconfig | 7 | ||||
-rw-r--r-- | arch/sandbox/Makefile | 2 | ||||
-rw-r--r-- | arch/sandbox/board/poweroff.c | 13 | ||||
-rw-r--r-- | arch/sandbox/mach-sandbox/include/mach/linux.h | 1 | ||||
-rw-r--r-- | arch/sandbox/os/common.c | 49 | ||||
-rw-r--r-- | arch/sandbox/os/tap.c | 2 |
6 files changed, 63 insertions, 11 deletions
diff --git a/arch/sandbox/Kconfig b/arch/sandbox/Kconfig index c4d0ab4dbc..b5213c662b 100644 --- a/arch/sandbox/Kconfig +++ b/arch/sandbox/Kconfig @@ -24,6 +24,13 @@ config SANDBOX_UNWIND select ARCH_HAS_STACK_DUMP depends on KASAN +config SANDBOX_REEXEC + prompt "exec(2) reset handler" + def_bool y + help + The normal reset handler hangs barebox. On Linux, barebox + instead can exec itself to simulate a reset. + config PHYS_ADDR_T_64BIT bool diff --git a/arch/sandbox/Makefile b/arch/sandbox/Makefile index 27021222dc..eb678b72db 100644 --- a/arch/sandbox/Makefile +++ b/arch/sandbox/Makefile @@ -25,7 +25,7 @@ KBUILD_CFLAGS += -Dmalloc=barebox_malloc -Dcalloc=barebox_calloc \ -Dglob=barebox_glob -Dglobfree=barebox_globfree \ -Dioctl=barebox_ioctl -Dfstat=barebox_fstat \ -Dopendir=barebox_opendir -Dreaddir=barebox_readdir \ - -Dclosedir=barebox_closedir \ + -Dclosedir=barebox_closedir -Dreadlink=barebox_readlink \ -Doptarg=barebox_optarg -Doptind=barebox_optind machdirs := $(patsubst %,arch/sandbox/mach-%/,$(machine-y)) diff --git a/arch/sandbox/board/poweroff.c b/arch/sandbox/board/poweroff.c index 5072b756e1..8ce739af72 100644 --- a/arch/sandbox/board/poweroff.c +++ b/arch/sandbox/board/poweroff.c @@ -19,11 +19,24 @@ static struct restart_handler rst_hang = { .restart = sandbox_rst_hang }; +static void sandbox_rst_reexec(struct restart_handler *rst) +{ + linux_reexec(); +} + +static struct restart_handler rst_reexec = { + .name = "reexec", .priority = 200, + .restart = sandbox_rst_reexec, +}; + static int poweroff_register_feature(void) { poweroff_handler_register_fn(sandbox_poweroff); restart_handler_register(&rst_hang); + if (IS_ENABLED(CONFIG_SANDBOX_REEXEC)) + restart_handler_register(&rst_reexec); + return 0; } coredevice_initcall(poweroff_register_feature); diff --git a/arch/sandbox/mach-sandbox/include/mach/linux.h b/arch/sandbox/mach-sandbox/include/mach/linux.h index f0a3a7b510..1ab48e52a0 100644 --- a/arch/sandbox/mach-sandbox/include/mach/linux.h +++ b/arch/sandbox/mach-sandbox/include/mach/linux.h @@ -18,6 +18,7 @@ off_t linux_lseek(int fildes, off_t offset); int linux_tstc(int fd); void __attribute__((noreturn)) linux_exit(void); void linux_hang(void); +void linux_reexec(void); int linux_execve(const char * filename, char *const argv[], char *const envp[]); diff --git a/arch/sandbox/os/common.c b/arch/sandbox/os/common.c index bbab3bd231..9d59418136 100644 --- a/arch/sandbox/os/common.c +++ b/arch/sandbox/os/common.c @@ -44,6 +44,8 @@ #include <mach/linux.h> #include <mach/hostfile.h> +#define DELETED_OFFSET (sizeof(" (deleted)") - 1) + void __sanitizer_set_death_callback(void (*callback)(void)); int sdl_xres; @@ -122,6 +124,31 @@ void __attribute__((noreturn)) linux_exit(void) exit(0); } +static char **saved_argv; + +void linux_reexec(void) +{ + char buf[4097]; + ssize_t ret; + + cookmode(); + + /* we must follow the symlink, so we can exec an updated executable */ + ret = readlink("/proc/self/exe", buf, sizeof(buf) - 1); + if (0 < ret && ret < sizeof(buf) - 1) { + buf[ret] = '\0'; + execv(buf, saved_argv); + if (!strcmp(&buf[ret - DELETED_OFFSET], " (deleted)")) { + printf("barebox image on disk changed. Loading new.\n"); + buf[ret - DELETED_OFFSET] = '\0'; + execv(buf, saved_argv); + } + } + + printf("exec(%s) failed: %d\n", buf, errno); + /* falls through to generic hang() */ +} + void linux_hang(void) { cookmode(); @@ -130,7 +157,7 @@ void linux_hang(void) int linux_open(const char *filename, int readwrite) { - return open(filename, readwrite ? O_RDWR : O_RDONLY); + return open(filename, (readwrite ? O_RDWR : O_RDONLY) | O_CLOEXEC); } int linux_read(int fd, void *buf, size_t count) @@ -220,10 +247,10 @@ extern void mem_malloc_init(void *start, void *end); extern char * strsep_unescaped(char **s, const char *ct); -static int add_image(char *str, char *devname_template, int *devname_number) +static int add_image(const char *_str, char *devname_template, int *devname_number) { struct hf_info *hf = malloc(sizeof(struct hf_info)); - char *filename, *devname; + char *str, *filename, *devname; char tmp[16]; int readonly = 0; struct stat s; @@ -233,6 +260,8 @@ static int add_image(char *str, char *devname_template, int *devname_number) if (!hf) return -1; + str = strdup(_str); + filename = strsep_unescaped(&str, ","); while ((opt = strsep_unescaped(&str, ","))) { if (!strcmp(opt, "ro")) @@ -252,7 +281,7 @@ static int add_image(char *str, char *devname_template, int *devname_number) printf("add %s backed by file %s%s\n", devname, filename, readonly ? "(ro)" : ""); - fd = open(filename, readonly ? O_RDONLY : O_RDWR); + fd = open(filename, (readonly ? O_RDONLY : O_RDWR) | O_CLOEXEC); hf->fd = fd; hf->filename = filename; @@ -303,7 +332,7 @@ static int add_dtb(const char *file) void *dtb = NULL; int fd; - fd = open(file, O_RDONLY); + fd = open(file, O_RDONLY | O_CLOEXEC); if (fd < 0) { perror("open"); goto err_out; @@ -363,6 +392,8 @@ int main(int argc, char *argv[]) __sanitizer_set_death_callback(cookmode); #endif + saved_argv = argv; + while (1) { option_index = 0; opt = getopt_long(argc, argv, optstring, @@ -434,7 +465,7 @@ int main(int argc, char *argv[]) exit(1); break; case 'O': - fd = open(optarg, O_WRONLY); + fd = open(optarg, O_WRONLY | O_CLOEXEC); if (fd < 0) { perror("open"); exit(1); @@ -443,7 +474,7 @@ int main(int argc, char *argv[]) barebox_register_console(-1, fd); break; case 'I': - fd = open(optarg, O_RDWR); + fd = open(optarg, O_RDWR | O_CLOEXEC); if (fd < 0) { perror("open"); exit(1); @@ -459,7 +490,7 @@ int main(int argc, char *argv[]) } /* open stdout file */ - fd = open(aux + 1, O_WRONLY); + fd = open(aux + 1, O_WRONLY | O_CLOEXEC); if (fd < 0) { perror("open stdout"); exit(1); @@ -467,7 +498,7 @@ int main(int argc, char *argv[]) /* open stdin file */ aux = strndup(optarg, aux - optarg); - fd2 = open(aux, O_RDWR); + fd2 = open(aux, O_RDWR | O_CLOEXEC); if (fd2 < 0) { perror("open stdin"); exit(1); diff --git a/arch/sandbox/os/tap.c b/arch/sandbox/os/tap.c index 72b7fbb5ac..83b97ffd49 100644 --- a/arch/sandbox/os/tap.c +++ b/arch/sandbox/os/tap.c @@ -30,7 +30,7 @@ int tap_alloc(const char *dev) struct ifreq ifr; int fd, err; - if ((fd = open("/dev/net/tun", O_RDWR)) < 0) { + if ((fd = open("/dev/net/tun", O_RDWR | O_CLOEXEC)) < 0) { perror("could not open /dev/net/tun"); return -1; } |