803fb7
From fd09d69b1bca2b4b602f4ee98d4749a39af04bb4 Mon Sep 17 00:00:00 2001
803fb7
From: Lennart Poettering <lennart@poettering.net>
803fb7
Date: Fri, 10 Apr 2015 16:22:22 +0200
803fb7
Subject: [PATCH] tmpfiles: enforce ordering when executing lines
803fb7
803fb7
Always create files first, and then adjust their ACLs, xattrs, file
803fb7
attributes, never the opposite. Previously the order was not
803fb7
deterministic, thus possibly first adjusting ACLs/xattrs/file
803fb7
attributes before actually creating the items.
803fb7
803fb7
Cherry-picked from: 17493fa5d17cadce3b773692d3eeab137de7d323
803fb7
Resolves: #1365870
803fb7
---
803fb7
 src/tmpfiles/tmpfiles.c | 39 +++++++++++++++++++++++++++++++++++----
803fb7
 1 file changed, 35 insertions(+), 4 deletions(-)
803fb7
803fb7
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
803fb7
index 64c733aaa..bda89df5b 100644
803fb7
--- a/src/tmpfiles/tmpfiles.c
803fb7
+++ b/src/tmpfiles/tmpfiles.c
803fb7
@@ -78,18 +78,18 @@ typedef enum ItemType {
803fb7
         COPY_FILES = 'C',
803fb7
 
803fb7
         /* These ones take globs */
803fb7
+        WRITE_FILE = 'w',
803fb7
         SET_XATTR = 't',
803fb7
         RECURSIVE_SET_XATTR = 'T',
803fb7
         SET_ACL = 'a',
803fb7
         RECURSIVE_SET_ACL = 'A',
803fb7
-        WRITE_FILE = 'w',
803fb7
         IGNORE_PATH = 'x',
803fb7
         IGNORE_DIRECTORY_PATH = 'X',
803fb7
         REMOVE_PATH = 'r',
803fb7
         RECURSIVE_REMOVE_PATH = 'R',
803fb7
-        ADJUST_MODE = 'm', /* legacy, 'z' is identical to this */
803fb7
         RELABEL_PATH = 'z',
803fb7
         RECURSIVE_RELABEL_PATH = 'Z',
803fb7
+        ADJUST_MODE = 'm', /* legacy, 'z' is identical to this */
803fb7
 } ItemType;
803fb7
 
803fb7
 typedef struct Item {
803fb7
@@ -1480,6 +1480,31 @@ static void item_array_free(ItemArray *a) {
803fb7
         free(a);
803fb7
 }
803fb7
 
803fb7
+static int item_compare(const void *a, const void *b) {
803fb7
+        const Item *x = a, *y = b;
803fb7
+
803fb7
+        /* Make sure that the ownership taking item is put first, so
803fb7
+         * that we first create the node, and then can adjust it */
803fb7
+
803fb7
+        if (takes_ownership(x->type) && !takes_ownership(y->type))
803fb7
+                return -1;
803fb7
+        if (!takes_ownership(x->type) && takes_ownership(y->type))
803fb7
+                return 1;
803fb7
+
803fb7
+        return (int) x->type - (int) y->type;
803fb7
+}
803fb7
+
803fb7
+static void item_array_sort(ItemArray *a) {
803fb7
+
803fb7
+        /* Sort an item array, to enforce stable ordering in which we
803fb7
+         * apply things. */
803fb7
+
803fb7
+        if (a->count <= 1)
803fb7
+                return;
803fb7
+
803fb7
+        qsort(a->items, a->count, sizeof(Item), item_compare);
803fb7
+}
803fb7
+
803fb7
 static bool item_compatible(Item *a, Item *b) {
803fb7
         assert(a);
803fb7
         assert(b);
803fb7
@@ -1806,6 +1831,8 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
803fb7
                 return log_oom();
803fb7
 
803fb7
         memcpy(existing->items + existing->count++, &i, sizeof(i));
803fb7
+        item_array_sort(existing);
803fb7
+
803fb7
         zero(i);
803fb7
         return 0;
803fb7
 }
803fb7
@@ -2045,13 +2072,17 @@ int main(int argc, char *argv[]) {
803fb7
                 }
803fb7
         }
803fb7
 
803fb7
-        HASHMAP_FOREACH(a, globs, iterator) {
803fb7
+        /* The non-globbing ones usually create things, hence we apply
803fb7
+         * them first */
803fb7
+        HASHMAP_FOREACH(a, items, iterator) {
803fb7
                 k = process_item_array(a);
803fb7
                 if (k < 0 && r == 0)
803fb7
                         r = k;
803fb7
         }
803fb7
 
803fb7
-        HASHMAP_FOREACH(a, items, iterator) {
803fb7
+        /* The globbing ones usually alter things, hence we apply them
803fb7
+         * second. */
803fb7
+        HASHMAP_FOREACH(a, globs, iterator) {
803fb7
                 k = process_item_array(a);
803fb7
                 if (k < 0 && r == 0)
803fb7
                         r = k;