linux-user: Fixes for mmap syscall emulation

linux-user: Correctly detect access to /proc in openat
 util/interval-tree: Check root for null in interval_tree_iter_first
 tests/tcg: Disable filename test for info proc mappings
 -----BEGIN PGP SIGNATURE-----
 
 iQFRBAABCgA7FiEEekgeeIaLTbaoWgXAZN846K9+IV8FAmTT0O4dHHJpY2hhcmQu
 aGVuZGVyc29uQGxpbmFyby5vcmcACgkQZN846K9+IV9NeQf/SGtJsvcMdPPcOt1P
 ZK9fBK+gS9XzWvkquSL2wehs0ZY61u2IHznIqsFxhhmPqNTZPKb27u6Cg8DCxYdw
 Hc+YMtjx2MOBv2pXTCc14XWkTsclP2jJaf2VUFIR/MowBJb7Xcgbv53PvRnCn3xT
 KC80Pm6eJZFT0EkQZwHbT8doakkjyIx8JIapdNFvD6Ne0CWCKOwDK9sF5ob1Tf5g
 BXyCw5ZtnCiToYw+RpBnhZ1wsInV+o/MV7FwcgrxGWB+4ovwRLknBzAggHvhz3ZO
 pdCqvobBtUk88+txMX6ewIDYU9BsuOnWDR+j99MD9/kPtbgSLlRYzxJ0PAjCMG6m
 xu0Tyg==
 =n1TD
 -----END PGP SIGNATURE-----

Merge tag 'pull-lu-20230809' of https://gitlab.com/rth7680/qemu into staging

linux-user: Fixes for mmap syscall emulation
linux-user: Correctly detect access to /proc in openat
util/interval-tree: Check root for null in interval_tree_iter_first
tests/tcg: Disable filename test for info proc mappings

# -----BEGIN PGP SIGNATURE-----
#
# iQFRBAABCgA7FiEEekgeeIaLTbaoWgXAZN846K9+IV8FAmTT0O4dHHJpY2hhcmQu
# aGVuZGVyc29uQGxpbmFyby5vcmcACgkQZN846K9+IV9NeQf/SGtJsvcMdPPcOt1P
# ZK9fBK+gS9XzWvkquSL2wehs0ZY61u2IHznIqsFxhhmPqNTZPKb27u6Cg8DCxYdw
# Hc+YMtjx2MOBv2pXTCc14XWkTsclP2jJaf2VUFIR/MowBJb7Xcgbv53PvRnCn3xT
# KC80Pm6eJZFT0EkQZwHbT8doakkjyIx8JIapdNFvD6Ne0CWCKOwDK9sF5ob1Tf5g
# BXyCw5ZtnCiToYw+RpBnhZ1wsInV+o/MV7FwcgrxGWB+4ovwRLknBzAggHvhz3ZO
# pdCqvobBtUk88+txMX6ewIDYU9BsuOnWDR+j99MD9/kPtbgSLlRYzxJ0PAjCMG6m
# xu0Tyg==
# =n1TD
# -----END PGP SIGNATURE-----
# gpg: Signature made Wed 09 Aug 2023 10:46:22 AM PDT
# gpg:                using RSA key 7A481E78868B4DB6A85A05C064DF38E8AF7E215F
# gpg:                issuer "richard.henderson@linaro.org"
# gpg: Good signature from "Richard Henderson <richard.henderson@linaro.org>" [ultimate]

* tag 'pull-lu-20230809' of https://gitlab.com/rth7680/qemu:
  linux-user: Fix openat() emulation to correctly detect accesses to /proc
  util/interval-tree: Check root for null in interval_tree_iter_first
  tests/tcg: Disable filename test for info proc mappings
  linux-user: Use ARRAY_SIZE with bitmask_transtbl
  linux-user: Split out do_mmap
  qemu/osdep: Remove fallback for MAP_FIXED_NOREPLACE

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2023-08-09 10:48:46 -07:00
commit e53e2e2a1b
7 changed files with 113 additions and 45 deletions

View File

