diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 646300bdb8..ddca6b8ece 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -2992,6 +2992,7 @@ static struct thread_creds_args *rst_prep_creds_args(CredsEntry *ce, unsigned lo args->creds.cap_eff = NULL; args->creds.cap_prm = NULL; args->creds.cap_bnd = NULL; + args->creds.cap_amb = NULL; args->creds.groups = NULL; args->creds.lsm_profile = NULL; @@ -2999,6 +3000,7 @@ static struct thread_creds_args *rst_prep_creds_args(CredsEntry *ce, unsigned lo copy_caps(args->cap_eff, ce->cap_eff, ce->n_cap_eff); copy_caps(args->cap_prm, ce->cap_prm, ce->n_cap_prm); copy_caps(args->cap_bnd, ce->cap_bnd, ce->n_cap_bnd); + copy_caps(args->cap_amb, ce->cap_amb, ce->n_cap_amb); if (ce->n_groups && !groups_match(ce->groups, ce->n_groups)) { unsigned int *groups; diff --git a/criu/include/parasite.h b/criu/include/parasite.h index 1244220f67..b33d6710f8 100644 --- a/criu/include/parasite.h +++ b/criu/include/parasite.h @@ -148,6 +148,7 @@ struct parasite_dump_creds { u32 cap_prm[CR_CAP_SIZE]; u32 cap_eff[CR_CAP_SIZE]; u32 cap_bnd[CR_CAP_SIZE]; + u32 cap_amb[CR_CAP_SIZE]; int uids[4]; int gids[4]; diff --git a/criu/include/prctl.h b/criu/include/prctl.h index 4c2a548b16..77b149c77a 100644 --- a/criu/include/prctl.h +++ b/criu/include/prctl.h @@ -36,6 +36,15 @@ #ifndef PR_SET_NO_NEW_PRIVS #define PR_SET_NO_NEW_PRIVS 38 #endif +#ifndef PR_CAP_AMBIENT +#define PR_CAP_AMBIENT 47 +#endif +#ifndef PR_CAP_AMBIENT_IS_SET +#define PR_CAP_AMBIENT_IS_SET 1 +#endif +#ifndef PR_CAP_AMBIENT_RAISE +# define PR_CAP_AMBIENT_RAISE 2 +#endif #ifndef PR_SET_MM #define PR_SET_MM 35 diff --git a/criu/include/proc_parse.h b/criu/include/proc_parse.h index 0c334a190d..0bd79bf553 100644 --- a/criu/include/proc_parse.h +++ b/criu/include/proc_parse.h @@ -81,6 +81,7 @@ struct proc_status_creds { u32 cap_prm[PROC_CAP_SIZE]; u32 cap_eff[PROC_CAP_SIZE]; u32 cap_bnd[PROC_CAP_SIZE]; + u32 cap_amb[PROC_CAP_SIZE]; }; #define INVALID_UID ((uid_t)-1) diff --git a/criu/include/restorer.h b/criu/include/restorer.h index 3fb5322a4b..a4fb7ea794 100644 --- a/criu/include/restorer.h +++ b/criu/include/restorer.h @@ -75,6 +75,7 @@ struct thread_creds_args { u32 cap_prm[CR_CAP_SIZE]; u32 cap_eff[CR_CAP_SIZE]; u32 cap_bnd[CR_CAP_SIZE]; + u32 cap_amb[CR_CAP_SIZE]; char *lsm_profile; unsigned int *groups; diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index a88f8a66f2..6db9d21fee 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -103,16 +103,19 @@ static int alloc_groups_copy_creds(CredsEntry *ce, struct parasite_dump_creds *c BUILD_BUG_ON(sizeof(ce->cap_prm[0]) != sizeof(c->cap_prm[0])); BUILD_BUG_ON(sizeof(ce->cap_eff[0]) != sizeof(c->cap_eff[0])); BUILD_BUG_ON(sizeof(ce->cap_bnd[0]) != sizeof(c->cap_bnd[0])); + BUILD_BUG_ON(sizeof(ce->cap_amb[0]) != sizeof(c->cap_amb[0])); BUG_ON(ce->n_cap_inh != CR_CAP_SIZE); BUG_ON(ce->n_cap_prm != CR_CAP_SIZE); BUG_ON(ce->n_cap_eff != CR_CAP_SIZE); BUG_ON(ce->n_cap_bnd != CR_CAP_SIZE); + BUG_ON(ce->n_cap_amb != CR_CAP_SIZE); memcpy(ce->cap_inh, c->cap_inh, sizeof(c->cap_inh[0]) * CR_CAP_SIZE); memcpy(ce->cap_prm, c->cap_prm, sizeof(c->cap_prm[0]) * CR_CAP_SIZE); memcpy(ce->cap_eff, c->cap_eff, sizeof(c->cap_eff[0]) * CR_CAP_SIZE); memcpy(ce->cap_bnd, c->cap_bnd, sizeof(c->cap_bnd[0]) * CR_CAP_SIZE); + memcpy(ce->cap_amb, c->cap_amb, sizeof(c->cap_amb[0]) * CR_CAP_SIZE); if (c->no_new_privs > 0) { ce->no_new_privs = c->no_new_privs; diff --git a/criu/pie/parasite.c b/criu/pie/parasite.c index e151ed6563..1bc03dc2a0 100644 --- a/criu/pie/parasite.c +++ b/criu/pie/parasite.c @@ -324,6 +324,7 @@ static int dump_creds(struct parasite_dump_creds *args) args->cap_prm[i] = data[i].prm; args->cap_inh[i] = data[i].inh; args->cap_bnd[i] = 0; + args->cap_amb[i] = 0; for (j = 0; j < 32; j++) { if (j + i * 32 > args->cap_last_cap) @@ -336,6 +337,18 @@ static int dump_creds(struct parasite_dump_creds *args) if (ret) args->cap_bnd[i] |= (1 << j); } + + for (j = 0; j < 32; j++) { + if (j + i * 32 > args->cap_last_cap) + break; + ret = sys_prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, j + i * 32, 0, 0); + if (ret < 0) { + pr_err("Unable to read ambient capability %d: %d\n", j + i * 32, ret); + return -1; + } + if (ret) + args->cap_amb[i] |= (1 << j); + } } args->no_new_privs = sys_prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0); diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 51ed6ed4c8..c567008926 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -347,6 +347,21 @@ static int restore_creds(struct thread_creds_args *args, int procfd, int lsm_typ return -1; } + for (b = 0; b < CR_CAP_SIZE; b++) { + for (i = 0; i < 32; i++) { + if (b * 32 + i > args->cap_last_cap) + break; + if ((args->cap_amb[b] & (1 << i)) == 0) + /* don't set */ + continue; + ret = sys_prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, i + b * 32, 0, 0); + if (!ret) + continue; + pr_warn("Unable to raise ambient capability %d: %d\n", i + b * 32, ret); + } + } + + if (lsm_type != LSMTYPE__SELINUX) { /* * SELinux does not support setting the process context for diff --git a/criu/proc_parse.c b/criu/proc_parse.c index 6c4303e7dd..0fa9b7ba56 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -1071,7 +1071,7 @@ int parse_pid_status(pid_t pid, struct seize_task_status *ss, void *data) if (bfdopenr(&f)) return -1; - while (done < 13) { + while (done < 14) { str = breadline(&f); if (str == NULL) break; @@ -1155,6 +1155,13 @@ int parse_pid_status(pid_t pid, struct seize_task_status *ss, void *data) continue; } + if (!strncmp(str, "CapAmb:", 7)) { + if (cap_parse(str + 8, cr->cap_amb)) + goto err_parse; + done++; + continue; + } + if (!strncmp(str, "Seccomp:", 8)) { if (sscanf(str + 9, "%d", &cr->s.seccomp_mode) != 1) { goto err_parse; @@ -1198,7 +1205,7 @@ int parse_pid_status(pid_t pid, struct seize_task_status *ss, void *data) } /* seccomp and nspids are optional */ - expected_done = (parsed_seccomp ? 12 : 11); + expected_done = (parsed_seccomp ? 13 : 12); if (kdat.has_nspid) expected_done++; if (done == expected_done) diff --git a/criu/pstree.c b/criu/pstree.c index 8c44e71343..41df846eda 100644 --- a/criu/pstree.c +++ b/criu/pstree.c @@ -63,6 +63,7 @@ CoreEntry *core_entry_alloc(int th, int tsk) sz += CR_CAP_SIZE * sizeof(ce->cap_prm[0]); sz += CR_CAP_SIZE * sizeof(ce->cap_eff[0]); sz += CR_CAP_SIZE * sizeof(ce->cap_bnd[0]); + sz += CR_CAP_SIZE * sizeof(ce->cap_amb[0]); /* * @groups are dynamic and allocated * on demand. @@ -122,10 +123,12 @@ CoreEntry *core_entry_alloc(int th, int tsk) ce->n_cap_prm = CR_CAP_SIZE; ce->n_cap_eff = CR_CAP_SIZE; ce->n_cap_bnd = CR_CAP_SIZE; + ce->n_cap_amb = CR_CAP_SIZE; ce->cap_inh = xptr_pull_s(&m, CR_CAP_SIZE * sizeof(ce->cap_inh[0])); ce->cap_prm = xptr_pull_s(&m, CR_CAP_SIZE * sizeof(ce->cap_prm[0])); ce->cap_eff = xptr_pull_s(&m, CR_CAP_SIZE * sizeof(ce->cap_eff[0])); ce->cap_bnd = xptr_pull_s(&m, CR_CAP_SIZE * sizeof(ce->cap_bnd[0])); + ce->cap_amb = xptr_pull_s(&m, CR_CAP_SIZE * sizeof(ce->cap_amb[0])); if (arch_alloc_thread_info(core)) { xfree(core); diff --git a/images/creds.proto b/images/creds.proto index 220ed38587..932a40ccff 100644 --- a/images/creds.proto +++ b/images/creds.proto @@ -25,4 +25,6 @@ message creds_entry { optional string lsm_sockcreate = 16; optional bytes apparmor_data = 17; optional uint32 no_new_privs = 18; + + repeated uint32 cap_amb = 19; }