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; }