@ -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 */ /* So far all target and host bitmasks are the same */
#undef target_to_host_bitmask
#define target_to_host_bitmask(x, tbl) (x) #define target_to_host_bitmask(x, tbl) (x)
#undef host_to_target_bitmask
#define host_to_target_bitmask(x, tbl) (x) #define host_to_target_bitmask(x, tbl) (x)
#endif /* SYSCALL_DEFS_H */ #endif /* SYSCALL_DEFS_H */

View File

@ -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, unsigned int target_to_host_bitmask_len(unsigned int target_mask,
const bitmask_transtbl * trans_tbl); const bitmask_transtbl *trans_tbl,
unsigned int host_to_target_bitmask(unsigned int host_mask, size_t trans_len);
const bitmask_transtbl * trans_tbl); 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); void thunk_init(unsigned int max_structs);

View File

@ -289,9 +289,6 @@ void QEMU_ERROR("code path is reachable")
#ifndef MAP_ANONYMOUS #ifndef MAP_ANONYMOUS
#define MAP_ANONYMOUS MAP_ANON #define MAP_ANONYMOUS MAP_ANON
#endif #endif
#ifndef MAP_FIXED_NOREPLACE
#define MAP_FIXED_NOREPLACE 0
#endif
#ifndef MAP_NORESERVE #ifndef MAP_NORESERVE
#define MAP_NORESERVE 0 #define MAP_NORESERVE 0
#endif #endif

View File

