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

Maciej Wereski m.wereski at partner.samsung.com
Mon Jun 17 07:27:02 PDT 2013


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.

To keep backwards compatibility Argument field is used. If word starts
with "xattr=", then it is cut out from Argument and parsed. There may be
many xattrs. Full format is:

xattr=name=value

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 - - - - xattr=security.SMACK64=printing
---
 man/tmpfiles.d.xml      |  22 ++++++-
 src/tmpfiles/tmpfiles.c | 158 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 179 insertions(+), 1 deletion(-)

diff --git a/man/tmpfiles.d.xml b/man/tmpfiles.d.xml
index 519f9bc..36021b1 100644
--- a/man/tmpfiles.d.xml
+++ b/man/tmpfiles.d.xml
@@ -309,6 +309,26 @@ L    /tmp/foobar -    -    -    -   /dev/null</programlisting>
                         a short string that is written to the file,
                         suffixed by a newline. Ignored for all other
                         lines.</para>
+
+                        <para>If <command>systemd-tmpfiles</command> was 
+                        compiled with extended attributes support, then 
+                        argument field can be used to set extended attributes. 
+                        Such argument should follow format:</para>
+
+                        <programlisting>xattr=<replaceable>name</replaceable>=<replaceable>value</replaceable></programlisting>
+
+                        <para>Where <replaceable>name</replaceable> is extended 
+                        attribute name and <replaceable>value</replaceable> is 
+                        value to  be set. If value contains spaces, it must be 
+                        between quotation marks. If value contains quotation 
+                        mark, which should be set, then it must be escaped with 
+                        backslash.</para>
+                        
+                        <para>Such special arguments are cut out and from argument
+                        field, so there's no influence on other meanigs of argument
+                        field.</para>
+
+                        <para>xattr= can be especially used to set SMACK security labels.</para>
                 </refsect2>
 
         </refsect1>
@@ -320,7 +340,7 @@ 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 xattr=user.owner="John Koval" xattr=security.SMACK64=screen</programlisting>
                 </example>
         </refsect1>
 
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
index f4885ec..9869e58 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"
@@ -83,6 +86,7 @@ typedef struct Item {
 
         char *path;
         char *argument;
+        char **xattrs;
         uid_t uid;
         gid_t gid;
         mode_t mode;
@@ -447,6 +451,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("lsetxattr(%s) failed: %m", path);
+                                free(value);
+                                return -errno;
+                        }
+                }
+                else if (setxattr(path, name, value, n+1, 0) < 0) {
+                        log_error("setxattr(%s) failed: %m", 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 +557,9 @@ static int write_one_file(Item *i, const char *path) {
         if (r < 0)
                 return r;
 
+        if (i->xattrs)
+                return item_set_xattrs(i, path);
+
         return 0;
 }
 
@@ -568,6 +621,13 @@ static int recursive_relabel_children(Item *i, const char *path) {
                         continue;
                 }
 
+                if (i->xattrs) {
+                        r = item_set_xattrs(i, entry_path);
+                        if (ret == 0 && r != -ENOENT)
+                                ret = r;
+                        continue;
+                }
+
                 if (is_dir) {
                         r = recursive_relabel_children(i, entry_path);
                         if (r < 0 && ret == 0)
@@ -674,6 +734,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 +767,11 @@ 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 +801,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 +854,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 +868,12 @@ static int create_item(Item *i) {
                 r = glob_item(i, item_set_perms);
                 if (r < 0)
                         return 0;
+
+                if (i->xattrs){
+                        r = glob_item(i, item_set_xattrs);
+                        if (r < 0)
+                                return r;
+                }
                 break;
 
         case RECURSIVE_RELABEL_PATH:
@@ -968,6 +1058,7 @@ static void item_free(Item *i) {
 
         free(i->path);
         free(i->argument);
+        strv_free(i->xattrs);
         free(i);
 }
 
@@ -1020,6 +1111,11 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
         char type;
         Hashmap *h;
         int r, n = -1;
+#ifdef HAVE_XATTR
+        char end;
+        char **f;
+        char *substr = NULL, *xattr = NULL, *tmp = NULL, *q = NULL;
+#endif
 
         assert(fname);
         assert(line >= 1);
@@ -1052,6 +1148,68 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
                 }
         }
 
+#ifdef HAVE_XATTR
+        if (i->argument) {
+                xattr = new0(char, strlen(i->argument)+1);
+                if (!xattr)
+                        return log_oom();
+
+                tmp = strstr(i->argument, "xattr=");
+                while (tmp) {
+                        substr = tmp;
+                        tmp += 6;
+                        q = strchr(tmp, '=');
+                        if (!q) {
+                                log_warning("Corrupted xattr: %s - ignoring.", tmp);
+                                tmp = strstr(tmp, "xattr=");
+                                continue;
+                        }
+                        ++q;
+                        if (q[0] == '\"')
+                                end = '\"';
+                        else
+                                end = ' ';
+                        r = 0;
+                        while(true){
+                                ++r;
+                                if (q[r] == end || (unsigned)r >= strlen(q)) {
+                                        if (end == '\"' && q[r-1] == '\\' && (unsigned)r != strlen(q))
+                                                continue;
+                                        break;
+                                }
+                        }
+                        q += r+1;
+                        xattr = strncpy(xattr, tmp, q-tmp);
+                        strstrip(xattr);
+                        q = strchr(xattr, ' ');
+                        if (q && end == ' ') {
+                                log_warning("Corrupted xattr: %s - ignoring.", xattr);
+                                bzero(xattr, strlen(xattr));
+                                tmp = strstr(tmp, "xattr");
+                                continue;
+                        }
+                        f = i->xattrs;
+                        i->xattrs = strv_append(i->xattrs, xattr);
+                        if (!i->xattrs) {
+                                free(xattr);
+                                strv_free(f);
+                                return log_oom();
+                        }
+                        n = strlen(xattr);
+                        memmove(substr, substr+n+6, strlen(substr)-n+1);
+                        bzero(xattr, strlen(xattr));
+                        tmp = strstr(i->argument, "xattr=");
+                }
+
+                free(xattr);
+                strstrip(i->argument);
+                if (!strlen(i->argument)) {
+                        free(i->argument);
+                        i->argument = NULL;
+                }
+        }
+#endif
+
         switch(type) {
 
         case CREATE_FILE:
-- 
1.8.3.1



More information about the systemd-devel mailing list