Skip to content

Commit

Permalink
caps: Relax migration requirements between different kernels.
Browse files Browse the repository at this point in the history
When restoring on a kernel that has different number of supported
capabilities than checkpoint one, check that the extra caps are unset.
If running unprivileged warn if the check fails, error out otherwise.

Signed-off-by: Michał Mirosław <[email protected]>
  • Loading branch information
osctobe committed Jun 21, 2023
1 parent f018893 commit 7a75bf5
Showing 1 changed file with 34 additions and 10 deletions.
44 changes: 34 additions & 10 deletions criu/cr-restore.c
Original file line number Diff line number Diff line change
Expand Up @@ -2940,12 +2940,6 @@ static int prepare_posix_timers(int pid, struct task_restore_args *ta, CoreEntry
return ret;
}

static inline int verify_cap_size(CredsEntry *ce)
{
return ((ce->n_cap_inh == CR_CAP_SIZE) && (ce->n_cap_eff == CR_CAP_SIZE) && (ce->n_cap_prm == CR_CAP_SIZE) &&
(ce->n_cap_bnd == CR_CAP_SIZE));
}

static int prepare_mm(pid_t pid, struct task_restore_args *args)
{
int exe_fd, i, ret = -1;
Expand Down Expand Up @@ -3360,10 +3354,35 @@ static bool groups_match(gid_t *groups, int n_groups)
return ret;
}

static int copy_caps(u32 *out_caps, u32 *in_caps, int n_words)
{
int last_cap = min(kdat.last_cap, 32 * CR_CAP_SIZE - 1);
int i;

for (i = last_cap + 1; i < 32 * n_words; ++i) {
if (~in_caps[i / 32] & (1 << (i % 32)))
continue;

if (!opts.unprivileged) {
pr_error("Can't restore capability %d > min(kernel=%d, criu=%d)", kdat.last_cap, 32 * CR_CAP_SIZE - 1);
return -EPERM;
}
pr_warn("Can't restore capability %d > min(kernel=%d, criu=%d)", kdat.last_cap, 32 * CR_CAP_SIZE - 1);
in_caps[i / 32] &= ~(1 << (i % 32));
}

n_words = min(n_word, (last_cap + 31) / 32);
memcpy(out_caps, in_caps, sizeof(*out_caps) * n_words);
memset(out_caps + n_words, 0, sizeof(*out_caps) * (CR_CAP_SIZE - n_words));

return 0;
}

static struct thread_creds_args *rst_prep_creds_args(CredsEntry *ce, unsigned long *prev_pos)
{
unsigned long this_pos;
struct thread_creds_args *args;
int err;

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,
Expand Down Expand Up @@ -3458,10 +3477,15 @@ static struct thread_creds_args *rst_prep_creds_args(CredsEntry *ce, unsigned lo
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));
err = copy_caps(args->cap_inh, ce->cap_inh, ce->n_cap_inh);
if (!err)
err = copy_caps(args->cap_eff, ce->cap_eff, ce->n_cap_eff);
if (!err)
err = copy_caps(args->cap_prm, ce->cap_prm, ce->n_cap_prm);
if (!err)
err = copy_caps(args->cap_bnd, ce->cap_bnd, ce->n_cap_bnd);
if (err)
return ERR_PTR(err);

if (ce->n_groups && !groups_match(ce->groups, ce->n_groups)) {
unsigned int *groups;
Expand Down

0 comments on commit 7a75bf5

Please sign in to comment.