Commit e606c214 authored by Sophie Blee-Goldman's avatar Sophie Blee-Goldman Committed by Pavel Emelyanov

Dump capabilities from the parasite

Needed for future user namespace support. Capabilities will have to be
dumped from the parasite, ie from inside the namespace since there is no
obvious way to 'translate' capabilities from the global namespace (unlike
with uids and gids, where the id mappings can be used for translation).

[ additional explanation from Andrew Vagin:

"capabilities" are not translated between namespaces. They can exist
only in one userns, where a process lives. If a process is created in a
new userns, it gets a full set of capabilities in this userns, and
loses all caps in a parent userns.

So if capabilities are not shown in /proc/pid/stat, we have no way to
get it except of using parasite code. ]
Signed-off-by: 's avatarSophie Blee-Goldman <ableegoldman@google.com>
Acked-by: 's avatarAndrew Vagin <avagin@parallels.com>
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent 49407766
...@@ -59,6 +59,7 @@ getpgid 155 132 (pid_t pid) ...@@ -59,6 +59,7 @@ getpgid 155 132 (pid_t pid)
setfsuid 151 138 (int fsuid) setfsuid 151 138 (int fsuid)
setfsgid 152 139 (int fsgid) setfsgid 152 139 (int fsgid)
getsid 156 147 (void) 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) capset 91 185 (struct cap_header *h, struct cap_data *d)
rt_sigqueueinfo 138 178 (pid_t pid, int sig, siginfo_t *info) rt_sigqueueinfo 138 178 (pid_t pid, int sig, siginfo_t *info)
setpriority 140 97 (int which, int who, int nice) setpriority 140 97 (int which, int who, int nice)
......
...@@ -59,6 +59,7 @@ __NR_getpgid 121 sys_getpgid (pid_t pid) ...@@ -59,6 +59,7 @@ __NR_getpgid 121 sys_getpgid (pid_t pid)
__NR_setfsuid 122 sys_setfsuid (int fsuid) __NR_setfsuid 122 sys_setfsuid (int fsuid)
__NR_setfsgid 123 sys_setfsgid (int fsgid) __NR_setfsgid 123 sys_setfsgid (int fsgid)
__NR_getsid 124 sys_getsid (void) __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_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_rt_sigqueueinfo 129 sys_rt_sigqueueinfo (pid_t pid, int sig, siginfo_t *info)
__NR_sigaltstack 131 sys_sigaltstack (const void *uss, void *uoss) __NR_sigaltstack 131 sys_sigaltstack (const void *uss, void *uoss)
......
...@@ -502,10 +502,6 @@ static int dump_task_creds(struct parasite_ctl *ctl, ...@@ -502,10 +502,6 @@ static int dump_task_creds(struct parasite_ctl *ctl,
{ {
CredsEntry ce = CREDS_ENTRY__INIT; 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.uid = cr->uids[0];
ce.gid = cr->gids[0]; ce.gid = cr->gids[0];
ce.euid = cr->uids[1]; ce.euid = cr->uids[1];
...@@ -515,16 +511,9 @@ static int dump_task_creds(struct parasite_ctl *ctl, ...@@ -515,16 +511,9 @@ static int dump_task_creds(struct parasite_ctl *ctl,
ce.fsuid = cr->uids[3]; ce.fsuid = cr->uids[3];
ce.fsgid = cr->gids[3]; ce.fsgid = cr->gids[3];
BUILD_BUG_ON(CR_CAP_SIZE != PROC_CAP_SIZE); pr_info("\n");
pr_info("Dumping creds for %d)\n", ctl->pid.real);
ce.n_cap_inh = CR_CAP_SIZE; pr_info("----------------------------------------\n");
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;
if (parasite_dump_creds(ctl, &ce) < 0) if (parasite_dump_creds(ctl, &ce) < 0)
return -1; return -1;
......
...@@ -166,10 +166,21 @@ struct parasite_dump_misc { ...@@ -166,10 +166,21 @@ struct parasite_dump_misc {
* Calculate how long we can make the groups array in parasite_dump_creds * Calculate how long we can make the groups array in parasite_dump_creds
* and still fit the struct in one page * and still fit the struct in one page
*/ */
#define PARASITE_MAX_GROUPS \ #define PARASITE_MAX_GROUPS \
((PAGE_SIZE - 2 * sizeof(unsigned int)) / sizeof(unsigned int)) (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 { 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 secbits;
unsigned int ngroups; unsigned int ngroups;
unsigned int groups[PARASITE_MAX_GROUPS]; unsigned int groups[PARASITE_MAX_GROUPS];
......
...@@ -7,6 +7,9 @@ ...@@ -7,6 +7,9 @@
#ifndef PR_GET_NAME #ifndef PR_GET_NAME
# define PR_GET_NAME 16 # define PR_GET_NAME 16
#endif #endif
#ifndef PR_CAPBSET_READ
# define PR_CAPBSET_READ 23
#endif
#ifndef PR_CAPBSET_DROP #ifndef PR_CAPBSET_DROP
# define PR_CAPBSET_DROP 24 # define PR_CAPBSET_DROP 24
#endif #endif
......
...@@ -229,6 +229,8 @@ int kerndat_init(void) ...@@ -229,6 +229,8 @@ int kerndat_init(void)
ret = kerndat_get_dirty_track(); ret = kerndat_get_dirty_track();
if (!ret) if (!ret)
ret = init_zero_page_pfn(); ret = init_zero_page_pfn();
if (!ret)
ret = get_last_cap();
return ret; return ret;
} }
......
...@@ -738,9 +738,20 @@ int parasite_dump_creds(struct parasite_ctl *ctl, CredsEntry *ce) ...@@ -738,9 +738,20 @@ int parasite_dump_creds(struct parasite_ctl *ctl, CredsEntry *ce)
BUILD_BUG_ON(sizeof(*pc) > PAGE_SIZE); BUILD_BUG_ON(sizeof(*pc) > PAGE_SIZE);
pc = parasite_args(ctl, struct parasite_dump_creds); 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) if (parasite_execute_daemon(PARASITE_CMD_DUMP_CREDS, ctl) < 0)
return -1; 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->secbits = pc->secbits;
ce->n_groups = pc->ngroups; ce->n_groups = pc->ngroups;
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#include <errno.h> #include <errno.h>
#include <signal.h> #include <signal.h>
#include <linux/limits.h> #include <linux/limits.h>
#include <linux/capability.h>
#include <sys/mount.h> #include <sys/mount.h>
#include <stdarg.h> #include <stdarg.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
...@@ -177,7 +178,40 @@ static int dump_misc(struct parasite_dump_misc *args) ...@@ -177,7 +178,40 @@ static int dump_misc(struct parasite_dump_misc *args)
static int dump_creds(struct parasite_dump_creds *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); args->secbits = sys_prctl(PR_GET_SECUREBITS, 0, 0, 0, 0);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment