From: Karel Zak Date: Fri, 4 May 2007 09:05:51 +0000 (+0200) Subject: mount: add support for context, fscontext and defcontext selinux mount options X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3a620ba4bffade41d81c429560c40bb65c9b81a7;p=util-linux mount: add support for context, fscontext and defcontext selinux mount options Signed-off-by: Karel Zak --- diff --git a/mount/Makefile.am b/mount/Makefile.am index 6f0d403d..bd2ff1c2 100644 --- a/mount/Makefile.am +++ b/mount/Makefile.am @@ -62,6 +62,9 @@ swapargs.h: clean-local: rm -f swapargs.h +if HAVE_SELINUX +mount_LDADD += -lselinux +endif install-exec-hook: chmod 4755 $(DESTDIR)$(bindir)/mount diff --git a/mount/mount.8 b/mount/mount.8 index 4692a42b..8ed5a11b 100644 --- a/mount/mount.8 +++ b/mount/mount.8 @@ -703,6 +703,50 @@ This option implies the options .BR noexec ", " nosuid ", and " nodev (unless overridden by subsequent options, as in the option line .BR users,exec,dev,suid ). +.TP +\fBcontext=\fP\fIcontext\fP, \fBfscontext=\fP\fIcontext\fP and \fBdefcontext=\fP\fIcontext\fP +The +.BR context= +option is useful when mounting filesystems that do not support +extended attributes, such as a floppy or hard disk formatted with VFAT, or +systems that are not normally running under SELinux, such as an ext3 formatted +disk from a non-SELinux workstation. You can also use +.BR context= +on filesystems you do not trust, such as a floppy. It also helps in compatibility with +xattr-supporting filesystems on earlier 2.4. kernel versions. Even where +xattrs are supported, you can save time not having to label every file by +assigning the entire disk one security context. + +A commonly used option for removable media is +.BR context=system_u:object_r:removable_t . + +Two other options are +.BR fscontext= +and +.BR defcontext= , +both of which are mutually exclusive of the context option. This means you +can use fscontext and defcontext with each other, but neither can be used with +context. + +The +.BR fscontext= +option works for all filesystems, regardless of their xattr +support. The fscontext option sets the overarching filesystem label to a +specific security context. This filesystem label is separate from the +individual labels on the files. It represents the entire filesystem for +certain kinds of permission checks, such as during mount or file creation. +Individual file labels are still obtained from the xattrs on the files +themselves. The context option actually sets the aggregate context that +fscontext provides, in addition to supplying the same label for individual +files. + +You can set the default security context for unlabeled files using +.BR defcontext= +option. This overrides the value set for unlabeled files in the policy and requires a +file system that supports xattr labeling. + +For more details see +.BR selinux (8) .RE .TP .B \-\-bind diff --git a/mount/mount.c b/mount/mount.c index 495eaed6..be2e4bfc 100644 --- a/mount/mount.c +++ b/mount/mount.c @@ -24,6 +24,11 @@ #include #include +#ifdef HAVE_LIBSELINUX +#include +#include +#endif + #include "mount_blkid.h" #include "mount_constants.h" #include "sundries.h" @@ -298,13 +303,71 @@ append_numopt(char *s, const char *opt, long num) return append_opt(s, opt, buf); } +#ifdef HAVE_LIBSELINUX +/* strip quotes from a "string" + * Warning: This function modify the "str" argument. + */ +static char * +strip_quotes(char *str) +{ + char *end = NULL; + + if (*str != '"') + return str; + + end = strrchr(str, '"'); + if (end == NULL || end == str) + die (EX_USAGE, _("mount: improperly quoted option string '%s'"), str); + + *end = '\0'; + return str+1; +} + +/* translates SELinux context from human to raw format and + * appends it to the mount extra options. + * + * returns -1 on error and 0 on success + */ +static int +append_context(const char *optname, char *optdata, char **extra_opts) +{ + security_context_t raw = NULL; + char *data = NULL; + + if (!is_selinux_enabled()) + /* ignore the option if we running without selinux */ + return 0; + + if (optdata==NULL || *optdata=='\0' || optname==NULL) + return -1; + + /* TODO: use strip_quotes() for all mount options? */ + data = *optdata =='"' ? strip_quotes(optdata) : optdata; + + if (selinux_trans_to_raw_context( + (security_context_t) data, &raw)==-1 || + raw==NULL) + return -1; + + if (verbose) + printf(_("mount: translated %s '%s' to '%s'\n"), + optname, data, (char *) raw); + + *extra_opts = append_opt(*extra_opts, optname, NULL); + *extra_opts = xstrconcat4(*extra_opts, "\"", (char *) raw, "\""); + + freecon(raw); + return 0; +} +#endif + /* * Look for OPT in opt_map table and return mask value. * If OPT isn't found, tack it onto extra_opts (which is non-NULL). * For the options uid= and gid= replace user or group name by its value. */ static inline void -parse_opt(const char *opt, int *mask, char **extra_opts) { +parse_opt(char *opt, int *mask, char **extra_opts) { const struct opt_map *om; for (om = opt_map; om->opt != NULL; om++) @@ -348,6 +411,20 @@ parse_opt(const char *opt, int *mask, char **extra_opts) { } } +#ifdef HAVE_LIBSELINUX + if (strncmp(opt, "context=", 8) == 0 && *(opt+8)) { + if (append_context("context=", opt+8, extra_opts) == 0) + return; + } + if (strncmp(opt, "fscontext=", 10) == 0 && *(opt+10)) { + if (append_context("fscontext=", opt+10, extra_opts) == 0) + return; + } + if (strncmp(opt, "defcontext=", 11) == 0 && *(opt+11)) { + if (append_context("defcontext=", opt+11, extra_opts) == 0) + return; + } +#endif *extra_opts = append_opt(*extra_opts, opt, NULL); } @@ -362,12 +439,25 @@ parse_opts (const char *options, int *flags, char **extra_opts) { if (options != NULL) { char *opts = xstrdup(options); - char *opt; - - for (opt = strtok(opts, ","); opt; opt = strtok(NULL, ",")) - if (!parse_string_opt(opt)) - parse_opt(opt, flags, extra_opts); - + int open_quote = 0; + char *opt, *p; + + for (p=opts, opt=NULL; p && *p; p++) { + if (!opt) + opt = p; /* begin of the option item */ + if (*p == '"') + open_quote ^= 1; /* reverse the status */ + if (open_quote) + continue; /* still in quoted block */ + if (*p == ',') + *p = '\0'; /* terminate the option item */ + /* end of option item or last item */ + if (*p == '\0' || *(p+1) == '\0') { + if (!parse_string_opt(opt)) + parse_opt(opt, flags, extra_opts); + opt = NULL; + } + } free(opts); } @@ -490,8 +580,8 @@ do_mount_syscall (struct mountargs *args) { if ((flags & MS_MGC_MSK) == 0) flags |= MS_MGC_VAL; - mnt_debug(1, "mount(2) syscall: source=\"%s\" target=\"%s\" " - "filesystemtype=\"%s\" mountflags=%lu data=\"%s\"", + mnt_debug(1, "mount(2) syscall: source: \"%s\", target: \"%s\", " + "filesystemtype: \"%s\", mountflags: %lu, data: %s", args->spec, args->node, args->type, flags, (char *) args->data); ret = mount (args->spec, args->node, args->type, flags, args->data);