Context Mounts and Unsupported Contexts: util-linux
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
@@ -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, consif (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, chif (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 *flchar *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
@@ -756,12 +756,28 @@ parse_options(char *old_opts, struct nfschar *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 nfselse 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))