linux-user: Split out do_mmap

New function that rejects unsupported map types and flags.
In 4b840f96 we should not have accepted MAP_SHARED_VALIDATE
without actually validating the rest of the flags.

Fixes: 4b840f96 ("linux-user: Populate more bits in mmap_flags_tbl")
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2023-08-07 18:22:35 -07:00
parent c42e77a90d
commit 9ab8d07149

View file

@ -5985,10 +5985,6 @@ static const StructEntry struct_termios_def = {
#endif #endif
static const bitmask_transtbl mmap_flags_tbl[] = { static const bitmask_transtbl mmap_flags_tbl[] = {
{ TARGET_MAP_TYPE, TARGET_MAP_SHARED, MAP_TYPE, MAP_SHARED },
{ TARGET_MAP_TYPE, TARGET_MAP_PRIVATE, MAP_TYPE, MAP_PRIVATE },
{ TARGET_MAP_TYPE, TARGET_MAP_SHARED_VALIDATE,
MAP_TYPE, MAP_SHARED_VALIDATE },
{ TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED }, { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
{ TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS,
MAP_ANONYMOUS, MAP_ANONYMOUS }, MAP_ANONYMOUS, MAP_ANONYMOUS },
@ -6006,7 +6002,6 @@ static const bitmask_transtbl mmap_flags_tbl[] = {
Recognize it for the target insofar as we do not want to pass Recognize it for the target insofar as we do not want to pass
it through to the host. */ it through to the host. */
{ TARGET_MAP_STACK, TARGET_MAP_STACK, 0, 0 }, { TARGET_MAP_STACK, TARGET_MAP_STACK, 0, 0 },
{ TARGET_MAP_SYNC, TARGET_MAP_SYNC, MAP_SYNC, MAP_SYNC },
{ TARGET_MAP_NONBLOCK, TARGET_MAP_NONBLOCK, MAP_NONBLOCK, MAP_NONBLOCK }, { TARGET_MAP_NONBLOCK, TARGET_MAP_NONBLOCK, MAP_NONBLOCK, MAP_NONBLOCK },
{ TARGET_MAP_POPULATE, TARGET_MAP_POPULATE, MAP_POPULATE, MAP_POPULATE }, { TARGET_MAP_POPULATE, TARGET_MAP_POPULATE, MAP_POPULATE, MAP_POPULATE },
{ TARGET_MAP_FIXED_NOREPLACE, TARGET_MAP_FIXED_NOREPLACE, { TARGET_MAP_FIXED_NOREPLACE, TARGET_MAP_FIXED_NOREPLACE,
@ -6016,6 +6011,75 @@ static const bitmask_transtbl mmap_flags_tbl[] = {
{ 0, 0, 0, 0 } { 0, 0, 0, 0 }
}; };
/*
* Arrange for legacy / undefined architecture specific flags to be
* ignored by mmap handling code.
*/
#ifndef TARGET_MAP_32BIT
#define TARGET_MAP_32BIT 0
#endif
#ifndef TARGET_MAP_HUGE_2MB
#define TARGET_MAP_HUGE_2MB 0
#endif
#ifndef TARGET_MAP_HUGE_1GB
#define TARGET_MAP_HUGE_1GB 0
#endif
static abi_long do_mmap(abi_ulong addr, abi_ulong len, int prot,
int target_flags, int fd, off_t offset)
{
/*
* The historical set of flags that all mmap types implicitly support.
*/
enum {
TARGET_LEGACY_MAP_MASK = TARGET_MAP_SHARED
| TARGET_MAP_PRIVATE
| TARGET_MAP_FIXED
| TARGET_MAP_ANONYMOUS
| TARGET_MAP_DENYWRITE
| TARGET_MAP_EXECUTABLE
| TARGET_MAP_UNINITIALIZED
| TARGET_MAP_GROWSDOWN
| TARGET_MAP_LOCKED
| TARGET_MAP_NORESERVE
| TARGET_MAP_POPULATE
| TARGET_MAP_NONBLOCK
| TARGET_MAP_STACK
| TARGET_MAP_HUGETLB
| TARGET_MAP_32BIT
| TARGET_MAP_HUGE_2MB
| TARGET_MAP_HUGE_1GB
};
int host_flags;
switch (target_flags & TARGET_MAP_TYPE) {
case TARGET_MAP_PRIVATE:
host_flags = MAP_PRIVATE;
break;
case TARGET_MAP_SHARED:
host_flags = MAP_SHARED;
break;
case TARGET_MAP_SHARED_VALIDATE:
/*
* MAP_SYNC is only supported for MAP_SHARED_VALIDATE, and is
* therefore omitted from mmap_flags_tbl and TARGET_LEGACY_MAP_MASK.
*/
if (target_flags & ~(TARGET_LEGACY_MAP_MASK | TARGET_MAP_SYNC)) {
return -TARGET_EOPNOTSUPP;
}
host_flags = MAP_SHARED_VALIDATE;
if (target_flags & TARGET_MAP_SYNC) {
host_flags |= MAP_SYNC;
}
break;
default:
return -TARGET_EINVAL;
}
host_flags |= target_to_host_bitmask(target_flags, mmap_flags_tbl);
return get_errno(target_mmap(addr, len, prot, host_flags, fd, offset));
}
/* /*
* NOTE: TARGET_ABI32 is defined for TARGET_I386 (but not for TARGET_X86_64) * NOTE: TARGET_ABI32 is defined for TARGET_I386 (but not for TARGET_X86_64)
* TARGET_I386 is defined if TARGET_X86_64 is defined * TARGET_I386 is defined if TARGET_X86_64 is defined
@ -10536,28 +10600,20 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
v5 = tswapal(v[4]); v5 = tswapal(v[4]);
v6 = tswapal(v[5]); v6 = tswapal(v[5]);
unlock_user(v, arg1, 0); unlock_user(v, arg1, 0);
ret = get_errno(target_mmap(v1, v2, v3, return do_mmap(v1, v2, v3, v4, v5, v6);
target_to_host_bitmask(v4, mmap_flags_tbl),
v5, v6));
} }
#else #else
/* mmap pointers are always untagged */ /* mmap pointers are always untagged */
ret = get_errno(target_mmap(arg1, arg2, arg3, return do_mmap(arg1, arg2, arg3, arg4, arg5, arg6);
target_to_host_bitmask(arg4, mmap_flags_tbl),
arg5,
arg6));
#endif #endif
return ret;
#endif #endif
#ifdef TARGET_NR_mmap2 #ifdef TARGET_NR_mmap2
case TARGET_NR_mmap2: case TARGET_NR_mmap2:
#ifndef MMAP_SHIFT #ifndef MMAP_SHIFT
#define MMAP_SHIFT 12 #define MMAP_SHIFT 12
#endif #endif
ret = target_mmap(arg1, arg2, arg3, return do_mmap(arg1, arg2, arg3, arg4, arg5,
target_to_host_bitmask(arg4, mmap_flags_tbl), (off_t)(abi_ulong)arg6 << MMAP_SHIFT);
arg5, (off_t)(abi_ulong)arg6 << MMAP_SHIFT);
return get_errno(ret);
#endif #endif
case TARGET_NR_munmap: case TARGET_NR_munmap:
arg1 = cpu_untagged_addr(cpu, arg1); arg1 = cpu_untagged_addr(cpu, arg1);