[CRIU] [PATCH] Dump capabilities from the parasite

Sophie Blee-Goldman ableegoldman at google.com
Wed Aug 13 19:47:49 PDT 2014


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).

Signed-off-by: Sophie Blee-Goldman <ableegoldman at google.com>
---
 arch/arm/syscall.def        |  1 +
 arch/x86/syscall-x86-64.def |  1 +
 cr-dump.c                   | 17 +++--------------
 include/parasite.h          | 15 +++++++++++++--
 include/prctl.h             |  3 +++
 kerndat.c                   |  2 ++
 parasite-syscall.c          | 11 +++++++++++
 pie/parasite.c              | 36 +++++++++++++++++++++++++++++++++++-
 8 files changed, 69 insertions(+), 17 deletions(-)

diff --git a/arch/arm/syscall.def b/arch/arm/syscall.def
index c539e3e..02eaa65 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 878cf79..ec86dfe 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 1700d9d..f52af65 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 af81d85..d6d243d 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 b815b96..70db7b9 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 0fee20b..3c87f6c 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 dad2570..fe0db11 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 92e7708..c30a7fb 100644
--- a/pie/parasite.c
+++ b/pie/parasite.c
@@ -2,6 +2,7 @@
 #include <errno.h>
 #include <signal.h>
 #include <linux/limits.h>
+#include <linux/capability.h>
 #include <sys/mount.h>
 #include <stdarg.h>
 #include <sys/ioctl.h>
@@ -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);
 
-- 
2.1.0.rc2.206.gedb03e5



More information about the CRIU mailing list