Login
Log in using an SSO provider:
Fedora Account System
Red Hat Associate
Red Hat Customer
Login using a Red Hat Bugzilla account
Forgot Password
Create an Account
Red Hat Bugzilla – Attachment 440903 Details for
Bug 623522
bind mounts of /home prevents hardlinks on same file system
Home
New
Search
Simple Search
Advanced Search
My Links
Browse
Requests
Reports
Current State
Search
Tabular reports
Graphical reports
Duplicates
Other Reports
User Changes
Plotly Reports
Bug Status
Bug Severity
Non-Defaults
Product Dashboard
Help
Page Help!
Bug Writing Guidelines
What's new
Browser Support Policy
5.0.4.rh90 Release notes
FAQ
Guides index
User guide
Web Services
Contact
Legal
[?]
This site requires JavaScript to be enabled to function correctly, please enable it.
Here is the full c file.
seunshare.c (text/x-csrc), 12.98 KB, created by
Daniel Walsh
on 2010-08-25 12:31:39 UTC
(
hide
)
Description:
Here is the full c file.
Filename:
MIME Type:
Creator:
Daniel Walsh
Created:
2010-08-25 12:31:39 UTC
Size:
12.98 KB
patch
obsolete
>/* > * Authors: Dan Walsh <dwalsh@redhat.com> > * Authors: Thomas Liu <tliu@fedoraproject.org> > */ > >#define _GNU_SOURCE >#include <signal.h> >#include <sys/types.h> >#include <sys/stat.h> >#include <sys/wait.h> >#include <syslog.h> >#include <sys/mount.h> >#include <pwd.h> >#include <sched.h> >#include <libcgroup.h> >#include <string.h> >#include <stdio.h> >#include <regex.h> >#include <unistd.h> >#include <stdlib.h> >#include <cap-ng.h> >#include <getopt.h> /* for getopt_long() form of getopt() */ >#include <limits.h> >#include <stdlib.h> >#include <errno.h> >#include <fcntl.h> > >#include <selinux/selinux.h> >#include <selinux/context.h> /* for context-mangling functions */ > >#ifdef USE_NLS >#include <locale.h> /* for setlocale() */ >#include <libintl.h> /* for gettext() */ >#define _(msgid) gettext (msgid) >#else >#define _(msgid) (msgid) >#endif > >#ifndef MS_REC >#define MS_REC 1<<14 >#endif > >#ifndef MS_PRIVATE >#define MS_PRIVATE 1<<18 >#endif > >#ifndef PACKAGE >#define PACKAGE "policycoreutils" /* the name of this package lang translation */ >#endif > >#define BUF_SIZE 1024 > >/** > * This function will drop all capabilities > * Returns zero on success, non-zero otherwise > */ >static int drop_capabilities(uid_t uid) >{ > capng_clear(CAPNG_SELECT_BOTH); > > if (capng_lock() < 0) > return -1; > /* Change uid */ > if (setresuid(uid, uid, uid)) { > fprintf(stderr, _("Error changing uid, aborting.\n")); > return -1; > } > return capng_apply(CAPNG_SELECT_BOTH); >} > >#define DEFAULT_PATH "/usr/bin:/bin" >static int verbose = 0; > >/** > * Take care of any signal setup > */ >static int set_signal_handles(void) >{ > sigset_t empty; > > /* Empty the signal mask in case someone is blocking a signal */ > if (sigemptyset(&empty)) { > fprintf(stderr, "Unable to obtain empty signal set\n"); > return -1; > } > > (void)sigprocmask(SIG_SETMASK, &empty, NULL); > > /* Terminate on SIGHUP. */ > if (signal(SIGHUP, SIG_DFL) == SIG_ERR) { > perror("Unable to set SIGHUP handler"); > return -1; > } > > return 0; >} > >/** > * This function makes sure the mounted directory is owned by the user executing > * seunshare. > * If so, it returns 0. If it can not figure this out or they are different, it returns -1. > */ >static int verify_mount(const char *mntdir, struct passwd *pwd) { > struct stat sb; > if (stat(mntdir, &sb) == -1) { > fprintf(stderr, _("Invalid mount point %s: %s\n"), mntdir, strerror(errno)); > return -1; > } > if (sb.st_uid != pwd->pw_uid) { > errno = EPERM; > syslog(LOG_AUTHPRIV | LOG_ALERT, "%s attempted to mount an invalid directory, %s", pwd->pw_name, mntdir); > perror(_("Invalid mount point, reporting to administrator")); > return -1; > } > return 0; >} > >/** > * This function checks to see if the shell is known in /etc/shells. > * If so, it returns 0. On error or illegal shell, it returns -1. > */ >static int verify_shell(const char *shell_name) >{ > int rc = -1; > const char *buf; > > if (!(shell_name && shell_name[0])) > return rc; > > while ((buf = getusershell()) != NULL) { > /* ignore comments */ > if (*buf == '#') > continue; > > /* check the shell skipping newline char */ > if (!strcmp(shell_name, buf)) { > rc = 1; > break; > } > } > endusershell(); > return rc; >} > >static int seunshare_mount(const char *src, const char *dst, struct passwd *pwd) { > if (verbose) > printf("Mount %s on %s\n", src, dst); > > int flags = MS_REC; > if (strcmp("/tmp", dst) == 0) { > flags = flags | MS_NODEV | MS_NOSUID | MS_NOEXEC; > } > > if (mount(dst, dst, NULL, MS_BIND | flags, NULL) < 0) { > fprintf(stderr, _("Failed to mount %s on %s: %s\n"), dst, dst, strerror(errno)); > return -1; > } > > if (mount(dst, dst, NULL, MS_PRIVATE | flags, NULL) < 0) { > fprintf(stderr, _("Failed to make %s private: %s\n"), dst, strerror(errno)); > return -1; > } > > if (mount(src, dst, NULL, MS_BIND | flags, NULL) < 0) { > fprintf(stderr, _("Failed to mount %s on %s: %s\n"), src, dst, strerror(errno)); > return -1; > } > > if (verify_mount(dst, pwd) < 0) > return -1; > > if (strcmp("/tmp", dst) == 0) { > struct stat sb; > int fd = open(dst,O_RDONLY); > if ( fd == -1 ) goto err; > if (fstat(fd, &sb) == -1) { > close(fd); > goto err; > } > if (fchmod(fd, sb.st_mode | S_ISVTX) < 0) { > close(fd); > goto err; > } > close(fd); > } > > return 0; >err: > fprintf(stderr, _("Invalid mount point %s: %s\n"), src, strerror(errno)); > return -1; >} > >#define USAGE_STRING _("USAGE: seunshare [ -v ] [ -t tmpdir ] [ -h homedir ] [-Z CONTEXT] -- executable [args] ") > >int sandbox_error(const char *string) { > fprintf(stderr, string); > syslog(LOG_AUTHPRIV | LOG_ALERT, string); > exit(-1); > >} > > >int match(const char *string, char *pattern) { > int status; > regex_t re; > if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB) != 0) { > return 0; > } > status = regexec(&re, string, (size_t)0, NULL, 0); > regfree(&re); > if (status != 0) { > return 0; > } > return 1; >} > >void config_error() { > fprintf(stderr, "Error parsing config file."); > exit(-1); >} > >int main(int argc, char **argv) { > int rc; > int status = -1; > > security_context_t scontext = NULL; > > int flag_index; /* flag index in argv[] */ > int clflag; /* holds codes for command line flags */ > char *tmpdir_s = NULL; /* tmpdir spec'd by user in argv[] */ > char *homedir_s = NULL; /* homedir spec'd by user in argv[] */ > int usecgroups = 0; > > const struct option long_options[] = { > {"homedir", 1, 0, 'h'}, > {"tmpdir", 1, 0, 't'}, > {"verbose", 1, 0, 'v'}, > {"cgroups", 1, 0, 'c'}, > {"context", 1, 0, 'Z'}, > {NULL, 0, 0, 0} > }; > > uid_t uid = getuid(); > > if (!uid) { > fprintf(stderr, _("Must not be root")); > return -1; > } > >#ifdef USE_NLS > setlocale(LC_ALL, ""); > bindtextdomain(PACKAGE, LOCALEDIR); > textdomain(PACKAGE); >#endif > > struct passwd *pwd=getpwuid(uid); > if (!pwd) { > perror(_("getpwduid failed")); > return -1; > } > > if (verify_shell(pwd->pw_shell) < 0) { > fprintf(stderr, _("Error! Shell is not valid.\n")); > return -1; > } > > while (1) { > clflag = getopt_long(argc, argv, "cvh:t:c:m:p:Z:", long_options, > &flag_index); > if (clflag == -1) > break; > > switch (clflag) { > case 't': > tmpdir_s = optarg; > if (verify_mount(tmpdir_s, pwd) < 0) return -1; > break; > case 'h': > homedir_s = optarg; > if (verify_mount(homedir_s, pwd) < 0) return -1; > if (verify_mount(pwd->pw_dir, pwd) < 0) return -1; > break; > case 'v': > verbose = 1; > break; > case 'c': > usecgroups = 1; > break; > case 'Z': > scontext = strdup(optarg); > break; > default: > fprintf(stderr, "%s\n", USAGE_STRING); > return -1; > } > } > > if (! homedir_s && ! tmpdir_s) { > fprintf(stderr, _("Error: tmpdir and/or homedir required \n %s\n"),USAGE_STRING); > return -1; > } > > if (argc - optind < 1) { > fprintf(stderr, _("Error: executable required \n %s \n"), USAGE_STRING); > return -1; > } > > > if (set_signal_handles()) > return -1; > if (usecgroups) { > char *cpus = NULL; /* which CPUs to use */ > char *cgroupname = NULL;/* name for the cgroup */ > char *mem = NULL; /* string for memory amount to pass to cgroup */ > int64_t memusage = 0; /* amount of memory to use max (percent) */ > int cpupercentage = 0; /* what percentage of cpu to allow usage */ > FILE* fp; > char buf[BUF_SIZE]; > char *tok = NULL; > const char* fname = "/etc/sysconfig/sandbox"; > > if ((fp = fopen(fname, "rt")) == NULL) { > fprintf(stderr, "Error opening sandbox config file."); > exit(-1); > } > while(fgets(buf, BUF_SIZE, fp) != NULL) { > /* Skip comments */ > if (buf[0] == '#') continue; > > /* Copy the string, ignoring whitespace */ > int len = strlen(buf); > char *str = malloc((len + 1) * sizeof(char)); > > int ind = 0; > int i; > for (i = 0; i < len; i++) { > char cur = buf[i]; > if (cur != ' ' && cur != '\t') { > str[ind] = cur; > ind++; > } > } > str[ind] = '\0'; > > tok = strtok(str, "=\n"); > if (tok != NULL) { > if (!strcmp(tok, "CPUAFFINITY")) { > tok = strtok(NULL, "=\n"); > cpus = strdup(tok); > if (!strcmp(cpus, "ALL")) { > cpus = NULL; > } > } else if (!strcmp(tok, "MEMUSAGE")) { > tok = strtok(NULL, "=\n"); > if (match(tok, "^[0-9]+[kKmMgG%]")) { > char *ind = strchr(tok, '%'); > if (ind != NULL) { > *ind = '\0';; > memusage = atoi(tok); > } else { > mem = strdup(tok); > } > } else { > config_error(); > } > > } else if (!strcmp(tok, "CPUUSAGE")) { > tok = strtok(NULL, "=\n"); > if (match(tok, "^[0-9]+\%")) { > char* ind = strchr(tok, '%'); > *ind = '\0'; > cpupercentage = atoi(tok); > } else { > config_error(); > } > } else if (!strcmp(tok, "NAME")) { > tok = strtok(NULL, "=\n"); > cgroupname = strdup(tok); > } else { > continue; > } > } > > > } > if (mem == NULL) { > long phypz = sysconf(_SC_PHYS_PAGES); > long psize = sysconf(_SC_PAGE_SIZE); > memusage = phypz * psize * (float) memusage / 100.0; > } > > cgroup_init(); > > int64_t current_runtime = 0; > int64_t current_period = 0 ; > int64_t current_mem = 0; > char *curr_cpu_path = NULL; > char *curr_mem_path = NULL; > int ret = cgroup_get_current_controller_path(getpid(), "cpu", &curr_cpu_path); > if (ret) { > sandbox_error("Error while trying to get current controller path.\n"); > } else { > struct cgroup *curr = cgroup_new_cgroup(curr_cpu_path); > cgroup_get_cgroup(curr); > cgroup_get_value_int64(cgroup_get_controller(curr, "cpu"), "cpu.rt_runtime_us", ¤t_runtime); > cgroup_get_value_int64(cgroup_get_controller(curr, "cpu"), "cpu.rt_period_us", ¤t_period); > } > > ret = cgroup_get_current_controller_path(getpid(), "memory", &curr_mem_path); > if (ret) { > sandbox_error("Error while trying to get current controller path.\n"); > } else { > struct cgroup *curr = cgroup_new_cgroup(curr_mem_path); > cgroup_get_cgroup(curr); > cgroup_get_value_int64(cgroup_get_controller(curr, "memory"), "memory.limit_in_bytes", ¤t_mem); > } > > if (((float) cpupercentage) / 100.0> (float)current_runtime / (float) current_period) { > sandbox_error("CPU usage restricted!\n"); > exit(-1); > } > > if (mem == NULL) { > if (memusage > current_mem) { > sandbox_error("Attempting to use more memory than allowed!"); > exit(-1); > } > } > > long nprocs = sysconf(_SC_NPROCESSORS_ONLN); > > struct sched_param sp; > sp.sched_priority = sched_get_priority_min(SCHED_FIFO); > sched_setscheduler(getpid(), SCHED_FIFO, &sp); > struct cgroup *sandbox_group = cgroup_new_cgroup(cgroupname); > cgroup_add_controller(sandbox_group, "memory"); > cgroup_add_controller(sandbox_group, "cpu"); > > if (mem == NULL) { > if (memusage > 0) { > cgroup_set_value_uint64(cgroup_get_controller(sandbox_group, "memory"), "memory.limit_in_bytes", memusage); > } > } else { > cgroup_set_value_string(cgroup_get_controller(sandbox_group, "memory"), "memory.limit_in_bytes", mem); > } > if (cpupercentage > 0) { > cgroup_set_value_uint64(cgroup_get_controller(sandbox_group, "cpu"), "cpu.rt_runtime_us", > (float) cpupercentage / 100.0 * 60000); > cgroup_set_value_uint64(cgroup_get_controller(sandbox_group, "cpu"), "cpu.rt_period_us",60000 * nprocs); > } > if (cpus != NULL) { > cgroup_set_value_string(cgroup_get_controller(sandbox_group, "cpu"), "cgroup.procs",cpus); > } > > uint64_t allocated_mem; > if (cgroup_get_value_uint64(cgroup_get_controller(sandbox_group, "memory"), "memory.limit_in_bytes", &allocated_mem) > current_mem) { > sandbox_error("Attempting to use more memory than allowed!\n"); > exit(-1); > } > > > int r = cgroup_create_cgroup(sandbox_group, 1); > if (r != 0) { > sandbox_error("Failed to create group. Ensure that cgconfig service is running. \n"); > exit(-1); > } > > > cgroup_attach_task(sandbox_group); > > } > > if (unshare(CLONE_NEWNS) < 0) { > perror(_("Failed to unshare")); > return -1; > } > > if (homedir_s && tmpdir_s && (strncmp(pwd->pw_dir, tmpdir_s, strlen(pwd->pw_dir)) == 0)) { > if (seunshare_mount(tmpdir_s, "/tmp", pwd) < 0) > return -1; > if (seunshare_mount(homedir_s, pwd->pw_dir, pwd) < 0) > return -1; > } else { > if (homedir_s && seunshare_mount(homedir_s, pwd->pw_dir, pwd) < 0) > return -1; > > if (tmpdir_s && seunshare_mount(tmpdir_s, "/tmp", pwd) < 0) > return -1; > } > > if (drop_capabilities(uid)) { > perror(_("Failed to drop all capabilities")); > return -1; > } > > int child = fork(); > if (child == -1) { > perror(_("Unable to fork")); > return -1; > } > > if (!child) { > char *display=NULL; > /* Construct a new environment */ > char *d = getenv("DISPLAY"); > if (d) { > display = strdup(d); > if (!display) { > perror(_("Out of memory")); > exit(-1); > } > } > > if ((rc = clearenv())) { > perror(_("Unable to clear environment")); > free(display); > exit(-1); > } > > if (scontext) { > if (setexeccon(scontext)) { > fprintf(stderr, _("Could not set exec context to %s.\n"), > scontext); > free(display); > exit(-1); > } > } > > if (display) > rc |= setenv("DISPLAY", display, 1); > rc |= setenv("HOME", pwd->pw_dir, 1); > rc |= setenv("SHELL", pwd->pw_shell, 1); > rc |= setenv("USER", pwd->pw_name, 1); > rc |= setenv("LOGNAME", pwd->pw_name, 1); > rc |= setenv("PATH", DEFAULT_PATH, 1); > > if (chdir(pwd->pw_dir)) { > perror(_("Failed to change dir to homedir")); > exit(-1); > } > execv(argv[optind], argv + optind); > free(display); > freecon(scontext); > perror("execv"); > exit(-1); > } else { > waitpid(child, &status, 0); > } > > return status; >}
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 623522
: 440903