[systemd-devel] [PATCH v2] tmpfiles, man: Add xattr support to tmpfiles

Maciej Wereski m.wereski at partner.samsung.com
Fri Jul 5 08:33:43 PDT 2013


ping?

28.06.2013 at 17:39 Maciej Wereski <m.wereski at partner.samsung.com> wrote:

> This patch makes it possible to set extended attributes on files created
> by tmpfiles. This can be especially used to set SMACK security labels on
> volatile files and directories.
>
> It is done by adding new line of type "t". Such line should contain
> attributes in Argument field, using following format:
>
> name=value
>
> All other fields are ignored.
>
> If value contains spaces, then it must be surrounded by quotation marks.
> User can also put quotation mark in value by escaping it with backslash.
>
> Example:
> D /var/run/cups - - - -
> t /var/run/cups - - - - security.SMACK64=printing
> ---
> I've used "t" because IMHO "a" will be better for acl. To sum up: when
> "t" is met and it's not in hashmap, then it will be added. Then if other
> line for the same file appears, then it replaces SET_XATTR item in
> hashmap and has extended attributes added. If item earler existed in
> hashmap, then extended attributes are merged to existing entry. This
> means that there can be more than one "t" lines for one file. There is
> also posibility to have standalone "t" line. I hope that this is desired
> behaviour.
>
> regards,
> Maciej
> ---
>  man/tmpfiles.d.xml      |  26 ++++-
>  src/tmpfiles/tmpfiles.c | 274  
> ++++++++++++++++++++++++++++++++++++++++++++++--
>  2 files changed, 285 insertions(+), 15 deletions(-)
>
> diff --git a/man/tmpfiles.d.xml b/man/tmpfiles.d.xml
> index 519f9bc..92157b5 100644
> --- a/man/tmpfiles.d.xml
> +++ b/man/tmpfiles.d.xml
> @@ -229,6 +229,21 @@ L    /tmp/foobar -    -    -    -    
> /dev/null</programlisting>
>                                          place of normal path
>                                          names.</para></listitem>
>                                  </varlistentry>
> +
> +                                <varlistentry>
> +                                         
> <term><varname>t</varname></term>
> +                                        <listitem><para>Set extended
> +                                        attributes on item. It should be
> +                                        used with conjunction with other
> +                                        types (only d, D, f, F, L, p,  
> c, b, z
> +                                        makes sense). If used as a  
> standalone
> +                                        line, then  
> <command>systemd-tmpfiles
> +                                        </command> will try to set  
> extended
> +                                        attributes on specified path.
> +                                        This can be especially used to  
> set
> +                                        SMACK labels.
> +                                        </para></listitem>
> +                                </varlistentry>
>                          </variablelist>
>                  </refsect2>
> @@ -242,7 +257,7 @@ L    /tmp/foobar -    -    -    -    
> /dev/null</programlisting>
>                          objects. For z, Z lines if omitted or when set
>                          to - the file access mode will not be
>                          modified. This parameter is ignored for x, r,
> -                        R, L lines.</para>
> +                        R, L, t lines.</para>
>                  </refsect2>
>                 <refsect2>
> @@ -254,7 +269,7 @@ L    /tmp/foobar -    -    -    -    
> /dev/null</programlisting>
>                          omitted or when set to - the default 0 (root)
>                          is used. For z, Z lines when omitted or when  
> set to -
>                          the file ownership will not be modified.
> -                        These parameters are ignored for x, r, R, L  
> lines.</para>
> +                        These parameters are ignored for x, r, R, L, t  
> lines.</para>
>                  </refsect2>
>                 <refsect2>
> @@ -307,8 +322,10 @@ L    /tmp/foobar -    -    -    -    
> /dev/null</programlisting>
>                          minor formatted as integers, separated by :,
>                          e.g. "1:3". For f, F, w may be used to specify
>                          a short string that is written to the file,
> -                        suffixed by a newline. Ignored for all other
> +                        suffixed by a newline. Fot t determines extended
> +                        attributes to be set. Ignored for all other
>                          lines.</para>
> +
>                  </refsect2>
>         </refsect1>
> @@ -320,7 +337,8 @@ L    /tmp/foobar -    -    -    -    
> /dev/null</programlisting>
>                          <para><command>screen</command> needs two  
> directories created at boot with specific modes and ownership.</para>
>                         <programlisting>d /var/run/screens  1777 root  
> root 10d
> -d /var/run/uscreens 0755 root root 10d12h</programlisting>
> +d /var/run/uscreens 0755 root root 10d12h
> +t /var/run/screen - - - - user.name="John Koval"  
> security.SMACK64=screen</programlisting>
>                  </example>
>          </refsect1>
> diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
> index 555347a..098413f 100644
> --- a/src/tmpfiles/tmpfiles.c
> +++ b/src/tmpfiles/tmpfiles.c
> @@ -39,6 +39,9 @@
>  #include <glob.h>
>  #include <fnmatch.h>
>  #include <sys/capability.h>
> +#ifdef HAVE_XATTR
> +#include <attr/xattr.h>
> +#endif
> #include "log.h"
>  #include "util.h"
> @@ -75,7 +78,10 @@ typedef enum ItemType {
>          REMOVE_PATH = 'r',
>          RECURSIVE_REMOVE_PATH = 'R',
>          RELABEL_PATH = 'z',
> -        RECURSIVE_RELABEL_PATH = 'Z'
> +        RECURSIVE_RELABEL_PATH = 'Z',
> +
> +        /* These ones are options/additional operations */
> +        SET_XATTR = 't'
>  } ItemType;
> typedef struct Item {
> @@ -83,6 +89,7 @@ typedef struct Item {
>         char *path;
>          char *argument;
> +        char **xattrs;
>          uid_t uid;
>          gid_t gid;
>          mode_t mode;
> @@ -447,6 +454,52 @@ static int item_set_perms(Item *i, const char  
> *path) {
>          return label_fix(path, false, false);
>  }
> +static int item_set_xattrs(Item *i, const char *path) {
> +#ifdef HAVE_XATTR
> +        char *name, *value;
> +        char **x;
> +        int n;
> +        if (!i->xattrs)
> +                return 0;
> +        STRV_FOREACH(x, i->xattrs) {
> +                value = *x;
> +                name = strsep(&value, "=");
> +                if (name == NULL || value == NULL) {
> +                        log_warning("%s: %s is not valid xattr,  
> ignoring.", path, *x);
> +                        continue;
> +                }
> +                n = strlen(value);
> +                if (value[n-1]  == '\"')
> +                        value[n-1] = '\0';
> +                if (value[0] == '\"')
> +                        memmove(value, value+1, n);
> +                value = strreplace(value, "\\\"", "\"");
> +                if (!value)
> +                        return log_oom();
> +                n = strlen(value);
> +                if (i->type == CREATE_SYMLINK) {
> +                        if (lsetxattr(path, name, value, n+1, 0) < 0) {
> +                                log_error("Setting extended attribute  
> %s=%s on symlink %s failed: %m", name, value, path);
> +                                free(value);
> +                                return -errno;
> +                        }
> +                }
> +                else if (setxattr(path, name, value, n+1, 0) < 0) {
> +                        log_error("Setting extended attribute %s=%s on  
> %s failed: %m", name, value, path);
> +                        free(value);
> +                        return -errno;
> +                }
> +                free(value);
> +        }
> +        return 0;
> +#else
> +        (void)i;
> +        (void)path;
> +        log_error("Setting extended attributes requested, but tmpfiles  
> was compiled without XATTR support!");
> +        return -ENOTSUP;
> +#endif
> +}
> +
>  static int write_one_file(Item *i, const char *path) {
>          int r, e, fd, flags;
>          struct stat st;
> @@ -507,6 +560,12 @@ static int write_one_file(Item *i, const char  
> *path) {
>          if (r < 0)
>                  return r;
> +        if (i->xattrs) {
> +                r = item_set_xattrs(i, i->path);
> +                if (r < 0)
> +                        return r;
> +        }
> +
>          return 0;
>  }
> @@ -595,6 +654,72 @@ static int recursive_relabel(Item *i, const char  
> *path) {
>          return r;
>  }
> +#ifdef HAVE_XATTR
> +static int get_xattrs_from_arg(Item *i){
> +        _cleanup_free_ char *xattr = NULL;
> +        _cleanup_strv_free_ char **tmp = NULL;
> +        char *p;
> +        char **f;
> +        unsigned n, len;
> +
> +        assert(i);
> +        assert(i->type == SET_XATTR);
> +
> +        if (!i->argument) {
> +                log_error("%s: Argument can't be empty!", i->path);
> +                return -EBADMSG;
> +        }
> +
> +        xattr = new0(char, strlen(i->argument)+1);
> +        if (!xattr)
> +                return log_oom();
> +
> +        tmp = strv_split(i->argument, WHITESPACE);
> +        if (!tmp)
> +                return log_oom();
> +
> +        for (n = 0; n < strv_length(tmp); ++n) {
> +                len = strlen(tmp[n]);
> +                strncpy(xattr, tmp[n], len+1);
> +                p = strchr(xattr, '=');
> +                if (!p) {
> +                        log_error("%s: Attribute has incorrect  
> format.", i->path);
> +                        return -EBADMSG;
> +                }
> +                if (p[1] == '\"') {
> +                        while (true) {
> +                                if (!p)
> +                                        p = tmp[n];
> +                                else
> +                                        p += 2;
> +                                p = strchr(p, '\"');
> +                                if (p && xattr[p-xattr-1] != '\\')
> +                                        break;
> +                                p = NULL;
> +                                ++n;
> +                                if (n == strv_length(tmp))
> +                                        break;
> +                                len += strlen(tmp[n]) + 1;
> +                                strncat(xattr, " ", 1);
> +                                strncat(xattr, tmp[n], len);
> +                        }
> +                }
> +                strstrip(xattr);
> +                f = i->xattrs;
> +                i->xattrs = strv_append(i->xattrs, xattr);
> +                if (!i->xattrs){
> +                        strv_free(f);
> +                        return log_oom();
> +                }
> +        }
> +
> +        free(i->argument);
> +        i->argument = NULL;
> +
> +        return 0;
> +}
> +#endif
> +
>  static int glob_item(Item *i, int (*action)(Item *, const char *)) {
>          int r = 0, k;
>          _cleanup_globfree_ glob_t g = {};
> @@ -674,6 +799,12 @@ static int create_item(Item *i) {
>                  if (r < 0)
>                          return r;
> +                if (i->xattrs) {
> +                        r = item_set_xattrs(i, i->path);
> +                        if (r < 0)
> +                                return r;
> +                }
> +
>                  break;
>         case CREATE_FIFO:
> @@ -701,6 +832,12 @@ static int create_item(Item *i) {
>                  if (r < 0)
>                          return r;
> +                if (i->xattrs) {
> +                        r = item_set_xattrs(i, i->path);
> +                        if (r < 0)
> +                                return r;
> +                }
> +
>                  break;
>         case CREATE_SYMLINK: {
> @@ -730,6 +867,13 @@ static int create_item(Item *i) {
>                  }
>                 free(x);
> +
> +                if (i->xattrs) {
> +                        r = item_set_xattrs(i, i->path);
> +                        if (r < 0)
> +                                return r;
> +                }
> +
>                  break;
>          }
> @@ -776,6 +920,12 @@ static int create_item(Item *i) {
>                  if (r < 0)
>                          return r;
> +                if (i->xattrs) {
> +                        r = item_set_xattrs(i, i->path);
> +                        if (r < 0)
> +                                return r;
> +                }
> +
>                  break;
>          }
> @@ -784,6 +934,12 @@ static int create_item(Item *i) {
>                  r = glob_item(i, item_set_perms);
>                  if (r < 0)
>                          return r;
> +
> +                if (i->xattrs) {
> +                        r = glob_item(i, item_set_xattrs);
> +                        if (r < 0)
> +                                return r;
> +                }
>                  break;
>         case RECURSIVE_RELABEL_PATH:
> @@ -791,6 +947,15 @@ static int create_item(Item *i) {
>                  r = glob_item(i, recursive_relabel);
>                  if (r < 0)
>                          return r;
> +                break;
> +
> +        case SET_XATTR:
> +                r = get_xattrs_from_arg(i);
> +                if (r < 0)
> +                        return r;
> +                r = item_set_xattrs(i, i->path);
> +                if (r < 0)
> +                        return r;
>          }
>         log_debug("%s created successfully.", i->path);
> @@ -817,6 +982,7 @@ static int remove_item_instance(Item *i, const char  
> *instance) {
>          case RELABEL_PATH:
>          case RECURSIVE_RELABEL_PATH:
>          case WRITE_FILE:
> +        case SET_XATTR:
>                  break;
>         case REMOVE_PATH:
> @@ -862,6 +1028,7 @@ static int remove_item(Item *i) {
>          case RELABEL_PATH:
>          case RECURSIVE_RELABEL_PATH:
>          case WRITE_FILE:
> +        case SET_XATTR:
>                  break;
>         case REMOVE_PATH:
> @@ -924,6 +1091,53 @@ static int clean_item_instance(Item *i, const  
> char* instance) {
>          return r;
>  }
> +static int copy_item_contents(Item *dest, const Item *src) {
> +        assert(src);
> +        assert(dest);
> +
> +        if (dest == src)
> +                return 0;
> +
> +        dest->type =  src->type;
> +
> +        free(dest->path);
> +        dest->path = strdup(src->path);
> +        if (!dest->path)
> +                return -ENOMEM;
> +
> +        if (dest->argument) {
> +                free(dest->argument);
> +                dest->argument = NULL;
> +        }
> +        if (src->argument)
> +                dest->argument = strdup(src->argument);
> +        if (!dest->argument && src->argument)
> +                return -ENOMEM;
> +
> +        if (dest->xattrs) {
> +                strv_free(dest->xattrs);
> +                dest->xattrs = NULL;
> +        }
> +        if (src->xattrs)
> +                dest->xattrs = strv_copy(src->xattrs);
> +        if (!dest->xattrs && src->xattrs)
> +                return -ENOMEM;
> +
> +        dest->uid = src->uid;
> +        dest->gid = src->gid;
> +        dest->mode = src->mode;
> +        dest->age = src->age;
> +
> +        dest->uid_set = src->uid_set;
> +        dest->gid_set = src->gid_set;
> +        dest->mode_set = src->mode_set;
> +        dest->age_set = src->age_set;
> +
> +        dest->keep_first_level = src->keep_first_level;
> +
> +        return 0;
> +}
> +
>  static int clean_item(Item *i) {
>          int r = 0;
> @@ -968,6 +1182,7 @@ static void item_free(Item *i) {
>         free(i->path);
>          free(i->argument);
> +        strv_free(i->xattrs);
>          free(i);
>  }
> @@ -1099,6 +1314,13 @@ static int parse_line(const char *fname, unsigned  
> line, const char *buffer) {
>                  break;
>          }
> +        case SET_XATTR:
> +                if (!i->argument) {
> +                        log_error("[%s:%u] Set extended attribute  
> requires argument.", fname, line);
> +                        return -EBADMSG;
> +                }
> +                break;
> +
>          default:
>                  log_error("[%s:%u] Unknown file type '%c'.", fname,  
> line, type);
>                  return -EBADMSG;
> @@ -1176,17 +1398,47 @@ static int parse_line(const char *fname,  
> unsigned line, const char *buffer) {
>          existing = hashmap_get(h, i->path);
>          if (existing) {
> -                /* Two identical items are fine */
> -                if (!item_equal(existing, i))
> -                        log_warning("Two or more conflicting lines for  
> %s configured, ignoring.", i->path);
> -
> +                char **tmp;
> +
> +                if (i->type == SET_XATTR) {
> +                        r = get_xattrs_from_arg(i);
> +                        if (r < 0)
> +                                return r;
> +                        tmp = existing->xattrs;
> +                        existing->xattrs = strv_merge(existing->xattrs,  
> i->xattrs);
> +                        if (!existing->xattrs) {
> +                                strv_free(tmp);
> +                                strv_free(i->xattrs);
> +                                return log_oom();
> +                        }
> +                } else if (existing->type == SET_XATTR) {
> +                        r = get_xattrs_from_arg(existing);
> +                        if (r < 0)
> +                                return r;
> +                        tmp = existing->xattrs;
> +                        existing->xattrs = NULL;
> +                        r = copy_item_contents(existing, i);
> +                        if (r < 0)
> +                                return r;
> +                        existing->xattrs = strv_merge(existing->xattrs,  
> tmp);
> +                        if (!existing->xattrs){
> +                                strv_free(tmp);
> +                                return log_oom();
> +                        }
> +                } else {
> +                        /* Two identical items are fine */
> +                        if (!item_equal(existing, i))
> +                                log_warning("Two or more conflicting  
> lines for %s configured, ignoring.", i->path);
> +                        return 0;
> +                }
> +                strv_free(i->xattrs);
>                  return 0;
> -        }
> -
> -        r = hashmap_put(h, i->path, i);
> -        if (r < 0) {
> -                log_error("Failed to insert item %s: %s", i->path,  
> strerror(-r));
> -                return r;
> +        } else {
> +                r = hashmap_put(h, i->path, i);
> +                if (r < 0) {
> +                        log_error("Failed to insert item %s: %s",  
> i->path, strerror(-r));
> +                        return r;
> +                }
>          }
>         i = NULL; /* avoid cleanup */


-- 
Maciej Wereski
Samsung R&D Institute Poland
Samsung Electronics
m.wereski at partner.samsung.com


More information about the systemd-devel mailing list