mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-19 08:02:15 -06:00
linux-user: Add emulation for MADV_WIPEONFORK and MADV_KEEPONFORK in madvise()
Both parameters have a different value on the parisc platform, so first translate the target value into a host value for usage in the native madvise() syscall. Those parameters are often used by security sensitive applications (e.g. tor browser, boringssl, ...) which expect the call to return a proper return code on failure, so return -EINVAL if qemu fails to forward the syscall to the host OS. While touching this code, enhance the comments about MADV_DONTNEED. Tested with testcase of tor browser when running hppa-linux guest on x86-64 host. Signed-off-by: Helge Deller <deller@gmx.de> Acked-by: Ilya Leoshkevich <iii@linux.ibm.com> Reviewed-by: Laurent Vivier <laurent@vivier.eu> Message-Id: <Y5iwTaydU7i66K/i@p100> Signed-off-by: Laurent Vivier <laurent@vivier.eu>
This commit is contained in:
parent
ab6c497e7e
commit
4530deb1fe
1 changed files with 43 additions and 13 deletions
|
@ -857,7 +857,7 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
|
||||||
return new_addr;
|
return new_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool can_passthrough_madv_dontneed(abi_ulong start, abi_ulong end)
|
static bool can_passthrough_madvise(abi_ulong start, abi_ulong end)
|
||||||
{
|
{
|
||||||
ulong addr;
|
ulong addr;
|
||||||
|
|
||||||
|
@ -901,25 +901,55 @@ abi_long target_madvise(abi_ulong start, abi_ulong len_in, int advice)
|
||||||
return -TARGET_EINVAL;
|
return -TARGET_EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Translate for some architectures which have different MADV_xxx values */
|
||||||
|
switch (advice) {
|
||||||
|
case TARGET_MADV_DONTNEED: /* alpha */
|
||||||
|
advice = MADV_DONTNEED;
|
||||||
|
break;
|
||||||
|
case TARGET_MADV_WIPEONFORK: /* parisc */
|
||||||
|
advice = MADV_WIPEONFORK;
|
||||||
|
break;
|
||||||
|
case TARGET_MADV_KEEPONFORK: /* parisc */
|
||||||
|
advice = MADV_KEEPONFORK;
|
||||||
|
break;
|
||||||
|
/* we do not care about the other MADV_xxx values yet */
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A straight passthrough may not be safe because qemu sometimes turns
|
* Most advice values are hints, so ignoring and returning success is ok.
|
||||||
* private file-backed mappings into anonymous mappings.
|
|
||||||
*
|
*
|
||||||
* This is a hint, so ignoring and returning success is ok.
|
* However, some advice values such as MADV_DONTNEED, MADV_WIPEONFORK and
|
||||||
|
* MADV_KEEPONFORK are not hints and need to be emulated.
|
||||||
*
|
*
|
||||||
* This breaks MADV_DONTNEED, completely implementing which is quite
|
* A straight passthrough for those may not be safe because qemu sometimes
|
||||||
* complicated. However, there is one low-hanging fruit: mappings that are
|
* turns private file-backed mappings into anonymous mappings.
|
||||||
* known to have the same semantics in the host and the guest. In this case
|
* can_passthrough_madvise() helps to check if a passthrough is possible by
|
||||||
* passthrough is safe, so do it.
|
* comparing mappings that are known to have the same semantics in the host
|
||||||
|
* and the guest. In this case passthrough is safe.
|
||||||
|
*
|
||||||
|
* We pass through MADV_WIPEONFORK and MADV_KEEPONFORK if possible and
|
||||||
|
* return failure if not.
|
||||||
|
*
|
||||||
|
* MADV_DONTNEED is passed through as well, if possible.
|
||||||
|
* If passthrough isn't possible, we nevertheless (wrongly!) return
|
||||||
|
* success, which is broken but some userspace programs fail to work
|
||||||
|
* otherwise. Completely implementing such emulation is quite complicated
|
||||||
|
* though.
|
||||||
*/
|
*/
|
||||||
mmap_lock();
|
mmap_lock();
|
||||||
if (advice == TARGET_MADV_DONTNEED &&
|
switch (advice) {
|
||||||
can_passthrough_madv_dontneed(start, end)) {
|
case MADV_WIPEONFORK:
|
||||||
ret = get_errno(madvise(g2h_untagged(start), len, MADV_DONTNEED));
|
case MADV_KEEPONFORK:
|
||||||
if (ret == 0) {
|
ret = -EINVAL;
|
||||||
|
/* fall through */
|
||||||
|
case MADV_DONTNEED:
|
||||||
|
if (can_passthrough_madvise(start, end)) {
|
||||||
|
ret = get_errno(madvise(g2h_untagged(start), len, advice));
|
||||||
|
if ((advice == MADV_DONTNEED) && (ret == 0)) {
|
||||||
page_reset_target_data(start, start + len);
|
page_reset_target_data(start, start + len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
mmap_unlock();
|
mmap_unlock();
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue