[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