[systemd-devel] [PATCH] core: reuse the same /tmp and /var/tmp

Michal Sekletar msekleta at redhat.com
Fri Feb 1 07:09:57 PST 2013


All Execs within the service, will get mounted the same /tmp and /var/tmp
directories, if service is configured with PrivateTmp=yes. Temporary
directories are cleaned up by service itself, rather than relying on
systemd-tmpfiles.
---
 src/core/execute.c   |  30 +++++++++--
 src/core/execute.h   |   5 +-
 src/core/namespace.c | 137 +++++++++++++++++++++++++++++++++------------------
 src/core/namespace.h |   4 ++
 src/core/service.c   |   8 +++
 src/test/test-ns.c   |   7 ++-
 6 files changed, 138 insertions(+), 53 deletions(-)

diff --git a/src/core/execute.c b/src/core/execute.c
index 1413c91..c614754 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -983,7 +983,7 @@ static int apply_seccomp(uint32_t *syscall_filter) {
 
 int exec_spawn(ExecCommand *command,
                char **argv,
-               const ExecContext *context,
+               ExecContext *context,
                int fds[], unsigned n_fds,
                char **environment,
                bool apply_permissions,
@@ -1051,6 +1051,12 @@ int exec_spawn(ExecCommand *command,
 
         cgroup_attribute_apply_list(cgroup_attributes, cgroup_bondings);
 
+        if (context->private_tmp) {
+                r = setup_tmpdirs(context);
+                if (r < 0)
+                        return r;
+        }
+
         pid = fork();
         if (pid < 0)
                 return -errno;
@@ -1312,12 +1318,13 @@ int exec_spawn(ExecCommand *command,
                 if (strv_length(context->read_write_dirs) > 0 ||
                     strv_length(context->read_only_dirs) > 0 ||
                     strv_length(context->inaccessible_dirs) > 0 ||
-                    context->mount_flags != 0 ||
-                    context->private_tmp) {
+                    context->mount_flags != 0 ) {
                         err = setup_namespace(context->read_write_dirs,
                                               context->read_only_dirs,
                                               context->inaccessible_dirs,
                                               context->private_tmp,
+                                              context->tmp_dir,
+                                              context->var_tmp_dir,
                                               context->mount_flags);
                         if (err < 0) {
                                 r = EXIT_NAMESPACE;
@@ -1545,6 +1552,21 @@ void exec_context_init(ExecContext *c) {
         c->timer_slack_nsec = (nsec_t) -1;
 }
 
+void exec_context_tmpdirs_done(ExecContext *c) {
+        if (c->tmp_dir) {
+                rm_rf_dangerous(c->tmp_dir, false, true, false);
+                free(c->tmp_dir);
+                c->tmp_dir = NULL;
+        }
+
+        if (c->var_tmp_dir) {
+                rm_rf_dangerous(c->var_tmp_dir, false, true, false);
+                free(c->tmp_dir);
+                c->tmp_dir = NULL;
+        }
+
+}
+
 void exec_context_done(ExecContext *c) {
         unsigned l;
 
@@ -1609,6 +1631,8 @@ void exec_context_done(ExecContext *c) {
 
         free(c->syscall_filter);
         c->syscall_filter = NULL;
+
+        exec_context_tmpdirs_done(c);
 }
 
 void exec_command_done(ExecCommand *c) {
diff --git a/src/core/execute.h b/src/core/execute.h
index 2bcd2e1..ee74d24 100644
--- a/src/core/execute.h
+++ b/src/core/execute.h
@@ -141,6 +141,8 @@ struct ExecContext {
         bool non_blocking;
         bool private_tmp;
         bool private_network;
+        char *tmp_dir;
+        char *var_tmp_dir;
 
         bool no_new_privileges;
 
@@ -164,7 +166,7 @@ struct ExecContext {
 
 int exec_spawn(ExecCommand *command,
                char **argv,
-               const ExecContext *context,
+               ExecContext *context,
                int fds[], unsigned n_fds,
                char **environment,
                bool apply_permissions,
@@ -192,6 +194,7 @@ void exec_command_append_list(ExecCommand **l, ExecCommand *e);
 int exec_command_set(ExecCommand *c, const char *path, ...);
 
 void exec_context_init(ExecContext *c);
+void exec_context_tmpdirs_done(ExecContext *c);
 void exec_context_done(ExecContext *c);
 void exec_context_dump(ExecContext *c, FILE* f, const char *prefix);
 void exec_context_tty_reset(const ExecContext *context);
diff --git a/src/core/namespace.c b/src/core/namespace.c
index ba18ddc..6d44005 100644
--- a/src/core/namespace.c
+++ b/src/core/namespace.c
@@ -178,22 +178,104 @@ static int make_read_only(Path *p) {
         return 0;
 }
 
+int setup_tmpdirs(ExecContext *context) {
+        int r = 0;
+        bool remove_tmp = false, remove_var_tmp = false;
+        mode_t u;
+        char *d = NULL;
+        char tmp_dir[] = "/tmp/systemd-private-XXXXXX",
+             var_tmp_dir[] = "/var/tmp/systemd-private-XXXXXX";
+
+        assert(context);
+
+        if (!context->tmp_dir) {
+                d = mktemp(tmp_dir);
+                if (!d) {
+                        r = -errno;
+                        goto fail;
+                }
+
+                context->tmp_dir = strdup(d);
+                if (!context->tmp_dir) {
+                        r = log_oom();
+                        goto fail;
+                }
+
+                u = umask(0000);
+                r = mkdir(tmp_dir, 0777);
+                umask(u);
+                if (r < 0) {
+                        r = -errno;
+                        goto fail;
+                }
+                remove_tmp = true;
+
+                if (chmod(tmp_dir, 0777 | S_ISVTX) < 0) {
+                        r = -errno;
+                        goto fail;
+                }
+        }
+
+        if (!context->var_tmp_dir) {
+                d = mktemp(var_tmp_dir);
+                if (!d) {
+                        r = -errno;
+                        goto fail;
+                }
+
+                context->var_tmp_dir = strdup(d);
+                if (!context->var_tmp_dir) {
+                        r = log_oom();
+                        goto fail;
+                }
+
+                u = umask(0000);
+                r = mkdir(var_tmp_dir, 0777);
+                umask(u);
+                if (r < 0) {
+                        r = -errno;
+                        goto fail;
+                }
+                remove_var_tmp = true;
+
+                if (chmod(var_tmp_dir, 0777 | S_ISVTX) < 0) {
+                        r = -errno;
+                        goto fail;
+                }
+        }
+
+        return r;
+fail:
+        if (remove_tmp) {
+                free(context->tmp_dir);
+                context->tmp_dir = NULL;
+                rmdir(tmp_dir);
+        }
+
+        if (remove_var_tmp) {
+                free(context->var_tmp_dir);
+                context->var_tmp_dir = NULL;
+                rmdir(var_tmp_dir);
+        }
+
+        return r;
+}
+
 int setup_namespace(
                 char **writable,
                 char **readable,
                 char **inaccessible,
                 bool private_tmp,
+                char *tmp_dir,
+                char *var_tmp_dir,
                 unsigned long flags) {
 
-        char
-                tmp_dir[] = "/tmp/systemd-private-XXXXXX",
-                var_tmp_dir[] = "/var/tmp/systemd-private-XXXXXX",
-                inaccessible_dir[] = "/tmp/systemd-inaccessible-XXXXXX";
+        char inaccessible_dir[] = "/tmp/systemd-inaccessible-XXXXXX";
 
         Path *paths, *p;
         unsigned n;
         bool need_inaccessible = false;
-        bool remove_tmp = false, remove_var_tmp = false, remove_inaccessible = false;
+        bool remove_inaccessible = false;
         int r;
 
         if (!flags)
@@ -222,6 +304,8 @@ int setup_namespace(
         }
 
         assert(paths + n == p);
+        assert(tmp_dir);
+        assert(var_tmp_dir);
 
         qsort(paths, n, sizeof(Path), path_compare);
         drop_duplicates(paths, &n, &need_inaccessible);
@@ -242,43 +326,6 @@ int setup_namespace(
                 remove_inaccessible = true;
         }
 
-        if (private_tmp) {
-                mode_t u;
-                char *d;
-
-                u = umask(0000);
-                d = mkdtemp(tmp_dir);
-                umask(u);
-
-                if (!d) {
-                        r = -errno;
-                        goto fail;
-                }
-
-                remove_tmp = true;
-
-                u = umask(0000);
-                d = mkdtemp(var_tmp_dir);
-                umask(u);
-
-                if (!d) {
-                        r = -errno;
-                        goto fail;
-                }
-
-                remove_var_tmp = true;
-
-                if (chmod(tmp_dir, 0777 + S_ISVTX) < 0) {
-                        r = -errno;
-                        goto fail;
-                }
-
-                if (chmod(var_tmp_dir, 0777 + S_ISVTX) < 0) {
-                        r = -errno;
-                        goto fail;
-                }
-        }
-
         if (unshare(CLONE_NEWNS) < 0) {
                 r = -errno;
                 goto fail;
@@ -320,11 +367,5 @@ fail:
         if (remove_inaccessible)
                 rmdir(inaccessible_dir);
 
-        if (remove_tmp)
-                rmdir(tmp_dir);
-
-        if (remove_var_tmp)
-                rmdir(var_tmp_dir);
-
         return r;
 }
diff --git a/src/core/namespace.h b/src/core/namespace.h
index 5d72ed9..0b8028a 100644
--- a/src/core/namespace.h
+++ b/src/core/namespace.h
@@ -22,10 +22,14 @@
 ***/
 
 #include <stdbool.h>
+#include "execute.h"
 
+int setup_tmpdirs(ExecContext *context);
 int setup_namespace(
                 char **writable,
                 char **readable,
                 char **inaccessible,
                 bool private_tmp,
+                char *tmp_dir,
+                char *var_tmp_dir,
                 unsigned long flags);
diff --git a/src/core/service.c b/src/core/service.c
index 9141463..ed98e29 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -1872,6 +1872,12 @@ static int cgroup_good(Service *s) {
         return !r;
 }
 
+static void service_cleanup_tmpdirs(Service *s) {
+        assert(s);
+
+        exec_context_tmpdirs_done(&s->exec_context);
+}
+
 static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart) {
         int r;
         assert(s);
@@ -2519,6 +2525,8 @@ static int service_stop(Unit *u) {
                s->state == SERVICE_EXITED);
 
         service_enter_stop(s, SERVICE_SUCCESS);
+        service_cleanup_tmpdirs(s);
+
         return 0;
 }
 
diff --git a/src/test/test-ns.c b/src/test/test-ns.c
index b1c759f..72df9d4 100644
--- a/src/test/test-ns.c
+++ b/src/test/test-ns.c
@@ -47,8 +47,13 @@ int main(int argc, char *argv[]) {
         };
 
         int r;
+        char tmp_dir[] = "/tmp/systemd-private-XXXXXX",
+             var_tmp_dir[] = "/var/tmp/systemd-private-XXXXXX";
 
-        r = setup_namespace((char**) writable, (char**) readonly, (char**) inaccessible, true, 0);
+        mkdtemp(tmp_dir);
+        mkdtemp(var_tmp_dir);
+
+        r = setup_namespace((char**) writable, (char**) readonly, (char**) inaccessible, true, tmp_dir, var_tmp_dir, 0);
         if (r < 0) {
                 log_error("Failed to setup namespace: %s", strerror(-r));
                 return 1;
-- 
1.8.1



More information about the systemd-devel mailing list