[CRIU] [PATCH 09/10] dump: Add dumping of file owners

Cyrill Gorcunov gorcunov at openvz.org
Mon Mar 12 16:55:22 EDT 2012


File owners need to be dumped via parasite code,
there is no other way to access such information
for another's process address space.

Still, while fcntl provides almost all data file
owner handler might have, a missing piece reminds
uid and euid of owner.

For this sake a kernel patch is needed, which means
the crtools will refuse to work on old kernels without
fcntl extension.

This patch brings only dump/show procedure for a while,
the restore patch will be provided later, still all
existing test cases are passed well because restoring
code have no idea about file owners.

Note the @type member in struct fowner_entry set to be
u32 intentionally, just to avoid penalty on unaligned
member access.

Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
---
 cr-dump.c                  |    6 ++
 cr-show.c                  |   27 +++++++
 include/image.h            |    2 +-
 include/parasite-syscall.h |    1 +
 include/parasite.h         |    7 ++
 parasite-syscall.c         |   42 +++++++++++
 parasite.c                 |  164 ++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 248 insertions(+), 1 deletions(-)

diff --git a/cr-dump.c b/cr-dump.c
index 6c71c84..6e0558e 100644
--- a/cr-dump.c
+++ b/cr-dump.c
@@ -1327,6 +1327,12 @@ static int dump_one_task(const struct pstree_item *item, struct cr_fdset *cr_fds
 		goto err;
 	}
 
+	ret = parasite_dump_fowners_seized(parasite_ctl, cr_fdset);
+	if (ret) {
+		pr_err("Can't dump fowners (pid: %d) with parasite\n", pid);
+		goto err;
+	}
+
 	ret = parasite_dump_pages_seized(parasite_ctl, &vma_area_list, cr_fdset);
 	if (ret) {
 		pr_err("Can't dump pages (pid: %d) with parasite\n", pid);
diff --git a/cr-show.c b/cr-show.c
index eeb7042..140a51d 100644
--- a/cr-show.c
+++ b/cr-show.c
@@ -107,6 +107,28 @@ out:
 	pr_img_tail(CR_FD_FDINFO);
 }
 