@ -455,7 +455,6 @@ static const bitmask_transtbl fcntl_flags_tbl[] = {
#if TARGET_O_LARGEFILE != 0 || O_LARGEFILE != 0 #if TARGET_O_LARGEFILE != 0 || O_LARGEFILE != 0
{ TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, }, { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
#endif #endif
{ 0, 0, 0, 0 }
}; };
_syscall2(int, sys_getcwd1, char *, buf, size_t, size) _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_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
{ TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL }, { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
{ TARGET_IUTF8, TARGET_IUTF8, IUTF8, IUTF8}, { TARGET_IUTF8, TARGET_IUTF8, IUTF8, IUTF8},
{ 0, 0, 0, 0 }
}; };
static const bitmask_transtbl oflag_tbl[] = { static const bitmask_transtbl oflag_tbl[] = {
@ -5841,7 +5839,6 @@ static const bitmask_transtbl oflag_tbl[] = {
{ TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 }, { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
{ TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 }, { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
{ TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 }, { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
{ 0, 0, 0, 0 }
}; };
static const bitmask_transtbl cflag_tbl[] = { static const bitmask_transtbl cflag_tbl[] = {
@ -5876,7 +5873,6 @@ static const bitmask_transtbl cflag_tbl[] = {
{ TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL }, { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
{ TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL }, { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
{ TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS }, { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
{ 0, 0, 0, 0 }
}; };
static const bitmask_transtbl lflag_tbl[] = { static const bitmask_transtbl lflag_tbl[] = {
@ -5896,7 +5892,6 @@ static const bitmask_transtbl lflag_tbl[] = {
{ TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN }, { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
{ TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN }, { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
{ TARGET_EXTPROC, TARGET_EXTPROC, EXTPROC, EXTPROC}, { TARGET_EXTPROC, TARGET_EXTPROC, EXTPROC, EXTPROC},
{ 0, 0, 0, 0 }
}; };
static void target_to_host_termios (void *dst, const void *src) static void target_to_host_termios (void *dst, const void *src)
@ -5985,10 +5980,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,16 +5997,83 @@ 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,
MAP_FIXED_NOREPLACE, MAP_FIXED_NOREPLACE }, MAP_FIXED_NOREPLACE, MAP_FIXED_NOREPLACE },
{ TARGET_MAP_UNINITIALIZED, TARGET_MAP_UNINITIALIZED, { TARGET_MAP_UNINITIALIZED, TARGET_MAP_UNINITIALIZED,
MAP_UNINITIALIZED, MAP_UNINITIALIZED }, MAP_UNINITIALIZED, MAP_UNINITIALIZED },
{ 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
@ -8499,9 +8557,12 @@ static int open_hardware(CPUArchState *cpu_env, int fd)
} }
#endif #endif
int do_guest_openat(CPUArchState *cpu_env, int dirfd, const char *pathname,
int do_guest_openat(CPUArchState *cpu_env, int dirfd, const char *fname,
int flags, mode_t mode, bool safe) int flags, mode_t mode, bool safe)
{ {
g_autofree char *proc_name = NULL;
const char *pathname;
struct fake_open { struct fake_open {
const char *filename; const char *filename;
int (*fill)(CPUArchState *cpu_env, int fd); int (*fill)(CPUArchState *cpu_env, int fd);
@ -8527,6 +8588,14 @@ int do_guest_openat(CPUArchState *cpu_env, int dirfd, const char *pathname,
{ NULL, NULL, NULL } { NULL, NULL, NULL }
}; };
/* if this is a file from /proc/ filesystem, expand full name */
proc_name = realpath(fname, NULL);
if (proc_name && strncmp(proc_name, "/proc/", 6) == 0) {
pathname = proc_name;
} else {
pathname = fname;
}
if (is_proc_myself(pathname, "exe")) { if (is_proc_myself(pathname, "exe")) {
if (safe) { if (safe) {
return safe_openat(dirfd, exec_path, flags, mode); return safe_openat(dirfd, exec_path, flags, mode);
@ -10536,28 +10605,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);

View File

@ -436,29 +436,29 @@ const argtype *thunk_print(void *arg, const argtype *type_ptr)
/* Utility function: Table-driven functions to translate bitmasks /* Utility function: Table-driven functions to translate bitmasks
* between host and target formats * between host and target formats
*/ */
unsigned int target_to_host_bitmask(unsigned int target_mask, unsigned int target_to_host_bitmask_len(unsigned int target_mask,
const bitmask_transtbl * trans_tbl) const bitmask_transtbl *tbl,
size_t len)
{ {
const bitmask_transtbl *btp;
unsigned int host_mask = 0; unsigned int host_mask = 0;
for (btp = trans_tbl; btp->target_mask && btp->host_mask; btp++) { for (size_t i = 0; i < len; ++i) {
if ((target_mask & btp->target_mask) == btp->target_bits) { if ((target_mask & tbl[i].target_mask) == tbl[i].target_bits) {
host_mask |= btp->host_bits; host_mask |= tbl[i].host_bits;
} }
} }
return host_mask; return host_mask;
} }
unsigned int host_to_target_bitmask(unsigned int host_mask, unsigned int host_to_target_bitmask_len(unsigned int host_mask,
const bitmask_transtbl * trans_tbl) const bitmask_transtbl *tbl,
size_t len)
{ {
const bitmask_transtbl *btp;
unsigned int target_mask = 0; unsigned int target_mask = 0;
for (btp = trans_tbl; btp->target_mask && btp->host_mask; btp++) { for (size_t i = 0; i < len; ++i) {
if ((host_mask & btp->host_mask) == btp->host_bits) { if ((host_mask & tbl[i].host_mask) == tbl[i].host_bits) {
target_mask |= btp->target_bits; target_mask |= tbl[i].target_bits;
} }
} }
return target_mask; return target_mask;

View File

@ -33,7 +33,8 @@ def run_test():
return return
raise raise
report(isinstance(mappings, str), "Fetched the mappings from the inferior") report(isinstance(mappings, str), "Fetched the mappings from the inferior")
report("/sha1" in mappings, "Found the test binary name in the mappings") # Broken with host page size > guest page size
# report("/sha1" in mappings, "Found the test binary name in the mappings")
def main(): def main():

View File

@ -797,7 +797,7 @@ IntervalTreeNode *interval_tree_iter_first(IntervalTreeRoot *root,
{ {
IntervalTreeNode *node, *leftmost; IntervalTreeNode *node, *leftmost;
if (!root->rb_root.rb_node) { if (!root || !root->rb_root.rb_node) {
return NULL; return NULL;
} }