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