Skip to contentSkip to conversation

Context Mounts and Unsupported Contexts: util-linux

RFC PATCH In review Cory Olmo 1 participant 1 message Aug 15, 2006 SELinux security module

lore
Share & tools
lore

Cory Olmo

author
#0 lore raw

RFC PATCH 2/3 Context Mounts and Unsupported Contexts: util-linux

This patch modifies the option parsing in parse_opts(), contained in mount.c, and parse_options(), contained in nfsmount.c, to take options after finding a comma only if it hasn't seen a quote or if the quotes are matched. It also will strip the quotes from the context option prior to translation and then replace them after the translation.

There's an unrelated update in the patch for parse_opt() which includes the latest rootcontext option.

 util-linux/mount/mount.c    |   81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
 util-linux/mount/nfsmount.c |   34 +++++++++++++++++++++++--
 2 files changed, 103 insertions(+), 12 deletions(-)
mount/mount.c +72 -9
index dbbb92e..49a6c38 100644
@@ -265,6 +265,32 @@ my_free(const void *s) {
 }
 
 #ifdef HAVE_LIBSELINUX
+/* strip quotes from a context string
+ * returns Null on error and char * to new string
+ * caller responsible for freeing returned memory
+ */
+static char *
+strip_quotes(const char *opt_str)
+{
+	char *new_str = NULL;
+	char *str_end = NULL;
+
+	if (*opt_str != '\"') {
+		new_str = xstrdup(opt_str);
+		return new_str;
+	}
+
+	str_end = rindex(opt_str, '\"');
+	if (!str_end || str_end == opt_str) {
+		printf(_("mount: improperly quoted context string '%s'\n"), 
+			opt_str);
+		return NULL;
+	}
+
+	new_str = xstrndup(opt_str+1, str_end - (opt_str+1));
+	return new_str;
+}
+
 /* translates SELinux context from human to raw format and 
  * appends it to the mount extra options.
  *
@@ -274,6 +300,7 @@ static int
 append_context(const char *optname, const char *optdata, char *extra_opts, int *len)
 {
 	security_context_t raw = NULL;
+	char *stripped_data = NULL;
 	char *buf = NULL;
 	int bufsz;
 	
@@ -284,19 +311,32 @@ append_context(const char *optname, cons
 	if (optdata==NULL || *optdata=='\0' || optname==NULL)
 		return -1;
 	
-	if (selinux_trans_to_raw_context(
-			(security_context_t) optdata, &raw)==-1 ||
-			raw==NULL)
-		return -1;
+	if (*optdata =='\"') {
+		stripped_data = strip_quotes(optdata);
+		if (!stripped_data) 
+			return -1;
+		if (selinux_trans_to_raw_context(
+				(security_context_t) stripped_data, &raw)==-1 ||
+				raw==NULL) {
+			my_free(stripped_data);
+			return -1;
+		}
+		my_free(stripped_data);
+	} else {
+		if (selinux_trans_to_raw_context(
+				(security_context_t) optdata, &raw)==-1 ||
+				raw==NULL)
+			return -1;
+	}
 	
 	if (verbose)
 		printf(_("mount: translated %s '%s' to '%s'\n"), 
 				optname, optdata, (char *) raw);
 
-	bufsz = strlen(optname) + strlen(raw) + 2;	/* 2 is \0 and '=' */ 
+	bufsz = strlen(optname) + strlen(raw) + 2 + 2;	/* 2 is \0 and '=' */ 
 	buf = xmalloc(bufsz);
 
-	snprintf(buf, bufsz, "%s=%s", optname, (char *) raw);
+	snprintf(buf, bufsz, "%s=\"%s\"", optname, (char *) raw);
 	freecon(raw);
 	
 	if ((*len -= bufsz-1) > 0)
@@ -378,6 +418,10 @@ parse_opt(const char *opt, int *mask, ch
 		if (append_context("defcontext", opt+11, extra_opts, &len)==0)
 			return;
 	}