+static void show_fowners(int fd_fowners)
+{
+	struct fowner_entry e;
+
+	pr_img_head(CR_FD_FOWNERS);
+
+	while (1) {
+		int ret;
+
+		ret = read_img_eof(fd_fowners, &e);
+		if (ret <= 0)
+			goto out;
+
+		pr_msg("type: %2x id: %16lx uid: %4x euid: %4x "
+		       "signum: %4x pid_type: %4x pid: %8x\n",
+		       e.type, e.id, e.uid, e.euid,
+		       e.signum, e.pid_type, e.pid);
+	}
+out:
+	pr_img_tail(CR_FD_FOWNERS);
+}
+
 static void show_pipes(int fd_pipes)
 {
 	struct pipe_entry e;
@@ -521,6 +543,9 @@ static int cr_parse_file(struct cr_options *opts)
 	case CREDS_MAGIC:
 		show_creds(fd);
 		break;
+	case FOWNERS_MAGIC:
+		show_fowners(fd);
+		break;
 	case IPCNS_VAR_MAGIC:
 		show_ipc_var(fd);
 		break;
@@ -606,6 +631,8 @@ static int cr_show_all(unsigned long pid, struct cr_options *opts)
 
 		show_files(cr_fdset->fds[CR_FD_FDINFO]);
 
+		show_fowners(cr_fdset->fds[CR_FD_FOWNERS]);
+
 		show_shmem(cr_fdset->fds[CR_FD_SHMEM]);
 
 		show_sigacts(cr_fdset->fds[CR_FD_SIGACT]);
diff --git a/include/image.h b/include/image.h
index 5773a7a..9416707 100644
--- a/include/image.h
+++ b/include/image.h
@@ -45,8 +45,8 @@
 #define PAGE_ANON	2
 
 struct fowner_entry {
-	u8	type;
 	u64	id;
+	u32	type;
 
 	u32	uid;
 	u32	euid;
diff --git a/include/parasite-syscall.h b/include/parasite-syscall.h
index 5ae1554..a00a06c 100644
--- a/include/parasite-syscall.h
+++ b/include/parasite-syscall.h
@@ -31,6 +31,7 @@ struct parasite_ctl {
 
 extern int parasite_dump_sigacts_seized(struct parasite_ctl *ctl, struct cr_fdset *cr_fdset);
 extern int parasite_dump_itimers_seized(struct parasite_ctl *ctl, struct cr_fdset *cr_fdset);
+extern int parasite_dump_fowners_seized(struct parasite_ctl *ctl, struct cr_fdset *cr_fdset);
 
 struct parasite_dump_misc;
 extern int parasite_dump_misc_seized(struct parasite_ctl *ctl, struct parasite_dump_misc *misc);
diff --git a/include/parasite.h b/include/parasite.h
index c255394..84af8ad 100644
--- a/include/parasite.h
+++ b/include/parasite.h
@@ -104,6 +104,13 @@ struct parasite_dump_sk_queues {
 	struct sk_queue_item	items[0];
 };
 
+struct parasite_dump_fowners {
+	parasite_status_t	status;
+
+	unsigned int		nr_pipes;
+	unsigned int		nr_fd;
+};
+
 /*
  * Some useful offsets
  */
diff --git a/parasite-syscall.c b/parasite-syscall.c
index 731ba80..95446b0 100644
--- a/parasite-syscall.c
+++ b/parasite-syscall.c
@@ -515,6 +515,48 @@ err_alloc:
 	return -1;
 }
 
+int parasite_dump_fowners_seized(struct parasite_ctl *ctl, struct cr_fdset *cr_fdset)
+{
+	struct parasite_dump_fowners args = { };
+	parasite_status_t *st = &args.status;
+	int ret = -1;
+
+	pr_info("\n");
+	pr_info("Dumping fowners (type: %d pid: %d)\n", CR_FD_FOWNERS, ctl->pid);
+	pr_info("----------------------------------------\n");
+
+	fdatasync(cr_fdset->fds[CR_FD_FOWNERS]);
+	fdatasync(cr_fdset->fds[CR_FD_FDINFO]);
+	fdatasync(cr_fdset->fds[CR_FD_PIPES]);
+
+	ret = parasite_prep_file(CR_FD_FOWNERS, ctl, cr_fdset);
+	if (ret < 0)
+		goto out;
+
+	ret = parasite_send_fd(ctl, cr_fdset->fds[CR_FD_FDINFO]);
+	if (ret < 0)
+		goto out;
+
+	ret = parasite_send_fd(ctl, cr_fdset->fds[CR_FD_PIPES]);
+	if (ret < 0)
+		goto out;
+
+	ret = parasite_execute(PARASITE_CMD_DUMP_FOWNERS, ctl, (parasite_status_t *)&args, sizeof(args));
+	if (ret < 0) {
+		pr_err("Dumping fowners failed with %li at %li\n",
+		       args.status.ret,
+		       args.status.line);
+		goto out;
+	}
+
+	pr_info("Done with %u fds and %u pipes\n", args.nr_fd, args.nr_pipes);
+
+out:
+	fchmod(cr_fdset->fds[CR_FD_FOWNERS], CR_FD_PERM);
+	pr_info("----------------------------------------\n");
+	return ret;
+}
+
 /*
  * This routine drives parasite code (been previously injected into a victim
  * process) and tells it to dump pages into the file.
diff --git a/parasite.c b/parasite.c
index 1189f6e..335a71e 100644
--- a/parasite.c
+++ b/parasite.c
@@ -1,6 +1,7 @@
 #include <sys/mman.h>
 #include <sys/socket.h>
 #include <unistd.h>
+#include <fcntl.h>
 
 #include "compiler.h"
 #include "types.h"
@@ -517,6 +518,166 @@ err_dmp:
 	return ret;
 }
 
+static int dump_fowners(struct parasite_dump_fowners *args)
+{
+	parasite_status_t *st = &args->status;
+	int fowners_fd, fdinfo_fd, pipes_fd;
+	struct f_owner_ex owner_ex;
+	struct fowner_entry owner;
+	struct fdinfo_entry fe;
+	struct pipe_entry pe;
+	int ret = -1;
+	u32 v[2];
+
+	fowners_fd = recv_fd(tsock);
+	if (fowners_fd < 0) {
+		SET_PARASITE_ERR(st, fowners_fd);
+		goto out;
+	}
+
+	fdinfo_fd = recv_fd(tsock);
+	if (fdinfo_fd < 0) {
+		SET_PARASITE_ERR(st, fdinfo_fd);
+		goto err_owners;
+	}
+
+	pipes_fd = recv_fd(tsock);
+	if (pipes_fd < 0) {
+		SET_PARASITE_ERR(st, pipes_fd);
+		goto err_fdinfo;
+	}
+
+	args->nr_fd = args->nr_pipes = 0;
+	sys_lseek(fowners_fd, MAGIC_OFFSET, SEEK_SET);
+
+	/* Start with fdinfo */
+	sys_lseek(fdinfo_fd, MAGIC_OFFSET, SEEK_SET);
+	while (1) {
+		ret = sys_read(fdinfo_fd, &fe, sizeof(fe));
+		if (ret == 0)
+			break;
+
+		if (ret != sizeof(fe)) {
+			sys_write_msg("sys_read failed\n");
+			SET_PARASITE_ERR(st, ret);
+			goto err;
+		}
+
+		if (fe.type != FDINFO_REG)
+			goto next_fe;
+
+		ret = sys_fcntl(fe.addr, F_GETOWN_EX, (long)&owner_ex);
+		if (ret) {
+			sys_write_msg("sys_fcntl failed\n");
+			SET_PARASITE_ERR(st, ret);
+			goto err;
+		}
+
+		/*
+		 * No sense to write unchanged descriptors.
+		 */
+		if (owner_ex.pid == 0)
+			goto next_fe;
+
+		owner.signum = sys_fcntl(fe.addr, F_GETSIG, 0);
+		if ((s32)owner.signum < 0) {
+			SET_PARASITE_ERR(st, (s32)owner.signum);
+			goto err;
+		}
+
+		ret = sys_fcntl(fe.addr, F_GETOWNER_UIDS, (long)&v);
+		if (ret) {
+			SET_PARASITE_ERR(st, ret);
+			goto err;
+		}
+
+		owner.type	= FOWNER_FD;
+		owner.id	= fe.id;
+		owner.uid	= v[0];
+		owner.euid	= v[1];
+		owner.pid_type	= owner_ex.type;
+		owner.pid	= owner_ex.pid;
+
+		ret = sys_write(fowners_fd, &owner, sizeof(owner));
+		if (ret != sizeof(owner)) {
+			sys_write_msg("sys_write failed\n");
+			SET_PARASITE_ERR(st, ret);
+			goto err;
+		}
+
+		args->nr_fd++;
+next_fe:
+		sys_lseek(fdinfo_fd, fe.len, SEEK_CUR);
+	}
+
+	/* Now pipes */
+	sys_lseek(pipes_fd, MAGIC_OFFSET, SEEK_SET);
+	while (1) {
+		ret = sys_read(pipes_fd, &pe, sizeof(pe));
+		if (ret == 0)
+			break;
+
+		if (ret != sizeof(pe)) {
+			sys_write_msg("sys_read failed\n");
+			SET_PARASITE_ERR(st, ret);
+			goto err;
+		}
+
+		ret = sys_fcntl(pe.fd, F_GETOWN_EX, (long)&owner_ex);
+		if (ret) {
+			sys_write_msg("sys_fcntl failed\n");
+			SET_PARASITE_ERR(st, ret);
+			goto err;
+		}
+
+		/*
+		 * No sense to write unchanged descriptors.
+		 */
+		if (owner_ex.pid == 0)
+			goto next_pe;
+
+		owner.signum = sys_fcntl(pe.fd, F_GETSIG, 0);
+		if ((s32)owner.signum < 0) {
+			SET_PARASITE_ERR(st, (s32)owner.signum);
+			goto err;
+		}
+
+		ret = sys_fcntl(pe.fd, F_GETOWNER_UIDS, (long)&v);
+		if (ret) {
+			SET_PARASITE_ERR(st, ret);
+			goto err;
+		}
+
+		owner.type	= FOWNER_PIPE;
+		owner.id	= pe.pipeid;
+		owner.uid	= v[0];
+		owner.euid	= v[1];
+		owner.pid_type	= owner_ex.type;
+		owner.pid	= owner_ex.pid;
+
+		ret = sys_write(fowners_fd, &owner, sizeof(owner));
+		if (ret != sizeof(owner)) {
+			sys_write_msg("sys_write failed\n");
+			SET_PARASITE_ERR(st, ret);
+			goto err;
+		}
+
+		args->nr_pipes++;
+next_pe:
+		sys_lseek(pipes_fd, pe.bytes, SEEK_CUR);
+	}
+
+	ret = 0;
+err:
+	sys_close(pipes_fd);
+err_fdinfo:
+	sys_close(fdinfo_fd);
+err_owners:
+	sys_close(fowners_fd);
+out:
+	return ret;
+}
+
 static int init(struct parasite_init_args *args)
 {
 	parasite_status_t *st = &args->status;
@@ -585,6 +746,7 @@ static int __used parasite_service(unsigned long cmd, void *args)
 	BUILD_BUG_ON(sizeof(struct parasite_dump_misc) > PARASITE_ARG_SIZE);
 	BUILD_BUG_ON(sizeof(struct parasite_dump_tid_addr) > PARASITE_ARG_SIZE);
 	BUILD_BUG_ON(sizeof(struct parasite_dump_sk_queues) > PARASITE_ARG_SIZE);
+	BUILD_BUG_ON(sizeof(struct parasite_dump_fowners) > PARASITE_ARG_SIZE);
 
 	switch (cmd) {
 	case PARASITE_CMD_INIT:
@@ -609,6 +771,8 @@ static int __used parasite_service(unsigned long cmd, void *args)
 		return dump_tid_addr((struct parasite_dump_tid_addr *)args);
 	case PARASITE_CMD_DUMP_SK_QUEUES:
 		return dump_skqueues((struct parasite_dump_sk_queues *)args);
+	case PARASITE_CMD_DUMP_FOWNERS:
+		return dump_fowners((struct parasite_dump_fowners *)args);
 	default:
 		{
 			parasite_status_t *st = (parasite_status_t *)args;
-- 
1.7.7.6



More information about the CRIU mailing list