[CRIU] [PATCH] irmap: Get root mntfd before releasing tasks on predump
Andrew Vagin
avagin at parallels.com
Tue Sep 30 21:40:47 PDT 2014
On Tue, Sep 30, 2014 at 11:57:54PM +0400, Pavel Emelyanov wrote:
> 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 at parallels.com>
Acked-by: Andrew Vagin <avagin at parallels.com>
>
> ---
>
> diff --git a/cr-dump.c b/cr-dump.c
> index 04c18fa..e82f576 100644
> --- a/cr-dump.c
> +++ b/cr-dump.c
> @@ -1693,6 +1693,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 b5b495d..3938d07 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 ab8247e..10ebb0a 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;
>
> _______________________________________________
> CRIU mailing list
> CRIU at openvz.org
> https://lists.openvz.org/mailman/listinfo/criu
More information about the CRIU
mailing list