Index: usr.sbin/bhyve/Makefile =================================================================== --- usr.sbin/bhyve/Makefile +++ usr.sbin/bhyve/Makefile @@ -122,9 +122,6 @@ .if ${MK_BHYVE_SNAPSHOT} != "no" CFLAGS+= -I${SRCTOP}/contrib/libucl/include -# Temporary disable capsicum, until we integrate checkpoint code with it. -#CFLAGS+= -DWITHOUT_CAPSICUM - CFLAGS+= -DBHYVE_SNAPSHOT .endif Index: usr.sbin/bhyve/bhyverun.c =================================================================== --- usr.sbin/bhyve/bhyverun.c +++ usr.sbin/bhyve/bhyverun.c @@ -1126,7 +1126,6 @@ if (reinit) { error = vm_reinit(ctx); if (error) { - fprintf(stderr, "%s: error code is %d\r\n", __func__, error); perror("vm_reinit"); exit(4); } @@ -1230,6 +1229,44 @@ set_config_bool("x86.strictmsr", true); } +#ifndef WITHOUT_CAPSICUM +char *get_ckp_path(char *str) +{ + char *strcopy; + char *aux1, *aux2, *aux3, *aux4, *aux5; + char *path = NULL; + const char delim[2] = ","; + + strcopy = strdup(str); + assert(strcopy != NULL); + + + aux1 = strtok(strcopy, delim); + aux2 = strtok(NULL, delim); + aux3 = strtok(NULL, delim); + if (aux3 != NULL) { + if (strcmp(aux3, "virtio-blk") || + strcmp(aux3, "ahci-hd") || + strcmp(aux3, "ahci")) { + + aux4 = realpath(aux3, NULL); + if (aux4 != NULL) { + aux5 = strrchr(aux4, '/'); + if (aux5 != NULL) { + *aux5 = '\0'; + path = strdup(aux4); + } + free(aux4); + } + } + } + + free(strcopy); + + return path; +} +#endif + int main(int argc, char *argv[]) { @@ -1247,8 +1284,8 @@ restore_file = NULL; #endif - cap_channel_t *capcas; - + cap_channel_t *capcas = NULL; + char *ckp_path = NULL; init_config(); set_defaults(); @@ -1314,8 +1351,13 @@ exit(0); } else if (pci_parse_slot(optarg) != 0) exit(4); - else + else { +#ifndef WITHOUT_CAPSISCUM + if (ckp_path == NULL) + ckp_path = get_ckp_path(optarg); +#endif break; + } case 'S': set_config_bool("memory.wired", true); break; @@ -1552,10 +1594,12 @@ */ setproctitle("%s", vmname); +#ifndef WITHOUT_CAPSICUM /* Open capability to Casper. */ capcas = cap_init(); if (capcas == NULL) errx(EX_OSERR, "cap_init() failed"); +#endif #ifdef BHYVE_SNAPSHOT if (restore_file != NULL) @@ -1567,7 +1611,7 @@ /* * checkpointing thread for communication with bhyvectl */ - if (init_checkpoint_thread(ctx, capcas) < 0) + if (init_checkpoint_thread(ctx, ckp_path, capcas) < 0) printf("Failed to start checkpoint thread!\r\n"); if (restore_file != NULL) @@ -1575,6 +1619,7 @@ #endif #ifndef WITHOUT_CAPSICUM + free(ckp_path); caph_cache_catpages(); if (caph_limit_stdout() == -1 || caph_limit_stderr() == -1) Index: usr.sbin/bhyve/snapshot.h =================================================================== --- usr.sbin/bhyve/snapshot.h +++ usr.sbin/bhyve/snapshot.h @@ -108,7 +108,7 @@ int get_checkpoint_msg(int conn_fd, struct vmctx *ctx); void *checkpoint_thread(void *param); void init_snapshot(void); -int init_checkpoint_thread(struct vmctx *ctx, cap_channel_t *chn); +int init_checkpoint_thread(struct vmctx *ctx, char *ckp_path, cap_channel_t *chn); int load_restore_file(const char *filename, struct restore_state *rstate); Index: usr.sbin/bhyve/snapshot.c =================================================================== --- usr.sbin/bhyve/snapshot.c +++ usr.sbin/bhyve/snapshot.c @@ -171,7 +171,7 @@ static pthread_cond_t vcpus_idle, vcpus_can_run; static bool checkpoint_active; -static int cdir_fd = -1; +static int cdir_fd = AT_FDCWD; /* * TODO: Harden this function and all of its callers since 'base_str' is a user * provided string. @@ -246,6 +246,15 @@ errx(EX_OSERR, "Unable to apply rights for sandbox"); } +static void +limit_metadata_socket(int s) +{ + cap_rights_t rights; + + cap_rights_init(&rights, CAP_FSTAT, CAP_MMAP_R, CAP_READ); + if (caph_rights_limit(s, &rights) == -1) + errx(EX_OSERR, "Unable to apply rights for sandbox"); +} #endif static int @@ -333,6 +342,7 @@ { const ucl_object_t *obj; struct ucl_parser *parser; + int md_fd = -1; int err; parser = ucl_parser_new(UCL_PARSER_DEFAULT); @@ -341,7 +351,13 @@ goto err_load_metadata; } - err = ucl_parser_add_file(parser, filename); + md_fd = open(filename, O_RDONLY); + +#ifndef WITHOUT_CAPSICUM + limit_metadata_socket(md_fd); +#endif + + err = ucl_parser_add_fd(parser, md_fd); if (err == 0) { fprintf(stderr, "Failed to parse metadata file: '%s'\n", filename); @@ -362,6 +378,8 @@ return (0); err_load_metadata: + if (md_fd > 0) + close(md_fd); if (parser != NULL) ucl_parser_free(parser); return (err); @@ -857,6 +875,7 @@ fprintf(stderr, "%s: Could not %s lowmem\r\n", __func__, op_wr ? "write" : "read"); totalmem = 0; + goto done; } if (highmem == 0) @@ -1406,6 +1425,7 @@ FILE *meta_file = NULL; char vmname[MAX_VMNAME]; + kdata_filename = strcat_extension(checkpoint_file, ".kern"); if (kdata_filename == NULL) { fprintf(stderr, "Failed to construct kernel data filename.\n"); @@ -1456,8 +1476,11 @@ fprintf(stderr, "Could not pause devices\r\n"); error = ret; goto done; +#ifndef WITHOUT_CAPSICUM if (cdir_fd > 0) - close(cdir_fd);} + close(cdir_fd); +#endif + } memsz = vm_snapshot_mem(ctx, fd_checkpoint, 0, true); if (memsz == 0) { @@ -1522,8 +1545,10 @@ fclose(meta_file); if (kdata_fd > 0) close(kdata_fd); +#ifndef WITHOUT_CAPSICUM if (cdir_fd > 0) close(cdir_fd); +#endif return (error); } @@ -1627,7 +1652,7 @@ * Create the listening socket for IPC with bhyvectl */ int -init_checkpoint_thread(struct vmctx *ctx, cap_channel_t *chn) +init_checkpoint_thread(struct vmctx *ctx, char *ckp_path, cap_channel_t *chn) { struct checkpoint_thread_info *checkpoint_info = NULL; struct sockaddr_un addr; @@ -1635,7 +1660,6 @@ pthread_t checkpoint_pthread; char vmname_buf[MAX_VMNAME]; int ret, err = 0; - char *cdir_name; memset(&addr, 0, sizeof(addr)); @@ -1646,18 +1670,17 @@ goto fail; } - cdir_name = getcwd(NULL, 0); - cdir_fd = open(cdir_name, O_RDONLY | O_DIRECTORY); - if (cdir_fd < 0) { - perror("Failed to open working directory."); - err = -1; - goto fail; + if (ckp_path != NULL) { + cdir_fd = open(ckp_path, O_RDONLY | O_DIRECTORY); + if (cdir_fd < 0) { + perror("Failed to open working directory."); + err = -1; + goto fail; + } + limit_control_socket(socket_fd); + limit_file_operations(); } - free(cdir_name); -#ifndef WITHOUT_CAPSICUM - limit_control_socket(socket_fd); - limit_file_operations(); -#endif + addr.sun_family = AF_UNIX; err = vm_get_name(ctx, vmname_buf, MAX_VMNAME - 1); @@ -1671,7 +1694,6 @@ addr.sun_len = SUN_LEN(&addr); unlink(addr.sun_path); - if (bind(socket_fd, (struct sockaddr *)&addr, addr.sun_len) != 0) { EPRINTLN("Failed to bind socket \"%s\": %s\n", addr.sun_path, strerror(errno));