* [PATCH 1/2] linux-user: Split out do_mmap
2023-08-08 2:55 [PATCH for-8.1 0/2] linux-user: Fix MAP_SHARED_VALIDATE, MAP_FIXED_NOREPLACE Richard Henderson
@ 2023-08-08 2:55 ` Richard Henderson
2023-08-09 9:15 ` Alex Bennée
2023-08-08 2:55 ` [PATCH 2/2] linux-user: Use ARRAY_SIZE with bitmask_transtbl Richard Henderson
1 sibling, 1 reply; 5+ messages in thread
From: Richard Henderson @ 2023-08-08 2:55 UTC (permalink / raw)
To: qemu-devel; +Cc: mjt, laurent
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")
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
linux-user/syscall.c | 90 +++++++++++++++++++++++++++++++++++---------
1 file changed, 73 insertions(+), 17 deletions(-)
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index a15bce2be2..34deff0723 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -5985,10 +5985,6 @@ static const StructEntry struct_termios_def = {
#endif
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_ANONYMOUS, TARGET_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
it through to the host. */
{ 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_POPULATE, TARGET_MAP_POPULATE, MAP_POPULATE, MAP_POPULATE },
{ TARGET_MAP_FIXED_NOREPLACE, TARGET_MAP_FIXED_NOREPLACE,
@@ -6016,6 +6011,75 @@ static const bitmask_transtbl mmap_flags_tbl[] = {
{ 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)
* 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]);
v6 = tswapal(v[5]);
unlock_user(v, arg1, 0);
- ret = get_errno(target_mmap(v1, v2, v3,
- target_to_host_bitmask(v4, mmap_flags_tbl),
- v5, v6));
+ return do_mmap(v1, v2, v3, v4, v5, v6);
}
#else
/* mmap pointers are always untagged */
- ret = get_errno(target_mmap(arg1, arg2, arg3,
- target_to_host_bitmask(arg4, mmap_flags_tbl),
- arg5,
- arg6));
+ return do_mmap(arg1, arg2, arg3, arg4, arg5, arg6);
#endif
- return ret;
#endif
#ifdef TARGET_NR_mmap2
case TARGET_NR_mmap2:
#ifndef MMAP_SHIFT
#define MMAP_SHIFT 12
#endif
- ret = target_mmap(arg1, arg2, arg3,
- target_to_host_bitmask(arg4, mmap_flags_tbl),
- arg5, (off_t)(abi_ulong)arg6 << MMAP_SHIFT);
- return get_errno(ret);
+ return do_mmap(arg1, arg2, arg3, arg4, arg5,
+ (off_t)(abi_ulong)arg6 << MMAP_SHIFT);
#endif
case TARGET_NR_munmap:
arg1 = cpu_untagged_addr(cpu, arg1);
--
2.34.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 2/2] linux-user: Use ARRAY_SIZE with bitmask_transtbl
2023-08-08 2:55 [PATCH for-8.1 0/2] linux-user: Fix MAP_SHARED_VALIDATE, MAP_FIXED_NOREPLACE Richard Henderson
2023-08-08 2:55 ` [PATCH 1/2] linux-user: Split out do_mmap Richard Henderson
@ 2023-08-08 2:55 ` Richard Henderson
2023-08-09 9:14 ` Alex Bennée
1 sibling, 1 reply; 5+ messages in thread
From: Richard Henderson @ 2023-08-08 2:55 UTC (permalink / raw)
To: qemu-devel; +Cc: mjt, laurent
Rather than using a zero tuple to end the table, use a macro
to apply ARRAY_SIZE and pass that on to the convert functions.
This fixes two bugs in which the conversion functions required
that both the target and host masks be non-zero in order to
continue, rather than require both target and host masks be
zero in order to terminate.
This affected mmap_flags_tbl when the host does not support
all of the flags we wish to convert (e.g. MAP_UNINITIALIZED).
Mapping these flags to zero is good enough, and matches how
the kernel ignores bits that are unknown.
Fixes: 4b840f96 ("linux-user: Populate more bits in mmap_flags_tbl")
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
bsd-user/syscall_defs.h | 2 ++
include/exec/user/thunk.h | 15 +++++++++++----
linux-user/syscall.c | 6 ------
linux-user/thunk.c | 24 ++++++++++++------------
4 files changed, 25 insertions(+), 22 deletions(-)
diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h
index b6d113d24a..aedfbf2d7d 100644
--- a/bsd-user/syscall_defs.h
+++ b/bsd-user/syscall_defs.h
@@ -227,7 +227,9 @@ type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
}
/* So far all target and host bitmasks are the same */
+#undef target_to_host_bitmask
#define target_to_host_bitmask(x, tbl) (x)
+#undef host_to_target_bitmask
#define host_to_target_bitmask(x, tbl) (x)
#endif /* SYSCALL_DEFS_H */
diff --git a/include/exec/user/thunk.h b/include/exec/user/thunk.h
index 300a840d58..6eedef48d8 100644
--- a/include/exec/user/thunk.h
+++ b/include/exec/user/thunk.h
@@ -193,10 +193,17 @@ static inline int thunk_type_align(const argtype *type_ptr, int is_host)
}
}
-unsigned int target_to_host_bitmask(unsigned int target_mask,
- const bitmask_transtbl * trans_tbl);
-unsigned int host_to_target_bitmask(unsigned int host_mask,
- const bitmask_transtbl * trans_tbl);
+unsigned int target_to_host_bitmask_len(unsigned int target_mask,
+ const bitmask_transtbl *trans_tbl,
+ size_t trans_len);
+unsigned int host_to_target_bitmask_len(unsigned int host_mask,
+ const bitmask_transtbl * trans_tbl,
+ size_t trans_len);
+
+#define target_to_host_bitmask(M, T) \
+ target_to_host_bitmask_len(M, T, ARRAY_SIZE(T))
+#define host_to_target_bitmask(M, T) \
+ host_to_target_bitmask_len(M, T, ARRAY_SIZE(T))
void thunk_init(unsigned int max_structs);
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 34deff0723..12ebc70df5 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -455,7 +455,6 @@ static const bitmask_transtbl fcntl_flags_tbl[] = {
#if TARGET_O_LARGEFILE != 0 || O_LARGEFILE != 0
{ TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
#endif
- { 0, 0, 0, 0 }
};
_syscall2(int, sys_getcwd1, char *, buf, size_t, size)
@@ -5813,7 +5812,6 @@ static const bitmask_transtbl iflag_tbl[] = {
{ TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
{ TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
{ TARGET_IUTF8, TARGET_IUTF8, IUTF8, IUTF8},
- { 0, 0, 0, 0 }
};
static const bitmask_transtbl oflag_tbl[] = {
@@ -5841,7 +5839,6 @@ static const bitmask_transtbl oflag_tbl[] = {
{ TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
{ TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
{ TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
- { 0, 0, 0, 0 }
};
static const bitmask_transtbl cflag_tbl[] = {
@@ -5876,7 +5873,6 @@ static const bitmask_transtbl cflag_tbl[] = {
{ TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
{ TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
{ TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
- { 0, 0, 0, 0 }
};
static const bitmask_transtbl lflag_tbl[] = {
@@ -5896,7 +5892,6 @@ static const bitmask_transtbl lflag_tbl[] = {
{ TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
{ TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
{ TARGET_EXTPROC, TARGET_EXTPROC, EXTPROC, EXTPROC},
- { 0, 0, 0, 0 }
};
static void target_to_host_termios (void *dst, const void *src)
@@ -6008,7 +6003,6 @@ static const bitmask_transtbl mmap_flags_tbl[] = {
MAP_FIXED_NOREPLACE, MAP_FIXED_NOREPLACE },
{ TARGET_MAP_UNINITIALIZED, TARGET_MAP_UNINITIALIZED,
MAP_UNINITIALIZED, MAP_UNINITIALIZED },
- { 0, 0, 0, 0 }
};
/*
diff --git a/linux-user/thunk.c b/linux-user/thunk.c
index dac4bf11c6..071aad4b5f 100644
--- a/linux-user/thunk.c
+++ b/linux-user/thunk.c
@@ -436,29 +436,29 @@ const argtype *thunk_print(void *arg, const argtype *type_ptr)
/* Utility function: Table-driven functions to translate bitmasks
* between host and target formats
*/
-unsigned int target_to_host_bitmask(unsigned int target_mask,
- const bitmask_transtbl * trans_tbl)
+unsigned int target_to_host_bitmask_len(unsigned int target_mask,
+ const bitmask_transtbl *tbl,
+ size_t len)
{
- const bitmask_transtbl *btp;
unsigned int host_mask = 0;
- for (btp = trans_tbl; btp->target_mask && btp->host_mask; btp++) {
- if ((target_mask & btp->target_mask) == btp->target_bits) {
- host_mask |= btp->host_bits;
+ for (size_t i = 0; i < len; ++i) {
+ if ((target_mask & tbl[i].target_mask) == tbl[i].target_bits) {
+ host_mask |= tbl[i].host_bits;
}
}
return host_mask;
}
-unsigned int host_to_target_bitmask(unsigned int host_mask,
- const bitmask_transtbl * trans_tbl)
+unsigned int host_to_target_bitmask_len(unsigned int host_mask,
+ const bitmask_transtbl *tbl,
+ size_t len)
{
- const bitmask_transtbl *btp;
unsigned int target_mask = 0;
- for (btp = trans_tbl; btp->target_mask && btp->host_mask; btp++) {
- if ((host_mask & btp->host_mask) == btp->host_bits) {
- target_mask |= btp->target_bits;
+ for (size_t i = 0; i < len; ++i) {
+ if ((host_mask & tbl[i].host_mask) == tbl[i].host_bits) {
+ target_mask |= tbl[i].target_bits;
}
}
return target_mask;
--
2.34.1
^ permalink raw reply related [flat|nested] 5+ messages in thread