[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