int __cdecl main(int argc, char *argv[]) { int ID; char *image; printf("GhostTool version %s\n", GHOST_VERSION); if (argc < 3) { print_help(); return 0; } ID = (int)argv[2][0] - 0x30; if (ID < 0 || ID > 9) { printf("Error: ID must be between 0 and 9\n"); return -1; } if (!strcmp(argv[1], "mount")) { /* we are going to mount an image */ mount_image(ID); } else if (!strcmp(argv[1], "umount")) { /* we have to umount an image */ umount_image(ID); } else { print_help(); } return 0; }
//int build_glance_image_policy(char * uuid,void ** boot_pcrs, void ** running_pcrs,int devno,void ** policy) int build_glance_image_policy(char * uuid,void ** boot_pcrs, void ** running_pcrs,void ** policy) { char cmd[512]; char desc[512]; char namebuf[512]; char digest[DIGEST_SIZE]; struct policy_file * pfile; struct vm_policy * image_policy; void * struct_template; int ret; void * sec_respool; void * sec_res; struct tcm_pcr_set * image_boot_pcrs; struct tcm_pcr_set * image_running_pcrs; sprintf(namebuf,"/var/lib/glance/images/%s",uuid); char dev[DIGEST_SIZE*2]; char part_dev[DIGEST_SIZE*2]; char mountpoint[DIGEST_SIZE*2]; /* sprintf(dev,"/dev/nbd%d",devno); sprintf(mountpoint,"./mnt%d",devno); */ sec_respool=find_sec_respool("image_mntpoint"); ret=sec_respool_getres(sec_respool,&sec_res); sec_resource_getvalue(sec_res,"dev_name",dev); sec_resource_getvalue(sec_res,"mount_path",mountpoint); sprintf(cmd,"mkdir %s",mountpoint); system(cmd); mount_image(namebuf,dev,mountpoint); ret=build_image_boot_pcrs(dev,mountpoint,uuid,&image_boot_pcrs); ret=build_image_running_pcrs(dev,mountpoint,uuid,&image_running_pcrs); ret=build_entity_policy(uuid,NULL,image_boot_pcrs,image_running_pcrs,uuid,&image_policy); if(image_policy!=NULL) AddPolicy(image_policy,"IMGP"); umount_image(dev,mountpoint); sprintf(cmd,"rmdir %s",mountpoint); system(cmd); ExportPolicy("IMGP"); *boot_pcrs=image_boot_pcrs; *running_pcrs=image_running_pcrs; *policy=image_policy; return 0; }
//int build_glance_image_pcrlib(char * uuid,int devno,char * image_desc,int trust_level) int build_glance_image_pcrlib(char * uuid,char * image_desc,int trust_level) { char cmd[512]; char desc[512]; char namebuf[512]; char digest[DIGEST_SIZE]; struct policy_file * pfile; void * struct_template; int ret; void * sec_respool; void * sec_res; sprintf(namebuf,"/var/lib/glance/images/%s",uuid); char dev[DIGEST_SIZE*2]; char part_dev[DIGEST_SIZE*2]; char mountpoint[DIGEST_SIZE*2]; /* sprintf(dev,"/dev/nbd%d",devno); sprintf(mountpoint,"./mnt%d",devno); */ sec_respool=find_sec_respool("image_mntpoint"); ret=sec_respool_getres(sec_respool,&sec_res); sec_resource_getvalue(sec_res,"dev_name",dev); sec_resource_getvalue(sec_res,"mount_path",mountpoint); sprintf(cmd,"mkdir %s",mountpoint); system(cmd); mount_image(namebuf,dev,mountpoint); ret=build_image_pcrlib(dev,mountpoint,image_desc,trust_level); umount_image(dev,mountpoint); sprintf(cmd,"rmdir %s",mountpoint); system(cmd); return 0; }
int main(int argc, char *argv[]) { mrom_set_log_tag("fw_mounter"); struct fstab *f = fstab_load(FW_MOUNTER_FSTAB, 0); if(!f) { ERROR("Failed to load %s\n", FW_MOUNTER_FSTAB); return -1; } struct fstab_part *fw_part = fstab_find_first_by_path(f, "/firmware"); if(!fw_part) { ERROR("Unable to find partition /firmware in %s!\n", FW_MOUNTER_FSTAB); return -1; } ERROR("Mounting %s to %s\n", fw_part->device, fw_part->path); return mount_image(fw_part->device, fw_part->path, fw_part->type, fw_part->mountflags, fw_part->options); }
int ploop_create_temporary_snapshot(struct ploop_disk_images_data *di, struct ploop_tsnapshot_param *param, int *holder_fd) { int ret; struct ploop_mount_param mount_param = { .ro = 1, }; char component_name[PLOOP_COOKIE_SIZE]; if (di == NULL || param == NULL) return SYSEXIT_PARAM; if (param->guid == NULL) { ploop_err(0, "Snapshot guid is not specified"); return SYSEXIT_PARAM; } if (param->component_name == NULL) { ploop_err(0, "Component name is not specified"); return SYSEXIT_PARAM; } if (ploop_lock_dd(di)) return SYSEXIT_LOCK; ret = do_create_snapshot(di, param->guid, param->snap_dir, 1); if (ret) goto err_unlock; /* FIXME: should be processed from 'struct ploop_mount_param' only ?? */ char *t = di->runtime->component_name; snprintf(component_name, sizeof(component_name), "%s%s", holder_fd == NULL ? TSNAPSHOT_MOUNT_LOCK_MARK : "", param->component_name); di->runtime->component_name = component_name; mount_param.guid = param->guid; mount_param.target = param->target; ret = mount_image(di, &mount_param); di->runtime->component_name = t; if (ret) goto err_merge; strncpy(param->device, mount_param.device, sizeof(param->device)); param->device[sizeof(param->device) - 1] = '\0'; if (holder_fd != NULL) { ret = open_snap_holder(param->device, holder_fd); if (ret) goto err; } ploop_unlock_dd(di); return 0; err: ploop_umount(mount_param.device, di); err_merge: ploop_merge_snapshot_by_guid(di, di->top_guid, NULL); err_unlock: ploop_unlock_dd(di); return ret; } int is_device_inuse(const char *dev) { int count; char fname[PATH_MAX]; char cookie[PLOOP_COOKIE_SIZE] = ""; if (ploop_get_attr(dev, "open_count", &count)) return 1; /* detect if snapshot locked by ploop mount */ snprintf(fname, sizeof(fname), "/sys/block/%s/pstate/cookie", memcmp(dev, "/dev/", 5) == 0 ? dev + 5 : dev); if (read_line_quiet(fname, cookie, sizeof(cookie))) return 1; if (!strncmp(cookie, TSNAPSHOT_MOUNT_LOCK_MARK, sizeof(TSNAPSHOT_MOUNT_LOCK_MARK)-1)) return 1; /* snap holder + mount */ if (count >= 2) return 1; /* if there single reference we should detect is holder is alive */ if (count == 1 && ploop_get_mnt_by_dev(dev, fname, sizeof(fname)) != 0) return 1; return 0; }
int main(int argc, char ** argv) { char *containerimage; char *mountpoint; char *bootstrap_script; char *defintion_script; char *loop_dev; int retval = 0; int containerimage_fd; int loop_fd; uid_t uid = geteuid(); if ( uid != 0 ) { fprintf(stderr, "ABORT: Calling user must be root\n"); return(1); } if ( argv[1] == NULL || argv[2] == NULL ) { fprintf(stderr, "USAGE: %s [singularity container image] [bootstrap definition]\n", argv[0]); return(1); } containerimage = strdup(argv[1]); defintion_script = strdup(argv[2]); bootstrap_script = strjoin(LIBEXECDIR, "/singularity/bootstrap.sh"); mountpoint = getenv("SINGULARITY_BUILD_ROOT"); if ( is_file(containerimage) < 0 ) { fprintf(stderr, "ABORT: Container image not found: %s\n", containerimage); return(1); } if ( is_dir(mountpoint) < 0 ) { fprintf(stderr, "ABORT: Mount point must be a directory: %s\n", mountpoint); return(1); } if ( unshare(CLONE_NEWNS) < 0 ) { fprintf(stderr, "ABORT: Could not virtulize mount namespace\n"); return(255); } if ( mount(NULL, "/", NULL, MS_PRIVATE|MS_REC, NULL) < 0 ) { fprintf(stderr, "ABORT: Could not make mountspaces private: %s\n", strerror(errno)); return(255); } if ( ( containerimage_fd = open(containerimage, O_RDWR) ) < 0 ) { fprintf(stderr, "ERROR: Could not open image %s: %s\n", containerimage, strerror(errno)); return(255); } loop_dev = obtain_loop_dev(); if ( ( loop_fd = open(loop_dev, O_RDWR) ) < 0 ) { fprintf(stderr, "ERROR: Failed to open %s: %s\n", loop_dev, strerror(errno)); return(-1); } if ( associate_loop(containerimage_fd, loop_fd) < 0 ) { fprintf(stderr, "ERROR: Could not associate %s to loop device %s\n", containerimage, loop_dev); return(255); } if ( mount_image(loop_dev, mountpoint, 1) < 0 ) { fprintf(stderr, "ABORT: exiting...\n"); return(255); } child_pid = fork(); if ( child_pid == 0 ) { char *exec[4]; exec[0] = strdup("/bin/bash"); exec[1] = strdup(bootstrap_script); exec[2] = strdup(defintion_script); exec[3] = NULL; if ( execv("/bin/bash", exec) != 0 ) { fprintf(stderr, "ABORT: exec of bootstrap failed: %s\n", strerror(errno)); } } else if ( child_pid > 0 ) { int tmpstatus; signal(SIGINT, sighandler); signal(SIGKILL, sighandler); signal(SIGQUIT, sighandler); waitpid(child_pid, &tmpstatus, 0); retval = WEXITSTATUS(tmpstatus); } else { fprintf(stderr, "ABORT: Could not fork child process\n"); retval++; } return(retval); }
int main(int argc, char ** argv) { FILE *loop_fp; FILE *containerimage_fp; char *containerimage; char *mountpoint; char *loop_dev; int retval = 0; uid_t uid = geteuid(); signal(SIGINT, sighandler); signal(SIGKILL, sighandler); signal(SIGQUIT, sighandler); if ( uid != 0 ) { message(ERROR, "Calling user must be root\n"); ABORT(1); } if ( argv[1] == NULL || argv[2] == NULL ) { fprintf(stderr, "USAGE: %s [singularity container image] [mount point] (shell container args)\n", argv[0]); return(1); } containerimage = strdup(argv[1]); mountpoint = strdup(argv[2]); if ( is_file(containerimage) < 0 ) { message(ERROR, "Container image not found: %s\n", containerimage); ABORT(1); } if ( is_dir(mountpoint) < 0 ) { message(ERROR, "Mount point must be a directory: %s\n", mountpoint); ABORT(1); } message(DEBUG, "Opening container image: %s\n", containerimage); if ( ( containerimage_fp = fopen(containerimage, "r+") ) < 0 ) { // Flawfinder: ignore message(ERROR, "Could not open image %s: %s\n", containerimage, strerror(errno)); ABORT(255); } message(DEBUG, "Binding container to loop interface\n"); if ( ( loop_fp = loop_bind(containerimage_fp, &loop_dev, 1)) == NULL ) { message(ERROR, "Could not bind image to loop!\n"); ABORT(255); } message(DEBUG, "Forking namespace child\n"); namespace_fork_pid = fork(); if ( namespace_fork_pid == 0 ) { if ( unshare(CLONE_NEWNS) < 0 ) { message(ERROR, "Could not virtualize mount namespace: %s\n", strerror(errno)); ABORT(255); } if ( mount(NULL, "/", NULL, MS_PRIVATE|MS_REC, NULL) < 0 ) { message(ERROR, "Could not make mountspaces private: %s\n", strerror(errno)); ABORT(255); } if ( mount_image(loop_dev, mountpoint, 1) < 0 ) { message(ERROR, "Failed mounting image...\n"); ABORT(255); } message(DEBUG, "Forking exec child\n"); exec_fork_pid = fork(); if ( exec_fork_pid == 0 ) { argv[2] = strdup("/bin/bash"); if ( execv("/bin/bash", &argv[2]) != 0 ) { // Flawfinder: ignore (exec* is necessary) message(ERROR, "Exec of /bin/bash failed: %s\n", strerror(errno)); } // We should never get here, so if we do, make it an error return(-1); } else if ( exec_fork_pid > 0 ) { int tmpstatus; strncpy(argv[0], "Singularity: exec", strlen(argv[0])); // Flawfinder: ignore message(DEBUG, "Waiting for exec child to return\n"); waitpid(exec_fork_pid, &tmpstatus, 0); retval = WEXITSTATUS(tmpstatus); message(DEBUG, "Exec child returned (RETVAL=%d)\n", retval); return(retval); } else { fprintf(stderr, "ABORT: Could not exec child process: %s\n", strerror(errno)); retval++; } } else if ( namespace_fork_pid > 0 ) { int tmpstatus; strncpy(argv[0], "Singularity: namespace", strlen(argv[0])); // Flawfinder: ignore message(DEBUG, "Waiting for namespace child to return\n"); waitpid(namespace_fork_pid, &tmpstatus, 0); retval = WEXITSTATUS(tmpstatus); message(DEBUG, "Namespace child returned (RETVAL=%d)\n", retval); } else { fprintf(stderr, "ABORT: Could not fork management process: %s\n", strerror(errno)); return(255); } return(retval); }
int main(int argc, char ** argv) { FILE *containerimage_fp; FILE *loop_fp; FILE *config_fp; char *containerimage; char *containername; char *containerpath; char *username; char *command; char *tmpdir; char *loop_dev_lock; char *loop_dev_cache; char *loop_dev = 0; char *config_path; char *tmp_config_string; char cwd[PATH_MAX]; int cwd_fd; int tmpdirlock_fd; int containerimage_fd; int loop_dev_lock_fd; int gid_list_count; int retval = 0; uid_t uid; gid_t gid; gid_t *gid_list; pid_t namespace_fork_pid = 0; struct passwd *pw; //****************************************************************************// // Init //****************************************************************************// signal(SIGINT, sighandler); signal(SIGKILL, sighandler); signal(SIGQUIT, sighandler); openlog("Singularity", LOG_CONS | LOG_NDELAY, LOG_LOCAL0); // Get all user/group info uid = getuid(); gid = getgid(); gid_list_count = getgroups(0, NULL); gid_list = (gid_t *) malloc(sizeof(gid_t) * gid_list_count); if ( getgroups(gid_list_count, gid_list) < 0 ) { fprintf(stderr, "ABORT: Could not obtain current supplementary group list: %s\n", strerror(errno)); return(255); } pw = getpwuid(uid); // Check to make sure we are installed correctly if ( seteuid(0) < 0 ) { fprintf(stderr, "ABORT: Check installation, must be performed by root.\n"); return(255); } // Lets start off as the calling UID if ( seteuid(uid) < 0 ) { fprintf(stderr, "ABORT: Could not set effective uid to %d: %s\n", uid, strerror(errno)); return(255); } if ( setegid(gid) < 0 ) { fprintf(stderr, "ABORT: Could not set effective gid to %d: %s\n", gid, strerror(errno)); return(255); } username = pw->pw_name; containerimage = getenv("SINGULARITY_IMAGE"); command = getenv("SINGULARITY_COMMAND"); unsetenv("SINGULARITY_COMMAND"); unsetenv("SINGULARITY_EXEC"); config_path = (char *) malloc(strlen(SYSCONFDIR) + 30); snprintf(config_path, strlen(SYSCONFDIR) + 30, "%s/singularity/singularity.conf", SYSCONFDIR); // Figure out where we start if ( (cwd_fd = open(".", O_RDONLY)) < 0 ) { fprintf(stderr, "ABORT: Could not open cwd fd (%s)!\n", strerror(errno)); return(1); } if ( getcwd(cwd, PATH_MAX) == NULL ) { fprintf(stderr, "Could not obtain current directory path: %s\n", strerror(errno)); return(1); } if ( containerimage == NULL ) { fprintf(stderr, "ABORT: SINGULARITY_IMAGE undefined!\n"); return(1); } if ( is_file(containerimage) != 0 ) { fprintf(stderr, "ABORT: Container image path is invalid: %s\n", containerimage); return(1); } if ( is_file(config_path) != 0 ) { fprintf(stderr, "ABORT: Configuration file not found: %s\n", config_path); return(255); } if ( is_owner(config_path, 0) != 0 ) { fprintf(stderr, "ABORT: Configuration file is not owned by root: %s\n", config_path); return(255); } // TODO: Offer option to only run containers owned by root (so root can approve // containers) if ( uid == 0 && is_owner(containerimage, 0) < 0 ) { fprintf(stderr, "ABORT: Root should only run containers that root owns!\n"); return(1); } containername = basename(strdup(containerimage)); tmpdir = strjoin("/tmp/.singularity-", file_id(containerimage)); loop_dev_lock = joinpath(tmpdir, "loop_dev.lock"); loop_dev_cache = joinpath(tmpdir, "loop_dev"); containerpath = (char *) malloc(strlen(tmpdir) + 5); snprintf(containerpath, strlen(tmpdir) + 5, "%s/mnt", tmpdir); syslog(LOG_NOTICE, "User=%s[%d], Command=%s, Container=%s, CWD=%s, Arg1=%s", username, uid, command, containerimage, cwd, argv[1]); //****************************************************************************// // Setup //****************************************************************************// if ( ( config_fp = fopen(config_path, "r") ) == NULL ) { fprintf(stderr, "ERROR: Could not open config file %s: %s\n", config_path, strerror(errno)); return(255); } if ( getenv("SINGULARITY_WRITABLE") == NULL ) { if ( ( containerimage_fp = fopen(containerimage, "r") ) == NULL ) { fprintf(stderr, "ERROR: Could not open image read only %s: %s\n", containerimage, strerror(errno)); return(255); } containerimage_fd = fileno(containerimage_fp); if ( flock(containerimage_fd, LOCK_SH | LOCK_NB) < 0 ) { fprintf(stderr, "ABORT: Image is locked by another process\n"); return(5); } } else { if ( ( containerimage_fp = fopen(containerimage, "r+") ) == NULL ) { fprintf(stderr, "ERROR: Could not open image read/write %s: %s\n", containerimage, strerror(errno)); return(255); } containerimage_fd = fileno(containerimage_fp); if ( flock(containerimage_fd, LOCK_EX | LOCK_NB) < 0 ) { fprintf(stderr, "ABORT: Image is locked by another process\n"); return(5); } } //****************************************************************************// // We are now running with escalated privileges until we exec //****************************************************************************// if ( seteuid(0) < 0 ) { fprintf(stderr, "ABORT: Could not escalate effective user privileges %s\n", strerror(errno)); return(255); } if ( setegid(0) < 0 ) { fprintf(stderr, "ABORT: Could not escalate effective group privileges: %s\n", strerror(errno)); return(255); } if ( s_mkpath(tmpdir, 0755) < 0 ) { fprintf(stderr, "ABORT: Could not create temporary directory %s: %s\n", tmpdir, strerror(errno)); return(255); } if ( is_owner(tmpdir, 0) < 0 ) { fprintf(stderr, "ABORT: Container working directory has wrong ownership: %s\n", tmpdir); syslog(LOG_ERR, "Container working directory has wrong ownership: %s", tmpdir); return(255); } tmpdirlock_fd = open(tmpdir, O_RDONLY); if ( tmpdirlock_fd < 0 ) { fprintf(stderr, "ERROR: Could not obtain file descriptor on %s: %s\n", tmpdir, strerror(errno)); return(255); } if ( flock(tmpdirlock_fd, LOCK_SH | LOCK_NB) < 0 ) { fprintf(stderr, "ERROR: Could not obtain shared lock on %s: %s\n", tmpdir, strerror(errno)); return(255); } if ( ( loop_dev_lock_fd = open(loop_dev_lock, O_CREAT | O_RDWR, 0644) ) < 0 ) { fprintf(stderr, "ERROR: Could not open loop_dev_lock %s: %s\n", loop_dev_lock, strerror(errno)); return(255); } if ( s_mkpath(containerpath, 0755) < 0 ) { fprintf(stderr, "ABORT: Could not create directory %s: %s\n", containerpath, strerror(errno)); return(255); } if ( is_owner(containerpath, 0) < 0 ) { fprintf(stderr, "ABORT: Container directory is not root owned: %s\n", containerpath); syslog(LOG_ERR, "Container directory has wrong ownership: %s", tmpdir); return(255); } if ( flock(loop_dev_lock_fd, LOCK_EX | LOCK_NB) == 0 ) { loop_dev = obtain_loop_dev(); if ( ( loop_fp = fopen(loop_dev, "r+") ) < 0 ) { fprintf(stderr, "ERROR: Failed to open loop device %s: %s\n", loop_dev, strerror(errno)); syslog(LOG_ERR, "Failed to open loop device %s: %s", loop_dev, strerror(errno)); return(255); } if ( associate_loop(containerimage_fp, loop_fp, 1) < 0 ) { fprintf(stderr, "ERROR: Could not associate %s to loop device %s\n", containerimage, loop_dev); syslog(LOG_ERR, "Failed to associate %s to loop device %s", containerimage, loop_dev); return(255); } if ( fileput(loop_dev_cache, loop_dev) < 0 ) { fprintf(stderr, "ERROR: Could not write to loop_dev_cache %s: %s\n", loop_dev_cache, strerror(errno)); return(255); } flock(loop_dev_lock_fd, LOCK_SH | LOCK_NB); } else { flock(loop_dev_lock_fd, LOCK_SH); if ( ( loop_dev = filecat(loop_dev_cache) ) == NULL ) { fprintf(stderr, "ERROR: Could not retrieve loop_dev_cache from %s\n", loop_dev_cache); return(255); } if ( ( loop_fp = fopen(loop_dev, "r") ) < 0 ) { fprintf(stderr, "ERROR: Failed to open loop device %s: %s\n", loop_dev, strerror(errno)); return(255); } } //****************************************************************************// // Management fork //****************************************************************************// namespace_fork_pid = fork(); if ( namespace_fork_pid == 0 ) { //****************************************************************************// // Setup namespaces //****************************************************************************// if ( unshare(CLONE_NEWNS) < 0 ) { fprintf(stderr, "ABORT: Could not virtualize mount namespace: %s\n", strerror(errno)); return(255); } // Privatize the mount namespaces (thank you for the pointer Doug Jacobsen!) if ( mount(NULL, "/", NULL, MS_PRIVATE|MS_REC, NULL) < 0 ) { // I am not sure if this error needs to be caught, maybe it will fail // on older kernels? If so, we can fix then. fprintf(stderr, "ABORT: Could not make mountspaces private: %s\n", strerror(errno)); return(255); } #ifdef NS_CLONE_NEWPID if ( getenv("SINGULARITY_NO_NAMESPACE_PID") == NULL ) { unsetenv("SINGULARITY_NO_NAMESPACE_PID"); if ( unshare(CLONE_NEWPID) < 0 ) { fprintf(stderr, "ABORT: Could not virtualize PID namespace: %s\n", strerror(errno)); return(255); } } #else #ifdef NS_CLONE_PID // This is for older legacy CLONE_PID if ( getenv("SINGULARITY_NO_NAMESPACE_PID") == NULL ) { unsetenv("SINGULARITY_NO_NAMESPACE_PID"); if ( unshare(CLONE_PID) < 0 ) { fprintf(stderr, "ABORT: Could not virtualize PID namespace: %s\n", strerror(errno)); return(255); } } #endif #endif #ifdef NS_CLONE_FS if ( getenv("SINGULARITY_NO_NAMESPACE_FS") == NULL ) { unsetenv("SINGULARITY_NO_NAMESPACE_FS"); if ( unshare(CLONE_FS) < 0 ) { fprintf(stderr, "ABORT: Could not virtualize file system namespace: %s\n", strerror(errno)); return(255); } } #endif #ifdef NS_CLONE_FILES if ( getenv("SINGULARITY_NO_NAMESPACE_FILES") == NULL ) { unsetenv("SINGULARITY_NO_NAMESPACE_FILES"); if ( unshare(CLONE_FILES) < 0 ) { fprintf(stderr, "ABORT: Could not virtualize file descriptor namespace: %s\n", strerror(errno)); return(255); } } #endif //****************************************************************************// // Mount image //****************************************************************************// if ( getenv("SINGULARITY_WRITABLE") == NULL ) { unsetenv("SINGULARITY_WRITABLE"); if ( mount_image(loop_dev, containerpath, 0) < 0 ) { fprintf(stderr, "ABORT: exiting...\n"); return(255); } } else { if ( mount_image(loop_dev, containerpath, 1) < 0 ) { fprintf(stderr, "ABORT: exiting...\n"); return(255); } } //****************************************************************************// // Check image //****************************************************************************// if ( is_exec(joinpath(containerpath, "/bin/sh")) < 0 ) { fprintf(stderr, "ERROR: Container image does not have a valid /bin/sh\n"); return(1); } //****************************************************************************// // Bind mounts //****************************************************************************// if ( getenv("SINGULARITY_CONTAIN") == NULL ) { unsetenv("SINGULARITY_CONTAIN"); rewind(config_fp); while ( ( tmp_config_string = config_get_key_value(config_fp, "bind path") ) != NULL ) { if ( ( is_file(tmp_config_string) != 0 ) && ( is_dir(tmp_config_string) != 0 ) ) { fprintf(stderr, "ERROR: Non existant bind source path: '%s'\n", tmp_config_string); continue; } if ( ( is_file(joinpath(containerpath, tmp_config_string)) != 0 ) && ( is_dir(joinpath(containerpath, tmp_config_string)) != 0 ) ) { fprintf(stderr, "WARNING: Non existant bind container destination path: '%s'\n", tmp_config_string); continue; } if ( mount_bind(tmp_config_string, joinpath(containerpath, tmp_config_string), 0) < 0 ) { fprintf(stderr, "ABORTING!\n"); return(255); } } if (is_file(joinpath(containerpath, "/etc/nsswitch.conf")) == 0 ) { if ( is_file(joinpath(SYSCONFDIR, "/singularity/default-nsswitch.conf")) == 0 ) { if ( mount_bind(joinpath(SYSCONFDIR, "/singularity/default-nsswitch.conf"), joinpath(containerpath, "/etc/nsswitch.conf"), 0) != 0 ) { fprintf(stderr, "ABORT: Could not bind /etc/nsswitch.conf\n"); return(255); } } else { fprintf(stderr, "WARNING: Template /etc/nsswitch.conf does not exist: %s\n", joinpath(SYSCONFDIR, "/singularity/default-nsswitch.conf")); } } if ( uid != 0 ) { // If we are root, no need to mess with passwd or group if (is_file(joinpath(containerpath, "/etc/passwd")) == 0 ) { if ( is_file(joinpath(tmpdir, "/passwd")) < 0 ) { if ( build_passwd(joinpath(containerpath, "/etc/passwd"), joinpath(tmpdir, "/passwd")) < 0 ) { fprintf(stderr, "ABORT: Failed creating template password file\n"); return(255); } } if ( mount_bind(joinpath(tmpdir, "/passwd"), joinpath(containerpath, "/etc/passwd"), 0) < 0 ) { fprintf(stderr, "ABORT: Could not bind /etc/passwd\n"); return(255); } } if (is_file(joinpath(containerpath, "/etc/group")) == 0 ) { if ( is_file(joinpath(tmpdir, "/group")) < 0 ) { if ( build_group(joinpath(containerpath, "/etc/group"), joinpath(tmpdir, "/group")) < 0 ) { fprintf(stderr, "ABORT: Failed creating template group file\n"); return(255); } } if ( mount_bind(joinpath(tmpdir, "/group"), joinpath(containerpath, "/etc/group"), 0) < 0 ) { fprintf(stderr, "ABORT: Could not bind /etc/group\n"); return(255); } } } } //****************************************************************************// // Fork child in new namespaces //****************************************************************************// exec_fork_pid = fork(); if ( exec_fork_pid == 0 ) { //****************************************************************************// // Enter the file system //****************************************************************************// if ( chroot(containerpath) < 0 ) { fprintf(stderr, "ABORT: failed enter CONTAINERIMAGE: %s\n", containerpath); return(255); } if ( chdir("/") < 0 ) { fprintf(stderr, "ABORT: Could not chdir after chroot to /: %s\n", strerror(errno)); return(1); } //****************************************************************************// // Setup real mounts within the container //****************************************************************************// rewind(config_fp); if ( config_get_key_bool(config_fp, "mount proc", 1) > 0 ) { if ( is_dir("/proc") == 0 ) { if ( mount("proc", "/proc", "proc", 0, NULL) < 0 ) { fprintf(stderr, "ABORT: Could not mount /proc: %s\n", strerror(errno)); return(255); } } } rewind(config_fp); if ( config_get_key_bool(config_fp, "mount sys", 1) > 0 ) { if ( is_dir("/sys") == 0 ) { if ( mount("sysfs", "/sys", "sysfs", 0, NULL) < 0 ) { fprintf(stderr, "ABORT: Could not mount /sys: %s\n", strerror(errno)); return(255); } } } //****************************************************************************// // Drop all privileges for good //****************************************************************************// if ( setgroups(gid_list_count, gid_list) < 0 ) { fprintf(stderr, "ABOFT: Could not reset supplementary group list: %s\n", strerror(errno)); return(255); } if ( setregid(gid, gid) < 0 ) { fprintf(stderr, "ABORT: Could not dump real and effective group privileges: %s\n", strerror(errno)); return(255); } if ( setreuid(uid, uid) < 0 ) { fprintf(stderr, "ABORT: Could not dump real and effective user privileges: %s\n", strerror(errno)); return(255); } //****************************************************************************// // Setup final environment //****************************************************************************// // After this, we exist only within the container... Let's make it known! if ( setenv("SINGULARITY_CONTAINER", "true", 0) != 0 ) { fprintf(stderr, "ABORT: Could not set SINGULARITY_CONTAINER to 'true'\n"); return(1); } if ( is_dir(cwd) == 0 ) { if ( chdir(cwd) < 0 ) { fprintf(stderr, "ABORT: Could not chdir to: %s: %s\n", cwd, strerror(errno)); return(1); } } else { if ( fchdir(cwd_fd) < 0 ) { fprintf(stderr, "ABORT: Could not fchdir to cwd: %s\n", strerror(errno)); return(1); } } //****************************************************************************// // Execv to container process //****************************************************************************// if ( command == NULL ) { fprintf(stderr, "No command specified, launching 'shell'\n"); command = strdup("shell"); } if ( strcmp(command, "run") == 0 ) { if ( is_exec("/singularity") == 0 ) { argv[0] = strdup("/singularity"); if ( execv("/singularity", argv) != 0 ) { fprintf(stderr, "ABORT: exec of /bin/sh failed: %s\n", strerror(errno)); } } else { fprintf(stderr, "No Singularity runscript found, launching 'shell'\n"); command = strdup("shell"); } } if ( strcmp(command, "exec") == 0 ) { if ( argc <= 1 ) { fprintf(stderr, "ABORT: Exec requires a command to run\n"); return(1); } if ( execvp(argv[1], &argv[1]) != 0 ) { fprintf(stderr, "ABORT: execvp of '%s' failed: %s\n", argv[1], strerror(errno)); return(1); } } if ( strcmp(command, "shell") == 0 ) { char *prompt; prompt = (char *) malloc(strlen(containername) + 16); snprintf(prompt, strlen(containerimage) + 16, "Singularity/%s> ", containername); setenv("PS1", prompt, 1); if ( is_exec("/bin/bash") == 0 ) { char *args[argc+2]; int i; args[0] = strdup("/bin/bash"); args[1] = strdup("--norc"); args[2] = strdup("--noprofile"); for(i=1; i<=argc; i++) { args[i+2] = argv[i]; } if ( execv("/bin/bash", args) != 0 ) { fprintf(stderr, "ABORT: exec of /bin/bash failed: %s\n", strerror(errno)); } } else { argv[0] = strdup("/bin/sh"); if ( execv("/bin/sh", argv) != 0 ) { fprintf(stderr, "ABORT: exec of /bin/sh failed: %s\n", strerror(errno)); } } } // If we get here... we fail on bad command fprintf(stderr, "ABORT: Unrecognized Singularity command: %s\n", command); return(1); //****************************************************************************// // Outer child waits for inner child //****************************************************************************// } else if ( exec_fork_pid > 0 ) { int tmpstatus; strncpy(argv[0], "Singularity: exec", strlen(argv[0])); if ( seteuid(uid) < 0 ) { fprintf(stderr, "ABORT: Could not set effective user privileges to %d: %s\n", uid, strerror(errno)); return(255); } waitpid(exec_fork_pid, &tmpstatus, 0); retval = WEXITSTATUS(tmpstatus); } else { fprintf(stderr, "ABORT: Could not fork namespace process: %s\n", strerror(errno)); return(255); } return(retval); } else if ( namespace_fork_pid > 0 ) { int tmpstatus; strncpy(argv[0], "Singularity: namespace", strlen(argv[0])); if ( seteuid(uid) < 0 ) { fprintf(stderr, "ABORT: Could not set effective user privileges to %d: %s\n", uid, strerror(errno)); return(255); } waitpid(namespace_fork_pid, &tmpstatus, 0); retval = WEXITSTATUS(tmpstatus); } else { fprintf(stderr, "ABORT: Could not fork management process: %s\n", strerror(errno)); return(255); } //****************************************************************************// // Final wrap up before exiting //****************************************************************************// if ( close(cwd_fd) < 0 ) { fprintf(stderr, "ERROR: Could not close cwd_fd: %s\n", strerror(errno)); retval++; } if ( flock(tmpdirlock_fd, LOCK_EX | LOCK_NB) == 0 ) { close(tmpdirlock_fd); if ( seteuid(0) < 0 ) { fprintf(stderr, "ABORT: Could not re-escalate effective user privileges: %s\n", strerror(errno)); return(255); } if ( s_rmdir(tmpdir) < 0 ) { fprintf(stderr, "WARNING: Could not remove all files in %s: %s\n", tmpdir, strerror(errno)); } // Dissociate loops from here Just in case autoflush didn't work. (void)disassociate_loop(loop_fp); if ( seteuid(uid) < 0 ) { fprintf(stderr, "ABORT: Could not drop effective user privileges: %s\n", strerror(errno)); return(255); } } else { // printf("Not removing tmpdir, lock still\n"); } close(containerimage_fd); close(tmpdirlock_fd); free(loop_dev_lock); free(containerpath); free(tmpdir); closelog(); return(retval); }
int main (int argc, char **argv) { char tempdir[] = "/tmp/approot_XXXXXX"; char *base_os; char **images; char *root; int n_images; pid_t child; int child_status = 0; char *app_root; char **mountpoints; int n_mountpoints; int i; uid_t ruid, euid, suid; gid_t rgid, egid, sgid; char cwd_buf[PATH_MAX]; char *cwd; if (argc < 2) fatal ("Too few arguments, need base and at least one image"); base_os = argv[1]; images = &argv[2]; n_images = argc - 2; root = mkdtemp (tempdir); if (root == NULL) fatal ("Can't create root"); if (getresgid (&rgid, &egid, &sgid) < 0) fatal_errno ("getresgid"); if (getresuid (&ruid, &euid, &suid) < 0) fatal_errno ("getresuid"); if ((child = syscall (__NR_clone, SIGCHLD | CLONE_NEWNS, NULL)) < 0) fatal_errno ("clone"); if (child == 0) { /* Child */ /* Disable setuid, new caps etc for children */ if (prctl (PR_SET_NO_NEW_PRIVS, 1) < 0 && errno != EINVAL) fatal_errno ("prctl (PR_SET_NO_NEW_PRIVS)"); else if (prctl (PR_SET_SECUREBITS, SECBIT_NOROOT | SECBIT_NOROOT_LOCKED) < 0) fatal_errno ("prctl (SECBIT_NOROOT)"); /* Don't leak our mounts to the parent namespace */ if (mount (NULL, "/", "none", MS_SLAVE | MS_REC, NULL) < 0) fatal_errno ("mount(/, MS_SLAVE | MS_REC)"); /* Check we're allowed to chdir into base os */ cwd = getcwd (cwd_buf, sizeof (cwd_buf)); if (fsuid_chdir (ruid, base_os) < 0) fatal_errno ("chdir"); if (chdir (cwd) < 0) fatal_errno ("chdir"); if (mount ("tmpfs", root, "tmpfs", MS_MGC_VAL | MS_PRIVATE, NULL) != 0) fatal_errno ("execv"); n_mountpoints = n_images + 1; mountpoints = calloc (n_mountpoints, sizeof (char *)); if (mountpoints == NULL) fatal ("oom"); mountpoints[0] = base_os; for (i = 0; i < n_images; i++) { if (fsuid_access (ruid, images[i], R_OK) < 0) fatal_errno ("access"); mountpoints[i+1] = mount_image (root, images[i]); if (mountpoints[i+1] == NULL) fatal ("mount image %s\n", images[i]); } app_root = make_fs_dir (root, "/root", 0555); if (app_root == NULL) fatal ("make_fs_dir root"); setup_base (app_root); merge_dirs (app_root, mountpoints, n_mountpoints); if (chdir (app_root) < 0) fatal_errno ("chdir"); if (chroot (".") < 0) fatal_errno ("chroot"); /* Switch back to the uid of our invoking process. These calls are * irrevocable - see setuid(2) */ if (setgid (rgid) < 0) fatal_errno ("setgid"); if (setuid (ruid) < 0) fatal_errno ("setuid"); if (execl ("/bin/sh", "/bin/sh", NULL) < 0) fatal_errno ("execl"); } /* Parent */ /* Let's also setuid back in the parent - there's no reason to stay uid 0, and * it's just better to drop privileges. */ if (setgid (rgid) < 0) fatal_errno ("setgid"); if (setuid (ruid) < 0) fatal_errno ("setuid"); if (child == -1) fatal_errno ("clone"); /* Ignore Ctrl-C in parent while waiting */ signal (SIGINT, SIG_IGN); if (waitpid (child, &child_status, 0) < 0) fatal_errno ("waitpid"); rmdir (root); if (WIFEXITED (child_status)) return WEXITSTATUS (child_status); else return 1; }