From ae2ab5ddadc24c06c12c545f1160086713f78f59 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 2 May 2019 13:41:46 +0000 Subject: [PATCH] lsm: also dump and restore sockcreate The file /proc/PID/attr/sockcreate is used by SELinux to label newly created sockets with the label available at sockcreate. If it is NULL, the default label of the process will be used. This reads out that file during checkpoint and restores the value during restore. This value is irrelevant for existing sockets as they might have been created with another context. This is only to make sure that newly created sockets have the correct context. Signed-off-by: Adrian Reber --- criu/cr-restore.c | 36 ++++++++++++++++++++++++++++++++++++ criu/include/restorer.h | 2 ++ criu/lsm.c | 32 ++++++++++++++++++++++++++++++++ criu/pie/restorer.c | 15 ++++++++++----- images/creds.proto | 1 + 5 files changed, 81 insertions(+), 5 deletions(-) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index a7b121b8c..7933fe37b 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -2994,6 +2994,8 @@ static void rst_reloc_creds(struct thread_restore_args *thread_args, if (args->lsm_profile) args->lsm_profile = rst_mem_remap_ptr(args->mem_lsm_profile_pos, RM_PRIVATE); + if (args->lsm_sockcreate) + args->lsm_sockcreate = rst_mem_remap_ptr(args->mem_lsm_sockcreate_pos, RM_PRIVATE); if (args->groups) args->groups = rst_mem_remap_ptr(args->mem_groups_pos, RM_PRIVATE); @@ -3059,6 +3061,40 @@ rst_prep_creds_args(CredsEntry *ce, unsigned long *prev_pos) args->mem_lsm_profile_pos = 0; } + if (ce->lsm_sockcreate) { + char *rendered = NULL; + char *profile; + + profile = ce->lsm_sockcreate; + + if (validate_lsm(profile) < 0) + return ERR_PTR(-EINVAL); + + if (profile && render_lsm_profile(profile, &rendered)) { + return ERR_PTR(-EINVAL); + } + if (rendered) { + size_t lsm_sockcreate_len; + char *lsm_sockcreate; + + args->mem_lsm_sockcreate_pos = rst_mem_align_cpos(RM_PRIVATE); + lsm_sockcreate_len = strlen(rendered); + lsm_sockcreate = rst_mem_alloc(lsm_sockcreate_len + 1, RM_PRIVATE); + if (!lsm_sockcreate) { + xfree(rendered); + return ERR_PTR(-ENOMEM); + } + + args = rst_mem_remap_ptr(this_pos, RM_PRIVATE); + args->lsm_sockcreate = lsm_sockcreate; + strncpy(args->lsm_sockcreate, rendered, lsm_sockcreate_len); + xfree(rendered); + } + } else { + args->lsm_sockcreate = NULL; + args->mem_lsm_sockcreate_pos = 0; + } + /* * Zap fields which we can't use. */ diff --git a/criu/include/restorer.h b/criu/include/restorer.h index 2884ce9e6..b83e9130c 100644 --- a/criu/include/restorer.h +++ b/criu/include/restorer.h @@ -69,8 +69,10 @@ struct thread_creds_args { unsigned int secbits; char *lsm_profile; unsigned int *groups; + char *lsm_sockcreate; unsigned long mem_lsm_profile_pos; + unsigned long mem_lsm_sockcreate_pos; unsigned long mem_groups_pos; unsigned long mem_pos_next; diff --git a/criu/lsm.c b/criu/lsm.c index 849ec37cd..b0ef0c396 100644 --- a/criu/lsm.c +++ b/criu/lsm.c @@ -98,6 +98,32 @@ err: freecon(ctx); return ret; } + +/* + * selinux_get_sockcreate_label reads /proc/PID/attr/sockcreate + * to see if the PID has a special label specified for sockets. + * Most of the time this will be empty and the process will use + * the process context also for sockets. + */ +static int selinux_get_sockcreate_label(pid_t pid, char **output) +{ + FILE *f; + + f = fopen_proc(pid, "attr/sockcreate"); + if (!f) + return -1; + + fscanf(f, "%ms", output); + /* + * No need to check the result of fscanf(). If there is something + * in /proc/PID/attr/sockcreate it will be copied to *output. If + * there is nothing it will stay NULL. So whatever fscanf() does + * it should be correct. + */ + + fclose(f); + return 0; +} #endif void kerndat_lsm(void) @@ -132,6 +158,7 @@ int collect_lsm_profile(pid_t pid, CredsEntry *ce) int ret; ce->lsm_profile = NULL; + ce->lsm_sockcreate = NULL; switch (kdat.lsm) { case LSMTYPE__NO_LSM: @@ -143,6 +170,9 @@ int collect_lsm_profile(pid_t pid, CredsEntry *ce) #ifdef CONFIG_HAS_SELINUX case LSMTYPE__SELINUX: ret = selinux_get_label(pid, &ce->lsm_profile); + if (ret) + break; + ret = selinux_get_sockcreate_label(pid, &ce->lsm_sockcreate); break; #endif default: @@ -153,6 +183,8 @@ int collect_lsm_profile(pid_t pid, CredsEntry *ce) if (ce->lsm_profile) pr_info("%d has lsm profile %s\n", pid, ce->lsm_profile); + if (ce->lsm_sockcreate) + pr_info("%d has lsm sockcreate label %s\n", pid, ce->lsm_sockcreate); return ret; } diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 6e18cc260..4f42605a0 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -149,7 +149,7 @@ static void sigchld_handler(int signal, siginfo_t *siginfo, void *data) sys_exit_group(1); } -static int lsm_set_label(char *label, int procfd) +static int lsm_set_label(char *label, char *type, int procfd) { int ret = -1, len, lsmfd; char path[STD_LOG_SIMPLE_CHUNK]; @@ -157,9 +157,9 @@ static int lsm_set_label(char *label, int procfd) if (!label) return 0; - pr_info("restoring lsm profile %s\n", label); + pr_info("restoring lsm profile (%s) %s\n", type, label); - std_sprintf(path, "self/task/%ld/attr/current", sys_gettid()); + std_sprintf(path, "self/task/%ld/attr/%s", sys_gettid(), type); lsmfd = sys_openat(procfd, path, O_WRONLY, 0); if (lsmfd < 0) { @@ -305,9 +305,14 @@ static int restore_creds(struct thread_creds_args *args, int procfd, * SELinux and instead the process context is set before the * threads are created. */ - if (lsm_set_label(args->lsm_profile, procfd) < 0) + if (lsm_set_label(args->lsm_profile, "current", procfd) < 0) return -1; } + + /* Also set the sockcreate label for all threads */ + if (lsm_set_label(args->lsm_sockcreate, "sockcreate", procfd) < 0) + return -1; + return 0; } @@ -1571,7 +1576,7 @@ long __export_restore_task(struct task_restore_args *args) if (args->lsm_type == LSMTYPE__SELINUX) { /* Only for SELinux */ if (lsm_set_label(args->t->creds_args->lsm_profile, - args->proc_fd) < 0) + "current", args->proc_fd) < 0) goto core_restore_end; } diff --git a/images/creds.proto b/images/creds.proto index 29fb8652e..23b84c7e5 100644 --- a/images/creds.proto +++ b/images/creds.proto @@ -20,4 +20,5 @@ message creds_entry { repeated uint32 groups = 14; optional string lsm_profile = 15; + optional string lsm_sockcreate = 16; }