int check_mounted(char *mountpoint) { int retval = -1; FILE *mounts; char *line = (char *)malloc(MAX_LINE_LEN); char *rootfs_dir = singularity_runtime_rootfs(NULL); unsigned int mountpoint_len = strlength(mountpoint, PATH_MAX); 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'; } 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 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; } // Check to see if mountpoint is already mounted if ( strcmp(joinpath(rootfs_dir, mountpoint), mount) == 0 ) { singularity_message(DEBUG, "Mountpoint is already mounted: %s\n", mountpoint); retval = 1; break; } } fclose(mounts); free(line); return(retval); }
int _singularity_runtime_mount_binds(void) { char *tmp_config_string; char *container_dir = singularity_runtime_rootfs(NULL); if ( singularity_registry_get("CONTAIN") != NULL ) { singularity_message(DEBUG, "Skipping bind mounts as contain was requested\n"); return(0); } singularity_message(DEBUG, "Checking configuration file for 'bind path'\n"); const char **tmp_config_string_list = singularity_config_get_value_multi(BIND_PATH); if ( strlength(*tmp_config_string_list, 1) == 0 ) { return(0); } while ( *tmp_config_string_list != NULL ) { tmp_config_string = strdup(*tmp_config_string_list); tmp_config_string_list++; char *source = strtok(tmp_config_string, ":"); char *dest = strtok(NULL, ":"); chomp(source); if ( dest == NULL ) { dest = strdup(source); } else { chomp(dest); } singularity_message(VERBOSE2, "Found 'bind path' = %s, %s\n", source, dest); if ( ( is_file(source) < 0 ) && ( is_dir(source) < 0 ) ) { singularity_message(WARNING, "Non existent 'bind path' source: '%s'\n", source); continue; } singularity_message(DEBUG, "Checking if bind point is already mounted: %s\n", dest); if ( check_mounted(dest) >= 0 ) { singularity_message(VERBOSE, "Not mounting bind point (already mounted): %s\n", dest); continue; } if ( ( is_file(source) == 0 ) && ( is_file(joinpath(container_dir, dest)) < 0 ) ) { if ( singularity_registry_get("OVERLAYFS_ENABLED") != NULL ) { char *basedir = dirname(joinpath(container_dir, dest)); singularity_message(DEBUG, "Checking base directory for file %s ('%s')\n", dest, basedir); if ( is_dir(basedir) != 0 ) { singularity_message(DEBUG, "Creating base directory for file bind\n"); singularity_priv_escalate(); if ( s_mkpath(basedir, 0755) != 0 ) { singularity_message(ERROR, "Failed creating base directory to bind file: %s\n", dest); ABORT(255); } singularity_priv_drop(); } free(basedir); singularity_priv_escalate(); singularity_message(VERBOSE3, "Creating bind file on overlay file system: %s\n", dest); FILE *tmp = fopen(joinpath(container_dir, dest), "w+"); // Flawfinder: ignore singularity_priv_drop(); if ( tmp == NULL ) { singularity_message(WARNING, "Could not create bind point file in container %s: %s\n", dest, strerror(errno)); continue; } if ( fclose(tmp) != 0 ) { singularity_message(WARNING, "Could not close bind point file descriptor %s: %s\n", dest, strerror(errno)); continue; } singularity_message(DEBUG, "Created bind file: %s\n", dest); } else { singularity_message(WARNING, "Non existent bind point (file) in container: '%s'\n", dest); continue; } } else if ( ( is_dir(source) == 0 ) && ( is_dir(joinpath(container_dir, dest)) < 0 ) ) { if ( singularity_registry_get("OVERLAYFS_ENABLED") != NULL ) { singularity_priv_escalate(); singularity_message(VERBOSE3, "Creating bind directory on overlay file system: %s\n", dest); if ( s_mkpath(joinpath(container_dir, dest), 0755) < 0 ) { singularity_priv_drop(); singularity_message(WARNING, "Could not create bind point directory in container %s: %s\n", dest, strerror(errno)); continue; } singularity_priv_drop(); } else { singularity_message(WARNING, "Non existent bind point (directory) in container: '%s'\n", dest); continue; } } singularity_priv_escalate(); singularity_message(VERBOSE, "Binding '%s' to '%s/%s'\n", source, container_dir, dest); if ( mount(source, joinpath(container_dir, dest), NULL, MS_BIND|MS_NOSUID|MS_REC, NULL) < 0 ) { singularity_message(ERROR, "There was an error binding the path %s: %s\n", source, strerror(errno)); ABORT(255); } if ( singularity_priv_userns_enabled() != 1 ) { if ( mount(NULL, joinpath(container_dir, dest), NULL, MS_BIND|MS_NOSUID|MS_REC|MS_REMOUNT, NULL) < 0 ) { singularity_message(ERROR, "There was an error remounting the path %s: %s\n", source, strerror(errno)); ABORT(255); } } singularity_priv_drop(); } return(0); }
int _singularity_runtime_mount_tmp(void) { char *container_dir = singularity_runtime_rootfs(NULL); char *tmp_source; char *vartmp_source; if ( singularity_config_get_bool(MOUNT_TMP) <= 0 ) { singularity_message(VERBOSE, "Skipping tmp dir mounting (per config)\n"); return(0); } if ( singularity_registry_get("CONTAIN") == NULL ) { tmp_source = strdup("/tmp"); vartmp_source = strdup("/var/tmp"); } else { char *tmpdirpath; if ( ( tmpdirpath = singularity_registry_get("WORKDIR") ) != NULL ) { if ( singularity_config_get_bool(USER_BIND_CONTROL) <= 0 ) { singularity_message(ERROR, "User bind control is disabled by system administrator\n"); ABORT(5); } tmp_source = joinpath(tmpdirpath, "/tmp"); vartmp_source = joinpath(tmpdirpath, "/var_tmp"); } else { char *sessiondir = singularity_registry_get("SESSIONDIR"); tmp_source = joinpath(sessiondir, "/tmp"); vartmp_source = joinpath(sessiondir, "/var_tmp"); } free(tmpdirpath); } if ( check_mounted("/tmp") < 0 ) { if ( s_mkpath(tmp_source, 0755) < 0 ) { singularity_message(ERROR, "Could not create source /tmp directory %s: %s\n", tmp_source, strerror(errno)); ABORT(255); } if ( is_dir(tmp_source) == 0 ) { if ( is_dir(joinpath(container_dir, "/tmp")) == 0 ) { singularity_priv_escalate(); singularity_message(VERBOSE, "Mounting directory: /tmp\n"); if ( mount(tmp_source, joinpath(container_dir, "/tmp"), NULL, MS_BIND|MS_NOSUID|MS_REC, NULL) < 0 ) { singularity_message(ERROR, "Failed to mount %s -> /tmp: %s\n", tmp_source, strerror(errno)); ABORT(255); } if ( singularity_priv_userns_enabled() != 1 ) { if ( mount(NULL, joinpath(container_dir, "/tmp"), NULL, MS_BIND|MS_NOSUID|MS_REC|MS_REMOUNT, NULL) < 0 ) { singularity_message(ERROR, "Failed to remount /tmp: %s\n", strerror(errno)); ABORT(255); } } singularity_priv_drop(); } else { singularity_message(VERBOSE, "Could not mount container's /tmp directory: does not exist\n"); } } else { singularity_message(VERBOSE, "Could not mount host's /tmp directory (%s): does not exist\n", tmp_source); } } else { singularity_message(VERBOSE, "Not mounting '/tmp', already mounted\n"); } if ( check_mounted("/var/tmp") < 0 ) { if ( s_mkpath(vartmp_source, 0755) < 0 ) { singularity_message(ERROR, "Could not create source /var/tmp directory %s: %s\n", vartmp_source, strerror(errno)); ABORT(255); } if ( is_dir(vartmp_source) == 0 ) { if ( is_dir(joinpath(container_dir, "/var/tmp")) == 0 ) { singularity_priv_escalate(); singularity_message(VERBOSE, "Mounting directory: /var/tmp\n"); if ( mount(vartmp_source, joinpath(container_dir, "/var/tmp"), NULL, MS_BIND|MS_NOSUID|MS_REC, NULL) < 0 ) { singularity_message(ERROR, "Failed to mount %s -> /var/tmp: %s\n", vartmp_source, strerror(errno)); ABORT(255); } if ( singularity_priv_userns_enabled() != 1 ) { if ( mount(NULL, joinpath(container_dir, "/var/tmp"), NULL, MS_BIND|MS_NOSUID|MS_REC|MS_REMOUNT, NULL) < 0 ) { singularity_message(ERROR, "Failed to remount /var/tmp: %s\n", strerror(errno)); ABORT(255); } } singularity_priv_drop(); } else { singularity_message(VERBOSE, "Could not mount container's /var/tmp directory: does not exist\n"); } } else { singularity_message(VERBOSE, "Could not mount host's /var/tmp directory (%s): does not exist\n", vartmp_source); } } else { singularity_message(VERBOSE, "Not mounting '/var/tmp', already mounted\n"); } free(tmp_source); free(vartmp_source); return(0); }
int _singularity_runtime_mount_userbinds(void) { char *container_dir = singularity_runtime_rootfs(NULL); char *bind_path_string; singularity_message(DEBUG, "Checking for environment variable 'SINGULARITY_BINDPATH'\n"); if ( ( bind_path_string = singularity_registry_get("BINDPATH") ) != NULL ) { singularity_message(DEBUG, "Checking for 'user bind control' in config\n"); if ( singularity_config_get_bool(USER_BIND_CONTROL) <= 0 ) { singularity_message(WARNING, "Ignoring user bind request: user bind control is disabled by system administrator\n"); return(0); } #ifndef SINGULARITY_NO_NEW_PRIVS singularity_message(WARNING, "Ignoring user bind request: host does not support PR_SET_NO_NEW_PRIVS\n"); return(0); #endif singularity_message(DEBUG, "Parsing SINGULARITY_BINDPATH for user-specified bind mounts.\n"); char *outside_token = NULL; char *inside_token = NULL; char *current = strtok_r(strdup(bind_path_string), ",", &outside_token); free(bind_path_string); while ( current != NULL ) { int read_only = 0; char *source = strtok_r(current, ":", &inside_token); char *dest = strtok_r(NULL, ":", &inside_token); char *opts = strtok_r(NULL, ":", &inside_token); current = strtok_r(NULL, ",", &outside_token); if ( dest == NULL ) { dest = source; } singularity_message(DEBUG, "Found bind: %s -> container:%s\n", source, dest); if ( opts != NULL ) { if ( strcmp(opts, "rw") == 0 ) { // This is the default } else if ( strcmp(opts, "ro") == 0 ) { read_only = 1; } else { singularity_message(WARNING, "Not mounting requested bind point, invalid mount option %s: %s\n", opts, dest); continue; } } singularity_message(DEBUG, "Checking if bind point is already mounted: %s\n", dest); if ( check_mounted(dest) >= 0 ) { singularity_message(WARNING, "Not mounting requested bind point (already mounted in container): %s\n", dest); continue; } if ( ( is_file(source) == 0 ) && ( is_file(joinpath(container_dir, dest)) < 0 ) ) { if ( singularity_registry_get("OVERLAYFS_ENABLED") != NULL ) { char *dir = dirname(strdup(dest)); if ( is_dir(joinpath(container_dir, dir)) < 0 ) { singularity_message(VERBOSE3, "Creating bind directory on overlay file system: %s\n", dest); if ( s_mkpath(joinpath(container_dir, dir), 0755) < 0 ) { singularity_priv_escalate(); singularity_message(VERBOSE3, "Retrying with privileges to create bind directory on overlay file system: %s\n", dest); if ( s_mkpath(joinpath(container_dir, dir), 0755) < 0 ) { singularity_message(ERROR, "Could not create basedir for file bind %s: %s\n", dest, strerror(errno)); continue; } singularity_priv_drop(); } } singularity_priv_escalate(); singularity_message(VERBOSE3, "Creating bind file on overlay file system: %s\n", dest); FILE *tmp = fopen(joinpath(container_dir, dest), "w+"); // Flawfinder: ignore singularity_priv_drop(); if ( tmp == NULL ) { singularity_message(WARNING, "Skipping user bind, could not create bind point %s: %s\n", dest, strerror(errno)); continue; } if ( fclose(tmp) != 0 ) { singularity_message(WARNING, "Skipping user bind, could not close bind point file descriptor %s: %s\n", dest, strerror(errno)); continue; } singularity_message(DEBUG, "Created bind file: %s\n", dest); } else { singularity_message(WARNING, "Skipping user bind, non existant bind point (file) in container: '%s'\n", dest); continue; } } else if ( ( is_dir(source) == 0 ) && ( is_dir(joinpath(container_dir, dest)) < 0 ) ) { if ( singularity_registry_get("OVERLAYFS_ENABLED") != NULL ) { singularity_message(VERBOSE3, "Creating bind directory on overlay file system: %s\n", dest); if ( s_mkpath(joinpath(container_dir, dest), 0755) < 0 ) { singularity_priv_escalate(); singularity_message(VERBOSE3, "Retrying with privileges to create bind directory on overlay file system: %s\n", dest); if ( s_mkpath(joinpath(container_dir, dest), 0755) < 0 ) { singularity_priv_drop(); singularity_message(WARNING, "Skipping user bind, could not create bind point %s: %s\n", dest, strerror(errno)); continue; } singularity_priv_drop(); } } else { singularity_message(WARNING, "Skipping user bind, non existant bind point (directory) in container: '%s'\n", dest); continue; } } singularity_priv_escalate(); singularity_message(VERBOSE, "Binding '%s' to '%s/%s'\n", source, container_dir, dest); if ( mount(source, joinpath(container_dir, dest), NULL, MS_BIND|MS_NOSUID|MS_REC, NULL) < 0 ) { singularity_message(ERROR, "There was an error binding the path %s: %s\n", source, strerror(errno)); ABORT(255); } if ( read_only ) { if ( singularity_priv_userns_enabled() == 1 ) { singularity_message(WARNING, "Can not make bind mount read only within the user namespace: %s\n", dest); } else { singularity_message(VERBOSE, "Remounting %s read-only\n", dest); if ( mount(NULL, joinpath(container_dir, dest), NULL, MS_RDONLY|MS_BIND|MS_NOSUID|MS_REC|MS_REMOUNT, NULL) < 0 ) { singularity_message(ERROR, "There was an error write-protecting the path %s: %s\n", source, strerror(errno)); ABORT(255); } if ( access(joinpath(container_dir, dest), W_OK) == 0 || errno != EROFS ) { // Flawfinder: ignore (precautionary confirmation, not necessary) singularity_message(ERROR, "Failed to write-protect the path %s: %s\n", source, strerror(errno)); ABORT(255); } } } else { if ( singularity_priv_userns_enabled() <= 0 ) { if ( mount(NULL, joinpath(container_dir, dest), NULL, MS_BIND|MS_NOSUID|MS_REC|MS_REMOUNT, NULL) < 0 ) { singularity_message(ERROR, "There was an error remounting the path %s: %s\n", source, strerror(errno)); ABORT(255); } } } singularity_priv_drop(); } singularity_message(DEBUG, "Unsetting environment variable 'SINGULARITY_BINDPATH'\n"); unsetenv("SINGULARITY_BINDPATH"); } else { singularity_message(DEBUG, "No user bind mounts specified.\n"); } return(0); }
static int setup_container(spank_t spank) { int rc; struct image_object image; char *command = NULL; if ((rc = setup_container_environment(spank)) != 0) { return rc; } /* * Ugg, singularity_* calls tend to call ABORT(255), which translates to * exit(255), all over the place. The slurm SPANK hook API may not * expect such sudden death of the pending slurm task. I've left * a bunch of following "return rc;" commented out, as the failure * conditions from singularity_* calls isn't clear to me. */ // Before we do anything, check privileges and drop permission singularity_priv_init(); singularity_priv_drop(); singularity_message(VERBOSE, "Running Slurm/Singularity integration " "plugin\n"); if ((rc = singularity_config_init()) != 0) { return rc; } singularity_priv_init(); //TODO singularity_suid_init(argv); singularity_registry_init(); singularity_priv_userns(); singularity_priv_drop(); singularity_cleanupd(); singularity_runtime_ns(SR_NS_ALL); singularity_sessiondir(); image = singularity_image_init(singularity_registry_get("IMAGE")); if ( singularity_registry_get("WRITABLE") == NULL ) { singularity_image_open(&image, O_RDONLY); } else { singularity_image_open(&image, O_RDWR); } singularity_image_check(&image); singularity_image_bind(&image); singularity_image_mount(&image, singularity_runtime_rootfs(NULL)); action_ready(singularity_runtime_rootfs(NULL)); singularity_runtime_overlayfs(); singularity_runtime_mounts(); singularity_runtime_files(); singularity_runtime_enter(); singularity_runtime_environment(); singularity_priv_drop_perm(); if ((rc = setup_container_cwd()) < 0) { singularity_message(ERROR, "Could not obtain current directory.\n"); return rc; } envar_set("SINGULARITY_CONTAINER", singularity_image_name(&image), 1); // Legacy PS1 support envar_set("SINGULARITY_NAME", singularity_image_name(&image), 1); envar_set("SINGULARITY_SHELL", singularity_registry_get("SHELL"), 1); command = singularity_registry_get("COMMAND"); singularity_message(LOG, "USER=%s, IMAGE='%s', COMMAND='%s'\n", singularity_priv_getuser(), singularity_image_name(&image), singularity_registry_get("COMMAND")); // At this point, the current process is in the runtime container environment. // Return control flow back to Slurm: when execv is invoked, it'll be done from // within the container. return 0; }