[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH] xen-mapcache: avoid a race on memory map while using MAP_FIX
From: |
Roger Pau Monné |
Subject: |
Re: [PATCH] xen-mapcache: avoid a race on memory map while using MAP_FIXED |
Date: |
Tue, 20 Apr 2021 10:53:18 +0200 |
On Tue, Apr 20, 2021 at 04:35:02AM +0100, Igor Druzhinin wrote:
> When we're replacing the existing mapping there is possibility of a race
> on memory map with other threads doing mmap operations - the address being
> unmapped/re-mapped could be occupied by another thread in between.
>
> Linux mmap man page recommends keeping the existing mappings in place to
> reserve the place and instead utilize the fact that the next mmap operation
> with MAP_FIXED flag passed will implicitly destroy the existing mappings
> behind the chosen address. This behavior is guaranteed by POSIX / BSD and
> therefore is portable.
>
> Note that it wouldn't make the replacement atomic for parallel accesses to
> the replaced region - those might still fail with SIGBUS due to
> xenforeignmemory_map not being atomic. So we're still not expecting those.
>
> Tested-by: Anthony PERARD <anthony.perard@citrix.com>
> Signed-off-by: Igor Druzhinin <igor.druzhinin@citrix.com>
Should we add a 'Fixes: 759235653de ...' or similar tag here?
> ---
> hw/i386/xen/xen-mapcache.c | 15 ++++++++++++++-
> 1 file changed, 14 insertions(+), 1 deletion(-)
>
> diff --git a/hw/i386/xen/xen-mapcache.c b/hw/i386/xen/xen-mapcache.c
> index 5b120ed..e82b7dc 100644
> --- a/hw/i386/xen/xen-mapcache.c
> +++ b/hw/i386/xen/xen-mapcache.c
> @@ -171,7 +171,20 @@ static void xen_remap_bucket(MapCacheEntry *entry,
> if (!(entry->flags & XEN_MAPCACHE_ENTRY_DUMMY)) {
> ram_block_notify_remove(entry->vaddr_base, entry->size);
> }
> - if (munmap(entry->vaddr_base, entry->size) != 0) {
> +
> + /*
> + * If an entry is being replaced by another mapping and we're using
> + * MAP_FIXED flag for it - there is possibility of a race for vaddr
> + * address with another thread doing an mmap call itself
> + * (see man 2 mmap). To avoid that we skip explicit unmapping here
> + * and allow the kernel to destroy the previous mappings by replacing
> + * them in mmap call later.
> + *
> + * Non-identical replacements are not allowed therefore.
> + */
> + assert(!vaddr || (entry->vaddr_base == vaddr && entry->size ==
> size));
> +
> + if (!vaddr && munmap(entry->vaddr_base, entry->size) != 0) {
Oh, so remappings of foreign addresses must always use the same
virtual address space, I somehow assumed that you could remap an
existing foreign map (or dummy mapping) into a different virtual
address if you so wanted.
Thanks, Roger.