diff --git a/arch/arm/syscall.def b/arch/arm/syscall.def index c539e3e14..02eaa65bc 100644 --- a/arch/arm/syscall.def +++ b/arch/arm/syscall.def @@ -59,6 +59,7 @@ getpgid 155 132 (pid_t pid) setfsuid 151 138 (int fsuid) setfsgid 152 139 (int fsgid) getsid 156 147 (void) +capget 90 184 (struct cap_header *h, struct cap_data *d) capset 91 185 (struct cap_header *h, struct cap_data *d) rt_sigqueueinfo 138 178 (pid_t pid, int sig, siginfo_t *info) setpriority 140 97 (int which, int who, int nice) diff --git a/arch/x86/syscall-x86-64.def b/arch/x86/syscall-x86-64.def index 878cf7996..ec86dfe5e 100644 --- a/arch/x86/syscall-x86-64.def +++ b/arch/x86/syscall-x86-64.def @@ -59,6 +59,7 @@ __NR_getpgid 121 sys_getpgid (pid_t pid) __NR_setfsuid 122 sys_setfsuid (int fsuid) __NR_setfsgid 123 sys_setfsgid (int fsgid) __NR_getsid 124 sys_getsid (void) +__NR_capget 125 sys_capget (struct cap_header *h, struct cap_data *d) __NR_capset 126 sys_capset (struct cap_header *h, struct cap_data *d) __NR_rt_sigqueueinfo 129 sys_rt_sigqueueinfo (pid_t pid, int sig, siginfo_t *info) __NR_sigaltstack 131 sys_sigaltstack (const void *uss, void *uoss) diff --git a/cr-dump.c b/cr-dump.c index 1700d9dc0..f52af6539 100644 --- a/cr-dump.c +++ b/cr-dump.c @@ -502,10 +502,6 @@ static int dump_task_creds(struct parasite_ctl *ctl, { CredsEntry ce = CREDS_ENTRY__INIT; - pr_info("\n"); - pr_info("Dumping creds for %d)\n", ctl->pid.real); - pr_info("----------------------------------------\n"); - ce.uid = cr->uids[0]; ce.gid = cr->gids[0]; ce.euid = cr->uids[1]; @@ -515,16 +511,9 @@ static int dump_task_creds(struct parasite_ctl *ctl, ce.fsuid = cr->uids[3]; ce.fsgid = cr->gids[3]; - BUILD_BUG_ON(CR_CAP_SIZE != PROC_CAP_SIZE); - - ce.n_cap_inh = CR_CAP_SIZE; - ce.cap_inh = cr->cap_inh; - ce.n_cap_prm = CR_CAP_SIZE; - ce.cap_prm = cr->cap_prm; - ce.n_cap_eff = CR_CAP_SIZE; - ce.cap_eff = cr->cap_eff; - ce.n_cap_bnd = CR_CAP_SIZE; - ce.cap_bnd = cr->cap_bnd; + pr_info("\n"); + pr_info("Dumping creds for %d)\n", ctl->pid.real); + pr_info("----------------------------------------\n"); if (parasite_dump_creds(ctl, &ce) < 0) return -1; diff --git a/include/parasite.h b/include/parasite.h index af81d85e2..d6d243d48 100644 --- a/include/parasite.h +++ b/include/parasite.h @@ -166,10 +166,21 @@ struct parasite_dump_misc { * Calculate how long we can make the groups array in parasite_dump_creds * and still fit the struct in one page */ -#define PARASITE_MAX_GROUPS \ - ((PAGE_SIZE - 2 * sizeof(unsigned int)) / sizeof(unsigned int)) +#define PARASITE_MAX_GROUPS \ + (PAGE_SIZE \ + - sizeof(unsigned int) /* cap_last_cap */ \ + - 4 * CR_CAP_SIZE * sizeof(u32) /* cap_{inh,prm,eff,bnd} */ \ + - 2 * sizeof(unsigned int) /* secbits, ngroups*/ \ + ) / sizeof(unsigned int) /* groups */ struct parasite_dump_creds { + unsigned int cap_last_cap; + + u32 cap_inh[CR_CAP_SIZE]; + u32 cap_prm[CR_CAP_SIZE]; + u32 cap_eff[CR_CAP_SIZE]; + u32 cap_bnd[CR_CAP_SIZE]; + unsigned int secbits; unsigned int ngroups; unsigned int groups[PARASITE_MAX_GROUPS]; diff --git a/include/prctl.h b/include/prctl.h index b815b96bb..70db7b901 100644 --- a/include/prctl.h +++ b/include/prctl.h @@ -7,6 +7,9 @@ #ifndef PR_GET_NAME # define PR_GET_NAME 16 #endif +#ifndef PR_CAPBSET_READ +# define PR_CAPBSET_READ 23 +#endif #ifndef PR_CAPBSET_DROP # define PR_CAPBSET_DROP 24 #endif diff --git a/kerndat.c b/kerndat.c index 0fee20b13..3c87f6ceb 100644 --- a/kerndat.c +++ b/kerndat.c @@ -229,6 +229,8 @@ int kerndat_init(void) ret = kerndat_get_dirty_track(); if (!ret) ret = init_zero_page_pfn(); + if (!ret) + ret = get_last_cap(); return ret; } diff --git a/parasite-syscall.c b/parasite-syscall.c index dad257019..fe0db1125 100644 --- a/parasite-syscall.c +++ b/parasite-syscall.c @@ -738,9 +738,20 @@ int parasite_dump_creds(struct parasite_ctl *ctl, CredsEntry *ce) BUILD_BUG_ON(sizeof(*pc) > PAGE_SIZE); pc = parasite_args(ctl, struct parasite_dump_creds); + pc->cap_last_cap = kern_last_cap; + if (parasite_execute_daemon(PARASITE_CMD_DUMP_CREDS, ctl) < 0) return -1; + ce->n_cap_inh = CR_CAP_SIZE; + ce->cap_inh = pc->cap_inh; + ce->n_cap_prm = CR_CAP_SIZE; + ce->cap_prm = pc->cap_prm; + ce->n_cap_eff = CR_CAP_SIZE; + ce->cap_eff = pc->cap_eff; + ce->n_cap_bnd = CR_CAP_SIZE; + ce->cap_bnd = pc->cap_bnd; + ce->secbits = pc->secbits; ce->n_groups = pc->ngroups; diff --git a/pie/parasite.c b/pie/parasite.c index 92e770852..c30a7fbe0 100644 --- a/pie/parasite.c +++ b/pie/parasite.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -177,7 +178,40 @@ static int dump_misc(struct parasite_dump_misc *args) static int dump_creds(struct parasite_dump_creds *args) { - int ret; + int ret, i, j; + struct cap_data data[_LINUX_CAPABILITY_U32S_3]; + struct cap_header hdr = {_LINUX_CAPABILITY_VERSION_3, 0}; + + ret = sys_capget(&hdr, data); + if (ret < 0) { + pr_err("Unable to get capabilities: %d\n", ret); + return -1; + } + + /* + * Loop through the capability constants until we reach cap_last_cap. + * The cap_bnd set is stored as a bitmask comprised of CR_CAP_SIZE number of + * 32-bit uints, hence the inner loop from 0 to 32. + */ + for (i = 0; i < CR_CAP_SIZE; i++) { + args->cap_eff[i] = data[i].eff; + args->cap_prm[i] = data[i].prm; + args->cap_inh[i] = data[i].inh; + args->cap_bnd[i] = 0; + + for (j = 0; j < 32; j++) { + if (j + i * 32 > args->cap_last_cap) + break; + ret = sys_prctl(PR_CAPBSET_READ, j + i * 32, 0, 0, 0); + if (ret < 0) { + pr_err("Unable to read capability %d: %d\n", + j + i * 32, ret); + return -1; + } + if (ret) + args->cap_bnd[i] |= (1 << j); + } + } args->secbits = sys_prctl(PR_GET_SECUREBITS, 0, 0, 0, 0);