[CRIU] [PATCH 8/9] creds: restore -- Implement per-thread restore of credentials
Pavel Emelyanov
xemul at parallels.com
Fri Dec 18 06:14:34 PST 2015
> @@ -2823,6 +2756,175 @@ out:
> extern void __gcov_flush(void) __attribute__((weak));
> void __gcov_flush(void) {}
>
> +static void rst_reloc_creds(struct thread_restore_args *thread_args,
> + unsigned long *creds_pos_next)
> +{
> + struct thread_creds_args *args;
> +
> + if (unlikely(!*creds_pos_next))
> + return;
> +
> + args = rst_mem_remap_ptr(*creds_pos_next, RM_PRIVATE);
> +
> + if (args->lsm_profile)
> + args->lsm_profile = rst_mem_remap_ptr(args->mem_lsm_profile_pos, RM_PRIVATE);
> + if (args->groups)
> + args->groups = rst_mem_remap_ptr(args->mem_groups_pos, RM_PRIVATE);
> +
> + *creds_pos_next = args->mem_pos_next;
> + thread_args->creds_args = args;
> +}
> +
> +static struct thread_creds_args *
> +rst_prep_creds_args(struct thread_creds_args *prev, CredsEntry *ce)
> +{
> + unsigned long this_pos = rst_mem_cpos(RM_PRIVATE);
> + struct thread_creds_args *args;
> +
> + if (!verify_cap_size(ce)) {
> + pr_err("Caps size mismatch %d %d %d %d\n",
> + (int)ce->n_cap_inh, (int)ce->n_cap_eff,
> + (int)ce->n_cap_prm, (int)ce->n_cap_bnd);
> + return ERR_PTR(-EINVAL);
> + }
> +
> + if (!may_restore(ce))
> + return ERR_PTR(-EINVAL);
> +
> + args = rst_mem_alloc(sizeof(*args), RM_PRIVATE);
> + if (!args)
> + return ERR_PTR(-ENOMEM);
> +
> + args->cap_last_cap = kdat.last_cap;
This is per-thread constant, leave it on task_args.
> + memcpy(&args->creds, ce, sizeof(args->creds));
> +
> + if (ce->lsm_profile || opts.lsm_supplied) {
> + char *rendered, *profile;
> +
> + profile = ce->lsm_profile;
> + if (opts.lsm_supplied)
> + profile = opts.lsm_profile;
> +
> + if (validate_lsm(profile) < 0)
> + return ERR_PTR(-EINVAL);
> +
> + if (profile) {
> + size_t lsm_profile_len;
> +
> + if (render_lsm_profile(profile, &rendered))
> + return ERR_PTR(-EINVAL);
> +
> + args->mem_lsm_profile_pos = rst_mem_cpos(RM_PRIVATE);
> + lsm_profile_len = strlen(rendered);
> + args->lsm_profile = rst_mem_alloc(lsm_profile_len + 1, RM_PRIVATE);
> + if (!args->lsm_profile) {
> + xfree(rendered);
> + return ERR_PTR(-ENOMEM);
> + }
> +
> + strncpy(args->lsm_profile, rendered, lsm_profile_len);
> + xfree(rendered);
> + }
> + } else {
> + args->lsm_profile = NULL;
> + args->mem_lsm_profile_pos = 0;
> + }
> +
> + /*
> + * Zap fields which we cant use.
> + */
> + args->creds.cap_inh = NULL;
> + args->creds.cap_eff = NULL;
> + args->creds.cap_prm = NULL;
> + args->creds.cap_bnd = NULL;
> + args->creds.groups = NULL;
> + args->creds.lsm_profile = NULL;
> +
> + memcpy(args->cap_inh, ce->cap_inh, sizeof(args->cap_inh));
> + memcpy(args->cap_eff, ce->cap_eff, sizeof(args->cap_eff));
> + memcpy(args->cap_prm, ce->cap_prm, sizeof(args->cap_prm));
> + memcpy(args->cap_bnd, ce->cap_bnd, sizeof(args->cap_bnd));
> +
> + if (ce->n_groups) {
> + args->mem_groups_pos = rst_mem_cpos(RM_PRIVATE);
> + args->groups = rst_mem_alloc(ce->n_groups * sizeof(u32), RM_PRIVATE);
> + if (!args->groups)
> + return ERR_PTR(-ENOMEM);
> + memcpy(args->groups, ce->groups, ce->n_groups * sizeof(u32));
> + } else {
> + args->groups = NULL;
> + args->mem_groups_pos = 0;
> + }
> +
> + args->mem_pos_next = 0;
> +
> + if (prev)
> + prev->mem_pos_next = this_pos;
> + return args;
> +}
> +
> +static int rst_prep_creds(pid_t pid, CoreEntry *core, unsigned long *creds_pos)
> +{
> + size_t i;
> +
> + /*
> + * This is _really_ very old image
> + * format where @thread_core were not
> + * present. It means we don't have
> + * creds either, just ignore and exit
> + * early.
> + */
> + if (unlikely(!core->thread_core)) {
> + *creds_pos = 0;
> + return 0;
> + }
> +
> + *creds_pos = rst_mem_cpos(RM_PRIVATE);
> +
> + /*
> + * Old format: one Creds per task carried in own image file.
> + */
> + if (!core->thread_core->creds)
> + return rst_prep_creds_from_img(pid);
This would produce only one creds object at creds_cpos, while the loop
below would produce several of them. But the threads_args code ... more
below scans (should scan) creds_pos as array which would only work for
"new" case.
> +
> + for (i = 0; i < current->nr_threads; i++) {
> + CredsEntry *ce = current->core[i]->thread_core->creds;
> + struct thread_creds_args *args = NULL;
> +
> + args = rst_prep_creds_args(args, ce);
The args as a function argument is always NULL here, so it is in the legacy
function above. Is this intended behavior?
> + if (IS_ERR(args))
> + return PTR_ERR(args);
> + }
> +
> + return 0;
> +}
> +
> static int sigreturn_restore(pid_t pid, CoreEntry *core)
> {
> void *mem = MAP_FAILED;
> @@ -3124,6 +3184,7 @@ static int sigreturn_restore(pid_t pid, CoreEntry *core)
> * Fill up per-thread data.
> */
> for (i = 0; i < current->nr_threads; i++) {
> + unsigned long creds_pos_next = creds_pos;
> CoreEntry *tcore;
> struct rt_sigframe *sigframe;
>
> @@ -3157,6 +3218,8 @@ static int sigreturn_restore(pid_t pid, CoreEntry *core)
> thread_args[i].clear_tid_addr = CORE_THREAD_ARCH_INFO(tcore)->clear_tid_addr;
> core_get_tls(tcore, &thread_args[i].tls);
>
> + rst_reloc_creds(&thread_args[i], &creds_pos_next);
The creds_pos_next is write-only constant variable here. Why do threads get
different creds after all?
> +
> if (tcore->thread_core) {
> thread_args[i].has_futex = true;
> thread_args[i].futex_rla = tcore->thread_core->futex_rla;
> @@ -884,7 +895,7 @@ long __export_restore_task(struct task_restore_args *args)
> log_set_fd(args->logfd);
> log_set_loglevel(args->loglevel);
>
> - cap_last_cap = args->cap_last_cap;
> + cap_last_cap = args->t->creds_args->cap_last_cap;
The global cap_last_cap becomes unused after this patch.
>
> pr_info("Switched to the restorer %d\n", my_pid);
>
More information about the CRIU
mailing list