struct tempfile *make_logfile(char *label) { struct tempfile *tf; char *daemon = singularity_registry_get("DAEMON_NAME"); char *image = basename(singularity_registry_get("IMAGE")); tf = malloc(sizeof(struct tempfile)); if (tf == NULL) { singularity_message(ERROR, "Could not allocate memory for tempfile\n"); ABORT(255); } if ( snprintf(tf->filename, sizeof(tf->filename) - 1, "/tmp/%s.%s.%s.XXXXXX", image, daemon, label) > sizeof(tf->filename) - 1 ) { singularity_message(ERROR, "Label string too long\n"); ABORT(255); } tf->filename[sizeof(tf->filename) - 1] = '\0'; if ( (tf->fd = mkstemp(tf->filename)) == -1 || (tf->fp = fdopen(tf->fd, "w+")) == NULL ) { if (tf->fd != -1) { unlink(tf->filename); close(tf->fd); } singularity_message(DEBUG, "Could not create log file, running silently\n"); return(NULL); } singularity_message(DEBUG, "Logging container's %s at: %s\n", label, tf->filename); return(tf); }
char *joinpath(const char * path1, const char * path2_in) { if ( path1 == NULL ) { singularity_message(ERROR, "joinpath() called with NULL path1\n"); ABORT(255); } if ( path2_in == NULL ) { singularity_message(ERROR, "joinpath() called with NULL path2\n"); ABORT(255); } const char *path2 = path2_in; char *tmp_path1 = strdup(path1); int path1_len = strlength(tmp_path1, 4096); char *ret = NULL; if ( tmp_path1[path1_len - 1] == '/' ) { tmp_path1[path1_len - 1] = '\0'; } if ( path2[0] == '/' ) { path2++; } size_t ret_pathlen = strlength(tmp_path1, PATH_MAX) + strlength(path2, PATH_MAX) + 2; ret = (char *) malloc(ret_pathlen); if (snprintf(ret, ret_pathlen, "%s/%s", tmp_path1, path2) >= ret_pathlen) { // Flawfinder: ignore singularity_message(ERROR, "Overly-long path name.\n"); ABORT(255); } return(ret); }
int singularity_rootfs_init(char *source) { char *containername = basename(strdup(source)); singularity_message(DEBUG, "Checking on container source type\n"); if ( containername != NULL ) { setenv("SINGULARITY_CONTAINER", containername, 1); } else { setenv("SINGULARITY_CONTAINER", "unknown", 1); } singularity_message(DEBUG, "Figuring out where to mount Singularity container\n"); mount_point = strdup(singularity_config_get_value(CONTAINER_DIR)); singularity_message(VERBOSE3, "Set image mount path to: %s\n", mount_point); if ( is_file(source) == 0 ) { int len = strlength(source, PATH_MAX); if ( strcmp(&source[len - 5], ".sqsh") == 0 ) { module = ROOTFS_SQUASHFS; return(rootfs_squashfs_init(source, joinpath(mount_point, ROOTFS_SOURCE))); } else { // Assume it is a standard Singularity image module = ROOTFS_IMAGE; return(rootfs_image_init(source, joinpath(mount_point, ROOTFS_SOURCE))); } } else if ( is_dir(source) == 0 ) { module = ROOTFS_DIR; return(rootfs_dir_init(source, joinpath(mount_point, ROOTFS_SOURCE))); } singularity_message(ERROR, "Container not found: %s\n", source); ABORT(255); return(-1); }
/* Updated wait_for_go_ahead() which allows bi-directional wait signaling */ int singularity_wait_for_go_ahead() { if ( (coordination_pipe[0] == -1) || (coordination_pipe[1] == -1)) { singularity_message(ERROR, "Internal error! wait_for_go_ahead invoked with invalid pipe state (%d, %d).\n", coordination_pipe[0], coordination_pipe[1]); ABORT(255); } singularity_message(DEBUG, "Waiting for go-ahead signal\n"); char code = -1; int retval; // Block until other process indicates it is OK to proceed. while ( (-1 == (retval = read(coordination_pipe[0], &code, 1))) && errno == EINTR) {} if (retval == -1) { // Failed to communicate with other process. singularity_message(ERROR, "Failed to communicate with other process: %s (errno=%d)\n", strerror(errno), errno); ABORT(255); } else if (retval == 0) { // Other process closed the write pipe unexpectedly. if ( close(dup(coordination_pipe[1])) == -1 ) { singularity_message(ERROR, "Other process closed write pipe unexpectedly.\n"); ABORT(255); } } singularity_message(DEBUG, "Received go-ahead signal: %d\n", code); return(code); }
static void wait_for_go_ahead() { if ( (coordination_pipe[0] == -1) || (coordination_pipe[1] == -1)) { singularity_message(ERROR, "Internal error! wait_for_go_ahead invoked with invalid pipe state (%d, %d).\n", coordination_pipe[0], coordination_pipe[1]); ABORT(255); } // Close our copy of the write end of the pipe; only the parent should write. close(coordination_pipe[1]); coordination_pipe[1] = -1; char parent_code = -1; int retval; // Block until parent indicates it is OK to proceed. while ( (-1 == (retval = read(coordination_pipe[0], &parent_code, 1))) && errno == EINTR) {} if (retval == -1) { // Failed to communicate with parent. singularity_message(ERROR, "Failed to communicate with parent process: %s (errno=%d)\n", strerror(errno), errno); ABORT(255); } else if (retval == 0) { // Parent closed the write pipe unexpectedly. singularity_message(ERROR, "Parent closed write pipe unexpectedly.\n"); ABORT(255); } // Parent successfully sent a code. if (parent_code != 0) { singularity_message(ERROR, "Parent indicated an error occurred; exiting with the suggested status.\n"); ABORT(parent_code); } close(coordination_pipe[0]); }
void install_sigchld_signal_handle() { int pipes[2]; struct sigaction action; sigset_t empty_mask; sigemptyset(&empty_mask); /* Fill action with handle_sigchld function */ action.sa_sigaction = &handle_sigchld; action.sa_flags = SA_SIGINFO|SA_RESTART; action.sa_mask = empty_mask; singularity_message(DEBUG, "Assigning SIGCHLD sigaction()\n"); if ( -1 == sigaction(SIGCHLD, &action, NULL) ) { singularity_message(ERROR, "Failed to install SIGCHLD signal handler: %s\n", strerror(errno)); ABORT(255); } /* Open pipes for handle_sigchld() to write to */ singularity_message(DEBUG, "Creating sigchld signal pipes\n"); if ( -1 == pipe2(pipes, O_CLOEXEC) ) { singularity_message(ERROR, "Failed to create communication pipes: %s\n", strerror(errno)); ABORT(255); } sigchld_signal_rpipe = pipes[0]; sigchld_signal_wpipe = pipes[1]; }
int singularity_fork_exec(unsigned int flags, char **argv) { int retval = 1; int i = 0; pid_t child; child = singularity_fork(0); if ( child == 0 ) { while(1) { if ( argv[i] == NULL ) { break; } else if ( i == 128 ) { singularity_message(ERROR, "singularity_fork_exec() ARGV out of bounds\n"); ABORT(255); } singularity_message(DEBUG, "fork argv[%d] = %s\n", i, argv[i]); i++; } singularity_message(VERBOSE, "Running child program: %s\n", argv[0]); if ( execvp(argv[0], argv) < 0 ) { //Flawfinder: ignore singularity_message(ERROR, "Failed to exec program %s: %s\n", argv[0], strerror(errno)); ABORT(255); } } else if ( child > 0 ) { retval = wait_child(); } singularity_message(DEBUG, "Returning from singularity_fork_exec with: %d\n", retval); return(retval); }
int envar_defined(char *name) { singularity_message(DEBUG, "Checking if environment variable is defined: %s\n", name); if ( getenv(name) == NULL ) { // Flawfinder: ignore singularity_message(VERBOSE2, "Environment variable is undefined: %s\n", name); return(-1); } singularity_message(VERBOSE2, "Environment variable is defined: %s\n", name); return(0); }
static void prepare_fork() { singularity_message(DEBUG, "Creating parent/child coordination pipes.\n"); // Note we use pipe and not pipe2 here with CLOEXEC. This is because we eventually want the parent process // to exec a separate unprivileged process and inherit the communication pipe. if ( -1 == pipe(coordination_pipe) ) { singularity_message(ERROR, "Failed to create coordination pipe for fork: %s (errno=%d)\n", strerror(errno), errno); ABORT(255); } }
int singularity_rootfs_check(void) { singularity_message(DEBUG, "Checking if container has /bin/sh...\n"); if ( ( is_exec(joinpath(joinpath(mount_point, OVERLAY_FINAL), "/bin/sh")) < 0 ) && ( is_link(joinpath(joinpath(mount_point, OVERLAY_FINAL), "/bin/sh")) < 0 ) ) { singularity_message(ERROR, "Container does not have a valid /bin/sh\n"); ABORT(255); } return(0); }
int check_mounted(char *mountpoint) { int retval = -1; FILE *mounts; char *line = (char *)malloc(MAX_LINE_LEN); char *rootfs_dir = CONTAINER_FINALDIR; unsigned int mountpoint_len = strlength(mountpoint, PATH_MAX); char *real_mountpoint; singularity_message(DEBUG, "Opening /proc/mounts\n"); if ( ( mounts = fopen("/proc/mounts", "r") ) == NULL ) { // Flawfinder: ignore singularity_message(ERROR, "Could not open /proc/mounts: %s\n", strerror(errno)); ABORT(255); } if ( mountpoint[mountpoint_len-1] == '/' ) { singularity_message(DEBUG, "Removing trailing slash from string: %s\n", mountpoint); mountpoint[mountpoint_len-1] = '\0'; } real_mountpoint = realpath(mountpoint, NULL); // Flawfinder: ignore if ( real_mountpoint == NULL ) { // mountpoint doesn't exists return(retval); } singularity_message(DEBUG, "Iterating through /proc/mounts\n"); while ( fgets(line, MAX_LINE_LEN, mounts) != NULL ) { (void) strtok(strdup(line), " "); char *mount = strtok(NULL, " "); // Check to see if mountpoint is already mounted if ( strcmp(joinpath(rootfs_dir, real_mountpoint), mount) == 0 ) { singularity_message(DEBUG, "Mountpoint is already mounted: %s\n", mountpoint); retval = 1; break; } // Check to see if path is in container root if ( strncmp(rootfs_dir, mount, strlength(rootfs_dir, 1024)) != 0 ) { continue; } // Check to see if path is ot the container root if ( strcmp(mount, rootfs_dir) == 0 ) { continue; } } fclose(mounts); free(line); free(real_mountpoint); return(retval); }
void free_tempfile(struct tempfile *tf) { if (fclose(tf->fp)) { singularity_message(ERROR, "Error while closing temp file %s\n", tf->filename); ABORT(255); } if (unlink(tf->filename) < 0) { singularity_message(ERROR, "Could not remove temp file %s\n", tf->filename); ABORT(255); } free(tf); }
static int setup_container_cwd() { singularity_message(DEBUG, "Trying to change directory to where we started\n"); char *target_pwd = singularity_registry_get("TARGET_PWD"); if (!target_pwd || (chdir(target_pwd) < 0)) { singularity_message(ERROR, "Failed to change into correct directory " "(%s) inside container.", target_pwd ? target_pwd : "UNKNOWN"); return -1; } free(target_pwd); return 0; }
int singularity_file_resolvconf(void) { char *file = "/etc/resolv.conf"; singularity_message(DEBUG, "Checking configuration option\n"); if ( singularity_config_get_bool(CONFIG_RESOLV_CONF) <= 0 ) { singularity_message(VERBOSE, "Skipping bind of the host's %s\n", file); return(0); } container_file_bind(file, file); return(0); }
int envar_set(char *key, char *value, int overwrite) { if ( key == NULL ) { singularity_message(VERBOSE2, "Not setting envar, null key\n"); return(-1); } if ( value == NULL ) { singularity_message(DEBUG, "Unsetting environment variable: %s\n", key); return(unsetenv(key)); } singularity_message(DEBUG, "Setting environment variable: '%s' = '%s'\n", key, value); return(setenv(key, value, overwrite)); }
void action_test_do(int argc, char **argv) { singularity_message(VERBOSE, "Exec'ing /.test\n"); if ( is_exec("/.test") == 0 ) { if ( execl("/bin/sh", "test:", "-e", "-x", "/.test", NULL) < 0 ) { // Flawfinder: ignore singularity_message(ERROR, "Failed to execv() /.test: %s\n", strerror(errno)); } } else { singularity_message(INFO, "No test code provided in this container\n"); exit(0); } singularity_message(ERROR, "We should never get here... Grrrrrr!\n"); ABORT(255); }
int main(int argc, char **argv) { struct image_object image; singularity_config_init(); singularity_suid_init(); singularity_priv_init(); singularity_registry_init(); singularity_priv_drop(); singularity_runtime_autofs(); if ( singularity_registry_get("WRITABLE") != NULL ) { singularity_message(VERBOSE3, "Instantiating writable container image object\n"); image = singularity_image_init(singularity_registry_get("IMAGE"), O_RDWR); } else { singularity_message(VERBOSE3, "Instantiating read only container image object\n"); image = singularity_image_init(singularity_registry_get("IMAGE"), O_RDONLY); } if ( is_owner(CONTAINER_MOUNTDIR, 0) != 0 ) { singularity_message(ERROR, "Root must own container mount directory: %s\n", CONTAINER_MOUNTDIR); ABORT(255); } singularity_runtime_ns(SR_NS_MNT); singularity_image_mount(&image, CONTAINER_MOUNTDIR); singularity_runtime_overlayfs(); singularity_priv_drop_perm(); envar_set("SINGULARITY_MOUNTPOINT", CONTAINER_FINALDIR, 1); if ( argc > 1 ) { singularity_message(VERBOSE, "Running command: %s\n", argv[1]); singularity_message(DEBUG, "Calling exec...\n"); execvp(argv[1], &argv[1]); // Flawfinder: ignore (Yes flawfinder, we are exec'ing) singularity_message(ERROR, "Exec failed: %s: %s\n", argv[1], strerror(errno)); ABORT(255); } else { singularity_message(INFO, "%s is mounted at: %s\n\n", singularity_image_name(&image), CONTAINER_FINALDIR); envar_set("PS1", "Singularity> ", 1); execl("/bin/sh", "/bin/sh", NULL); // Flawfinder: ignore (Yes flawfinder, this is what we want, sheesh, so demanding!) singularity_message(ERROR, "Exec of /bin/sh failed: %s\n", strerror(errno)); ABORT(255); } return(0); }
int setns(int fd, int nstype) { (void)fd; (void)nstype; singularity_message(VERBOSE, "setns() not supported at compile time by kernel at time of building\n"); errno = ENOSYS; return -1; }
int _singularity_image_create(struct image_object *image, long int size) { FILE *image_fp; int retval; if ( image->fd <= 0 ) { singularity_message(ERROR, "Can not check image with no FD associated\n"); ABORT(255); } if ( ( image_fp = fdopen(dup(image->fd), "w") ) == NULL ) { singularity_message(ERROR, "Could not associate file pointer from file descriptor on image %s: %s\n", image->path, strerror(errno)); ABORT(255); } singularity_message(VERBOSE2, "Writing image header\n"); fprintf(image_fp, LAUNCH_STRING); // Flawfinder: ignore (LAUNCH_STRING is a constant) singularity_message(VERBOSE2, "Growing image to %ldMB\n", size); while ( 1 ) { retval = posix_fallocate(singularity_image_fd(image), sizeof(LAUNCH_STRING), size * BUFFER_SIZE); if ( retval == EINTR ) { singularity_message(DEBUG, "fallocate was interrupted by a signal, trying again...\n"); continue; } else { break; } } if ( retval != 0 ) { switch ( retval ) { case ENOSPC: singularity_message(ERROR, "There is not enough to space to allocate the image\n"); break; case EBADF: singularity_message(ERROR, "The image file descriptor is not valid for writing\n"); break; case EFBIG: singularity_message(ERROR, "The image size was too big for the filesystem\n"); break; case EINVAL: singularity_message(ERROR, "The image size is invalid.\n"); break; } ABORT(255); } fclose(image_fp); return(0); }
int _singularity_image_mount_squashfs_mount(struct image_object *image, char *mount_point) { if ( image->loopdev == NULL ) { singularity_message(ERROR, "Could not obtain the image loop device\n"); ABORT(255); } singularity_priv_escalate(); singularity_message(VERBOSE, "Mounting squashfs image\n"); if ( mount(image->loopdev, mount_point, "squashfs", MS_NOSUID|MS_RDONLY|MS_NODEV, "errors=remount-ro") < 0 ) { singularity_message(ERROR, "Failed to mount squashfs image in (read only): %s\n", strerror(errno)); ABORT(255); } singularity_priv_drop(); return(0); }
void munmap_file(void *map, size_t size) { int retval; retval = munmap(map, size); if ( retval < 0 ) { singularity_message(ERROR, "Could not teardown memory map for file cleanly\n"); ABORT(255); } }
int singularity_rootfs_chroot(void) { singularity_priv_escalate(); singularity_message(VERBOSE, "Entering container file system root: %s\n", joinpath(mount_point, OVERLAY_FINAL)); if ( chroot(joinpath(mount_point, OVERLAY_FINAL)) < 0 ) { // Flawfinder: ignore (yep, yep, yep... we know!) singularity_message(ERROR, "failed enter container at: %s\n", joinpath(mount_point, OVERLAY_FINAL)); ABORT(255); } singularity_priv_drop(); singularity_message(DEBUG, "Changing dir to '/' within the new root\n"); if ( chdir("/") < 0 ) { singularity_message(ERROR, "Could not chdir after chroot to /: %s\n", strerror(errno)); ABORT(1); } return(0); }
int main(int argc, char ** argv) { char *section; char *file; int toggle_section = 0; int retval = 1; FILE *input; char *line = (char *)malloc(MAX_LINE_LEN); if ( argc < 3 ) { printf("USAGE: %s [section] [file]\n", argv[0]); exit(0); } section = strdup(argv[1]); file = strdup(argv[2]); if ( is_file(file) < 0 ) { singularity_message(ERROR, "File not found: %s\n", file); ABORT(1); } if ( ( input = fopen(file, "r") ) == NULL ) { // Flawfinder: ignore singularity_message(ERROR, "Could not open file %s: %s\n", file, strerror(errno)); ABORT(255); } singularity_message(DEBUG, "Iterating through file looking for sections matching: %%%s\n", section); while ( fgets(line, MAX_LINE_LEN, input) != NULL ) { if ( strncmp(line, strjoin("%", section), strlength(section, 128) + 1) == 0 ) { toggle_section = 1; retval = 0; } else if ( ( toggle_section == 1 ) && ( strncmp(line, "%", 1) == 0 ) ) { toggle_section = 0; } else if ( toggle_section == 1 ) { printf("%s", line); } } fclose(input); free(section); free(file); free(line); return(retval); }
void install_generic_signal_handle() { int pipes[2]; struct sigaction action; sigset_t empty_mask; sigemptyset(&empty_mask); /* Fill action with handle_signal function */ action.sa_sigaction = &handle_signal; action.sa_flags = SA_SIGINFO|SA_RESTART; action.sa_mask = empty_mask; singularity_message(DEBUG, "Assigning generic sigaction()s\n"); if ( -1 == sigaction(SIGINT, &action, NULL) ) { singularity_message(ERROR, "Failed to install SIGINT signal handler: %s\n", strerror(errno)); ABORT(255); } if ( -1 == sigaction(SIGQUIT, &action, NULL) ) { singularity_message(ERROR, "Failed to install SIGQUIT signal handler: %s\n", strerror(errno)); ABORT(255); } if ( -1 == sigaction(SIGTERM, &action, NULL) ) { singularity_message(ERROR, "Failed to install SIGTERM signal handler: %s\n", strerror(errno)); ABORT(255); } if ( -1 == sigaction(SIGHUP, &action, NULL) ) { singularity_message(ERROR, "Failed to install SIGHUP signal handler: %s\n", strerror(errno)); ABORT(255); } if ( -1 == sigaction(SIGUSR1, &action, NULL) ) { singularity_message(ERROR, "Failed to install SIGUSR1 signal handler: %s\n", strerror(errno)); ABORT(255); } if ( -1 == sigaction(SIGUSR2, &action, NULL) ) { singularity_message(ERROR, "Failed to install SIGUSR2 signal handler: %s\n", strerror(errno)); ABORT(255); } /* Open pipes for handle_signal() to write to */ singularity_message(DEBUG, "Creating generic signal pipes\n"); if ( -1 == pipe2(pipes, O_CLOEXEC) ) { singularity_message(ERROR, "Failed to create communication pipes: %s\n", strerror(errno)); ABORT(255); } generic_signal_rpipe = pipes[0]; generic_signal_wpipe = pipes[1]; }
static int wait_child() { int child_ok = 1; int retval, tmpstatus; singularity_message(DEBUG, "Parent process is waiting on child process\n"); do { /* Poll the signal handle read pipes to wait for any written signals */ while ( -1 == (retval = poll(fds, 2, -1)) && errno == EINTR ) {} if ( -1 == retval ) { singularity_message(ERROR, "Failed to wait for file descriptors: %s\n", strerror(errno)); ABORT(255); } /* When SIGCHILD is received, set child_ok = 0 to break out of loop */ if (fds[0].revents) { singularity_message(DEBUG, "SIGCHLD raised, parent is exiting\n"); child_ok = 0; } /* If we catch any other signal, */ if (fds[1].revents) { char signum = SIGKILL; while (-1 == (retval = read(generic_signal_rpipe, &signum, 1)) && errno == EINTR) {} // Flawfinder: ignore if (-1 == retval) { singularity_message(ERROR, "Failed to read from signal handler pipe: %s\n", strerror(errno)); ABORT(255); } singularity_message(VERBOSE2, "Sending signal to child: %d\n", signum); kill(child_pid, signum); } } while( child_ok ); /* Catch the exit status or kill signal of the child process */ waitpid(child_pid, &tmpstatus, 0); if (WIFEXITED(tmpstatus)) { return(WEXITSTATUS(tmpstatus)); } else if (WIFSIGNALED(tmpstatus)) { kill(getpid(), WTERMSIG(tmpstatus)); } return(-1); }
/* Updated signal_go_ahead() which allows bi-directional wait signaling */ void singularity_signal_go_ahead(int code) { if ( (coordination_pipe[0] == -1) || (coordination_pipe[1] == -1)) { singularity_message(ERROR, "Internal error! signal_go_ahead invoked with invalid pipe state (%d, %d).\n", coordination_pipe[0], coordination_pipe[1]); ABORT(255); } singularity_message(DEBUG, "Sending go-ahead signal: %d\n", code); int retval; while ( (-1 == (retval = write(coordination_pipe[1], &code, 1))) && errno == EINTR) {} if (retval == -1) { if ( errno != EPIPE ) { singularity_message(ERROR, "Failed to send go-ahead to child process: %s (errno=%d)\n", strerror(errno), errno); ABORT(255); } } // Note that we don't test for retval == 0 as we should get a EPIPE instead. }
int _singularity_image_mount_squashfs_check(struct image_object *image) { char *image_name = strdup(image->name); int len = strlength(image_name, 1024); if ( strcmp(&image_name[len-5], ".sqsh") != 0 ) { singularity_message(DEBUG, "Image does not appear to be of type '.sqsh': %s\n", image->path); return(-1); } return(0); }
void *mmap_file(off_t offset, size_t size, int fd) { void *map; map = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, offset); if ( map == MAP_FAILED ) { singularity_message(ERROR, "Could not mmap file: %s\n", strerror(errno)); ABORT(255); } return map; }
char *strjoin(char *str1, char *str2) { char *ret; int len = strlength(str1, 2048) + strlength(str2, 2048) + 1; ret = (char *) malloc(len); if (snprintf(ret, len, "%s%s", str1, str2) >= len) { // Flawfinder: ignore singularity_message(ERROR, "Overly-long string encountered.\n"); ABORT(255); } return(ret); }
char *uppercase(char *string) { int len = strlength(string, 4096); char *upperkey = strdup(string); int i = 0; while ( i <= len ) { upperkey[i] = toupper(string[i]); i++; } singularity_message(DEBUG, "Transformed to uppercase: '%s' -> '%s'\n", string, upperkey); return(upperkey); }