diff options
Diffstat (limited to 'arch/sandbox/os/common.c')
-rw-r--r-- | arch/sandbox/os/common.c | 249 |
1 files changed, 214 insertions, 35 deletions
diff --git a/arch/sandbox/os/common.c b/arch/sandbox/os/common.c index 382a923040..3446074f99 100644 --- a/arch/sandbox/os/common.c +++ b/arch/sandbox/os/common.c @@ -19,6 +19,7 @@ * These are host includes. Never include any barebox header * files here... */ +#define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <stdint.h> @@ -38,12 +39,17 @@ #include <sys/wait.h> #include <sys/ioctl.h> #include <linux/fs.h> +#include <sys/time.h> /* * ...except the ones needed to connect with barebox */ #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; int sdl_yres; @@ -69,6 +75,15 @@ static void cookmode(void) tcsetattr(0, TCSANOW, &term_orig); } +static char *stickypage_path; + +static void prepare_exit(void) +{ + cookmode(); + if (stickypage_path) + remove(stickypage_path); +} + int linux_tstc(int fd) { struct timeval tv = { @@ -116,13 +131,58 @@ uint64_t linux_get_time(void) void __attribute__((noreturn)) linux_exit(void) { - cookmode(); + prepare_exit(); exit(0); } +static char **saved_argv; + +static int selfpath(char *buf, size_t len) +{ + int ret; + + /* we must follow the symlink, so we can exec an updated executable */ + ret = readlink("/proc/self/exe", buf, len - 1); + if (ret < 0) + return ret; + + if (0 < ret && ret < len - 1) + buf[ret] = '\0'; + + return ret; +} + +void linux_reexec(void) +{ + char buf[4097]; + ssize_t ret; + + cookmode(); + + /* we must follow the symlink, so we can exec an updated executable */ + ret = selfpath(buf, sizeof(buf)); + if (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) +{ + prepare_exit(); + /* falls through to generic hang() */ +} + 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) @@ -181,7 +241,7 @@ ssize_t linux_write(int fd, const void *buf, size_t count) return write(fd, buf, count); } -off_t linux_lseek(int fd, off_t offset) +loff_t linux_lseek(int fd, loff_t offset) { return lseek(fd, offset, SEEK_SET); } @@ -207,31 +267,60 @@ int linux_execve(const char * filename, char *const argv[], char *const envp[]) } } +static void linux_watchdog(int signo) +{ + linux_reexec(); + _exit(0); +} + +int linux_watchdog_set_timeout(unsigned int timeout) +{ + static int signal_handler_installed; + + if (!signal_handler_installed) { + struct sigaction sact = { + .sa_flags = SA_NODEFER, .sa_handler = linux_watchdog + }; + + sigemptyset(&sact.sa_mask); + sigaction(SIGALRM, &sact, NULL); + signal_handler_installed = 1; + } + + return alarm(timeout); +} + extern void start_barebox(void); extern void mem_malloc_init(void *start, void *end); -static int add_image(char *str, char *devname_template, int *devname_number) +extern char * strsep_unescaped(char **s, const char *ct); + +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; + struct hf_info *hf = calloc(1, sizeof(struct hf_info)); + char *str, *filename, *devname; char tmp[16]; - int readonly = 0; - struct stat s; char *opt; - int fd, ret; + int ret; if (!hf) return -1; - filename = strtok(str, ","); - while ((opt = strtok(NULL, ","))) { + str = strdup(_str); + + filename = strsep_unescaped(&str, ","); + while ((opt = strsep_unescaped(&str, ","))) { if (!strcmp(opt, "ro")) - readonly = 1; + hf->is_readonly = 1; + if (!strcmp(opt, "cdev")) + hf->is_cdev = 1; + if (!strcmp(opt, "blkdev")) + hf->is_blockdev = 1; } /* parses: "devname=filename" */ - devname = strtok(filename, "="); - filename = strtok(NULL, "="); + devname = strsep_unescaped(&filename, "="); + filename = strsep_unescaped(&filename, "="); if (!filename) { filename = devname; snprintf(tmp, sizeof(tmp), @@ -239,13 +328,86 @@ static int add_image(char *str, char *devname_template, int *devname_number) devname = tmp; } - printf("add %s backed by file %s%s\n", devname, - filename, readonly ? "(ro)" : ""); - - fd = open(filename, readonly ? O_RDONLY : O_RDWR); - hf->fd = fd; hf->filename = filename; + hf->devname = strdup(devname); + ret = barebox_register_filedev(hf); + if (ret) + free(hf); + + return ret; +} + +extern uint8_t stickypage[4096]; + +char *linux_get_stickypage_path(void) +{ + size_t nwritten; + ssize_t ret; + int fd; + + ret = asprintf(&stickypage_path, "%s/barebox/stickypage.%lu", + getenv("XDG_RUNTIME_DIR") ?: "/run", (long)getpid()); + if (ret < 0) + goto err_asprintf; + + ret = mkdir(dirname(stickypage_path), 0755); + if (ret < 0 && errno != EEXIST) { + perror("mkdir"); + goto err_creat; + } + + stickypage_path[strlen(stickypage_path)] = '/'; + + fd = open(stickypage_path, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, 0644); + if (fd < 0) { + if (errno == EEXIST) + return stickypage_path; + + perror("open"); + goto err_creat; + } + + for (nwritten = 0; nwritten < sizeof(stickypage); ) { + ret = write(fd, &stickypage[nwritten], sizeof(stickypage) - nwritten); + if (ret < 0) { + if (errno == EINTR || errno == EAGAIN) + continue; + perror("write"); + goto err_write; + } + + nwritten += ret; + } + + close(fd); + + return stickypage_path; + +err_write: + close(fd); +err_creat: + free(stickypage_path); +err_asprintf: + stickypage_path = NULL; + + return NULL; +} + +int linux_open_hostfile(struct hf_info *hf) +{ + char *buf = NULL; + struct stat s; + int fd = -1; + + printf("add %s %sbacked by file %s%s\n", hf->devname, + hf->filename ? "" : "initially un", hf->filename ?: "", + hf->is_readonly ? "(ro)" : ""); + + if (!hf->filename) + return -ENOENT; + + fd = hf->fd = open(hf->filename, (hf->is_readonly ? O_RDONLY : O_RDWR) | O_CLOEXEC); if (fd < 0) { perror("open"); goto err_out; @@ -256,30 +418,41 @@ static int add_image(char *str, char *devname_template, int *devname_number) goto err_out; } + hf->base = (unsigned long)MAP_FAILED; hf->size = s.st_size; - hf->devname = strdup(devname); if (S_ISBLK(s.st_mode)) { if (ioctl(fd, BLKGETSIZE64, &hf->size) == -1) { perror("ioctl"); goto err_out; } + if (!hf->is_cdev) + hf->is_blockdev = 1; + } + if (hf->size <= SIZE_MAX) { + hf->base = (unsigned long)mmap(NULL, hf->size, + PROT_READ | (hf->is_readonly ? 0 : PROT_WRITE), + MAP_SHARED, fd, 0); + + if (hf->base == (unsigned long)MAP_FAILED) + printf("warning: mmapping %s failed: %s\n", + hf->filename, strerror(errno)); + } else { + printf("warning: %s: contiguous map failed\n", hf->filename); + } + + if (hf->is_blockdev && hf->size % 512 != 0) { + printf("warning: registering %s as block device failed: invalid block size\n", + hf->filename); + return -EINVAL; } - hf->base = (unsigned long)mmap(NULL, hf->size, - PROT_READ | (readonly ? 0 : PROT_WRITE), - MAP_SHARED, fd, 0); - if ((void *)hf->base == MAP_FAILED) - printf("warning: mmapping %s failed: %s\n", filename, strerror(errno)); - ret = barebox_register_filedev(hf); - if (ret) - goto err_out; return 0; err_out: - if (fd > 0) + if (fd >= 0) close(fd); - free(hf); + free(buf); return -1; } @@ -289,7 +462,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; @@ -345,6 +518,10 @@ int main(int argc, char *argv[]) int fdno = 0, envno = 0, option_index = 0; char *aux; +#ifdef CONFIG_ASAN + __sanitizer_set_death_callback(prepare_exit); +#endif + while (1) { option_index = 0; opt = getopt_long(argc, argv, optstring, @@ -382,6 +559,8 @@ int main(int argc, char *argv[]) } } + saved_argv = argv; + ram = malloc(malloc_size); if (!ram) { printf("unable to get malloc space\n"); @@ -416,7 +595,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); @@ -425,7 +604,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); @@ -441,7 +620,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); @@ -449,7 +628,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); |