Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/checkpoint-restore/criu.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPavel Emelyanov <xemul@parallels.com>2014-09-30 23:57:00 +0400
committerPavel Emelyanov <xemul@parallels.com>2014-10-01 12:42:50 +0400
commit1bbc9fbe37a8b718aa236e2d856175af6194c5ea (patch)
tree4dd47d1f437cb7b74757de84dd1b10de1e842ffa
parent05f3e17a01d01de8e06c603325ce1bd4b708f5cc (diff)
irmap: Get root mntfd before releasing tasks on predumpbr-1.3-stable
We have a use-after-free in predump code: 1st the free_pstree() is called in pre_dump_tasks(), then we go to irmap_predump_run() which may call the lookup_irmap() which, in turn, dereferences the root_item to get the root mount ns fd. But the problem is bigger than that. After we've released the tasks (done before freeing pstree on predump) we can no longer access them by PIDs, so keeping the root-item after irmap scan is not a fix. Fix is to get the root fd before releasing the tasks and using one in irmap scanner. Caught recently on iterative inotify_irmap test. Signed-off-by: Pavel Emelyanov <xemul@parallels.com> Acked-by: Andrew Vagin <avagin@parallels.com>
-rw-r--r--cr-dump.c3
-rw-r--r--include/irmap.h1
-rw-r--r--irmap.c27
3 files changed, 30 insertions, 1 deletions
diff --git a/cr-dump.c b/cr-dump.c
index cec579ead..1a3936158 100644
--- a/cr-dump.c
+++ b/cr-dump.c
@@ -1734,6 +1734,9 @@ int cr_pre_dump_tasks(pid_t pid)
if (pre_dump_one_task(item, &ctls))
goto err;
+ if (irmap_predump_prep())
+ goto err;
+
ret = 0;
err:
pstree_switch_state(root_item,
diff --git a/include/irmap.h b/include/irmap.h
index b5b495ddc..3938d07be 100644
--- a/include/irmap.h
+++ b/include/irmap.h
@@ -4,6 +4,7 @@ char *irmap_lookup(unsigned int s_dev, unsigned long i_ino);
struct _FhEntry;
int irmap_queue_cache(unsigned int dev, unsigned long ino,
struct _FhEntry *fh);
+int irmap_predump_prep(void);
int irmap_predump_run(void);
int check_open_handle(unsigned int s_dev, unsigned long i_ino,
struct _FhEntry *f_handle);
diff --git a/irmap.c b/irmap.c
index 17d3c1455..518219fef 100644
--- a/irmap.c
+++ b/irmap.c
@@ -217,6 +217,8 @@ invalid:
return 1;
}
+static bool doing_predump = false;
+
char *irmap_lookup(unsigned int s_dev, unsigned long i_ino)
{
struct irmap *c, *h, **p;
@@ -227,7 +229,14 @@ char *irmap_lookup(unsigned int s_dev, unsigned long i_ino)
pr_debug("Resolving %x:%lx path\n", s_dev, i_ino);
- if (__mntns_get_root_fd(root_item->pid.real) < 0)
+ /*
+ * If we're in predump, then processes already run
+ * and the root_item is already freed by that time.
+ * But the root service fd is already set by the
+ * irmap_predump_prep, so we just go ahead and scan.
+ */
+ if (!doing_predump &&
+ __mntns_get_root_fd(root_item->pid.real) < 0)
goto out;
timing_start(TIME_IRMAP_RESOLVE);
@@ -296,6 +305,22 @@ int irmap_queue_cache(unsigned int dev, unsigned long ino,
return 0;
}
+int irmap_predump_prep(void)
+{
+ /*
+ * Tasks are about to get released soon, but
+ * we'll need to do FS scan for irmaps. In this
+ * scan we will need to know the root dir tasks
+ * live in. Need to make sure the respective fd
+ * (service) is set to that root, so that the
+ * scan works and doesn't race with the tasks
+ * dying or changind root.
+ */
+
+ doing_predump = true;
+ return __mntns_get_root_fd(root_item->pid.real) < 0 ? -1 : 0;
+}
+
int irmap_predump_run(void)
{
int ret = 0, fd;