+	if (strncmp(opt, "rootcontext=", 12)==0 && *(opt+12)) {
+		if (append_context("rootcontext", opt+12, extra_opts, &len)==0)
+			return;
+	}
 #endif
 	if ((len -= strlen(opt)) > 0)
 		strcat(extra_opts, opt);
@@ -396,13 +440,32 @@ parse_opts (const char *options, int *fl
 		char *opts = xstrdup(options);
 		char *opt;
 		int len = strlen(opts) + 256;
+		int open_quote = 0;
+		char *opt_start = NULL;
+		char *opt_end = NULL;
 
 		*extra_opts = xmalloc(len); 
 		**extra_opts = '\0';
 
-		for (opt = strtok(opts, ","); opt; opt = strtok(NULL, ","))
-			if (!parse_string_opt(opt))
-				parse_opt(opt, flags, *extra_opts, len);
+		opt_start = opt_end = opts;
+		do {
+			if ((*opt_end == '"')) {
+				if (open_quote < 0)
+					open_quote += 1;
+				else
+					open_quote -= 1;
+			}
+			if (((*opt_end == ',') && (open_quote == 0)) ||
+					*opt_end == '\0') {
+				opt = xstrndup(opt_start, opt_end - opt_start);
+				if (!parse_string_opt(opt))
+					parse_opt(opt, flags, *extra_opts, len);
+				opt_start = opt_end + 1;
+				free(opt);
+				opt = NULL;
+			}
+		} while (*opt_end++);
+
 
 		free(opts);
 	}
mount/nfsmount.c +31 -3
index 362ef33..783994e 100644
@@ -756,12 +756,28 @@ parse_options(char *old_opts, struct nfs
 	char *opt, *opteq;
 	char *mounthost = NULL;
 	char cbuf[128];
+	char *opt_start, *opt_end;
+	int open_quote = 0;
 
 	data->flags = 0;
 	*bg = 0;
 
 	len = strlen(new_opts);
-	for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) {
+	opt_start = opt_end = old_opts;
+	do {
+		if ((*opt_end == '"')) {
+			if (open_quote < 0)
+				open_quote += 1;
+			else
+				open_quote -= 1;
+		}
+		if (!(((*opt_end == ',') && (open_quote == 0)) ||
+				*opt_end == '\0')) {
+			continue;
+		}
+		opt = xstrndup(opt_start, opt_end - opt_start);
+		opt_start = opt_end + 1;
+
 		if (strlen(opt) >= sizeof(cbuf))
 			goto bad_parameter;
 		if ((opteq = strchr(opt, '=')) && isdigit(opteq[1])) {
@@ -877,12 +893,22 @@ parse_options(char *old_opts, struct nfs
 			 else if (!strcmp(opt, "context")) {
  				char *context = opteq + 1;
  				
+				/* XXX: The size of cbuf would have to be
+				 * more than doubled or NFS_MAX_CONTEXT_LEN
+				 * reduced to <128 before this would ever be 
+				 * a factor.
+				 */
  				if (strlen(context) > NFS_MAX_CONTEXT_LEN) {
  					printf(_("context parameter exceeds limit of %d\n"),
  						 NFS_MAX_CONTEXT_LEN);
 					goto bad_parameter;
  				}
- 				strncpy(data->context, context, NFS_MAX_CONTEXT_LEN);
+				/* The context string is in the format of
+				 * "system_u:object_r:...". We only want 
+				 * the context str between the quotes.
+				 */
+ 				strncpy(data->context, context+1, 
+						strlen(context)-2);
  			} else if (!sloppy)
 				goto bad_parameter;
 			sprintf(cbuf, "%s=%s,", opt, opteq+1);
@@ -988,7 +1014,9 @@ parse_options(char *old_opts, struct nfs
 			goto out_bad;
 		}
 		strcat(new_opts, cbuf);
-	}
+		free(opt);
+		opt = NULL;
+	} while (*opt_end++);
 	/* See if the nfs host = mount host. */
 	if (mounthost) {
 		if (!nfs_gethostbyname(mounthost, mnt_saddr))