aboutsummaryrefslogtreecommitdiff
path: root/linux-user/syscall.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux-user/syscall.c')
-rw-r--r--linux-user/syscall.c338
1 files changed, 237 insertions, 101 deletions
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index b8c278b..fc37028 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -26,6 +26,9 @@
#include "tcg/startup.h"
#include "target_mman.h"
#include "exec/page-protection.h"
+#include "exec/mmap-lock.h"
+#include "exec/tb-flush.h"
+#include "exec/translation-block.h"
#include <elf.h>
#include <endian.h>
#include <grp.h>
@@ -54,7 +57,6 @@
#include <utime.h>
#include <sys/sysinfo.h>
#include <sys/signalfd.h>
-//#include <sys/user.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
@@ -136,14 +138,16 @@
#include "signal-common.h"
#include "loader.h"
#include "user-mmap.h"
+#include "user/page-protection.h"
#include "user/safe-syscall.h"
+#include "user/signal.h"
#include "qemu/guest-random.h"
#include "qemu/selfmap.h"
#include "user/syscall-trace.h"
#include "special-errno.h"
#include "qapi/error.h"
#include "fd-trans.h"
-#include "cpu_loop-common.h"
+#include "user/cpu_loop.h"
#ifndef CLONE_IO
#define CLONE_IO 0x80000000 /* Clone io context */
@@ -359,7 +363,8 @@ _syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len,
#define __NR_sys_sched_setaffinity __NR_sched_setaffinity
_syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len,
unsigned long *, user_mask_ptr);
-/* sched_attr is not defined in glibc */
+/* sched_attr is not defined in glibc < 2.41 */
+#ifndef SCHED_ATTR_SIZE_VER0
struct sched_attr {
uint32_t size;
uint32_t sched_policy;
@@ -372,6 +377,7 @@ struct sched_attr {
uint32_t sched_util_min;
uint32_t sched_util_max;
};
+#endif
#define __NR_sys_sched_getattr __NR_sched_getattr
_syscall4(int, sys_sched_getattr, pid_t, pid, struct sched_attr *, attr,
unsigned int, size, unsigned int, flags);
@@ -602,6 +608,33 @@ static int check_zeroed_user(abi_long addr, size_t ksize, size_t usize)
return 1;
}
+/*
+ * Copies a target struct to a host struct, in a way that guarantees
+ * backwards-compatibility for struct syscall arguments.
+ *
+ * Similar to kernels uaccess.h:copy_struct_from_user()
+ */
+int copy_struct_from_user(void *dst, size_t ksize, abi_ptr src, size_t usize)
+{
+ size_t size = MIN(ksize, usize);
+ size_t rest = MAX(ksize, usize) - size;
+
+ /* Deal with trailing bytes. */
+ if (usize < ksize) {
+ memset(dst + size, 0, rest);
+ } else if (usize > ksize) {
+ int ret = check_zeroed_user(src, ksize, usize);
+ if (ret <= 0) {
+ return ret ?: -TARGET_E2BIG;
+ }
+ }
+ /* Copy the interoperable parts of the struct. */
+ if (copy_from_user(dst, src, size)) {
+ return -TARGET_EFAULT;
+ }
+ return 0;
+}
+
#define safe_syscall0(type, name) \
static type safe_##name(void) \
{ \
@@ -653,6 +686,10 @@ safe_syscall3(ssize_t, read, int, fd, void *, buff, size_t, count)
safe_syscall3(ssize_t, write, int, fd, const void *, buff, size_t, count)
safe_syscall4(int, openat, int, dirfd, const char *, pathname, \
int, flags, mode_t, mode)
+
+safe_syscall4(int, openat2, int, dirfd, const char *, pathname, \
+ const struct open_how_ver0 *, how, size_t, size)
+
#if defined(TARGET_NR_wait4) || defined(TARGET_NR_waitpid)
safe_syscall4(pid_t, wait4, pid_t, pid, int *, status, int, options, \
struct rusage *, rusage)
@@ -759,10 +796,8 @@ safe_syscall6(ssize_t, copy_file_range, int, infd, loff_t *, pinoff,
* the libc function.
*/
#define safe_ioctl(...) safe_syscall(__NR_ioctl, __VA_ARGS__)
-/* Similarly for fcntl. Note that callers must always:
- * pass the F_GETLK64 etc constants rather than the unsuffixed F_GETLK
- * use the flock64 struct rather than unsuffixed flock
- * This will then work and use a 64-bit offset for both 32-bit and 64-bit hosts.
+/* Similarly for fcntl. Since we always build with LFS enabled,
+ * we should be using the 64-bit structures automatically.
*/
#ifdef __NR_fcntl64
#define safe_fcntl(...) safe_syscall(__NR_fcntl64, __VA_ARGS__)
@@ -1797,7 +1832,7 @@ static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
*dst = tswap32(*dst);
}
} else {
- qemu_log_mask(LOG_UNIMP, "Unsupported ancillary data: %d/%d\n",
+ qemu_log_mask(LOG_UNIMP, "Unsupported target ancillary data: %d/%d\n",
cmsg->cmsg_level, cmsg->cmsg_type);
memcpy(data, target_data, len);
}
@@ -1968,6 +2003,16 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
(void *) &errh->offender, sizeof(errh->offender));
break;
}
+ case IP_PKTINFO:
+ {
+ struct in_pktinfo *pkti = data;
+ struct target_in_pktinfo *target_pi = target_data;
+
+ __put_user(pkti->ipi_ifindex, &target_pi->ipi_ifindex);
+ target_pi->ipi_spec_dst.s_addr = pkti->ipi_spec_dst.s_addr;
+ target_pi->ipi_addr.s_addr = pkti->ipi_addr.s_addr;
+ break;
+ }
default:
goto unimplemented;
}
@@ -2019,7 +2064,7 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
default:
unimplemented:
- qemu_log_mask(LOG_UNIMP, "Unsupported ancillary data: %d/%d\n",
+ qemu_log_mask(LOG_UNIMP, "Unsupported host ancillary data: %d/%d\n",
cmsg->cmsg_level, cmsg->cmsg_type);
memcpy(target_data, data, MIN(len, tgt_len));
if (tgt_len > len) {
@@ -2090,16 +2135,23 @@ static abi_long do_setsockopt(int sockfd, int level, int optname,
}
ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
break;
+ case IP_MULTICAST_IF:
case IP_ADD_MEMBERSHIP:
case IP_DROP_MEMBERSHIP:
{
struct ip_mreqn ip_mreq;
struct target_ip_mreqn *target_smreqn;
+ int min_size;
QEMU_BUILD_BUG_ON(sizeof(struct ip_mreq) !=
sizeof(struct target_ip_mreq));
- if (optlen < sizeof (struct target_ip_mreq) ||
+ if (optname == IP_MULTICAST_IF) {
+ min_size = sizeof(struct in_addr);
+ } else {
+ min_size = sizeof(struct target_ip_mreq);
+ }
+ if (optlen < min_size ||
optlen > sizeof (struct target_ip_mreqn)) {
return -TARGET_EINVAL;
}
@@ -2109,13 +2161,14 @@ static abi_long do_setsockopt(int sockfd, int level, int optname,
return -TARGET_EFAULT;
}
ip_mreq.imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
- ip_mreq.imr_address.s_addr = target_smreqn->imr_address.s_addr;
- if (optlen == sizeof(struct target_ip_mreqn)) {
- ip_mreq.imr_ifindex = tswapal(target_smreqn->imr_ifindex);
- optlen = sizeof(struct ip_mreqn);
+ if (optlen >= sizeof(struct target_ip_mreq)) {
+ ip_mreq.imr_address.s_addr = target_smreqn->imr_address.s_addr;
+ if (optlen >= sizeof(struct target_ip_mreqn)) {
+ __put_user(target_smreqn->imr_ifindex, &ip_mreq.imr_ifindex);
+ optlen = sizeof(struct ip_mreqn);
+ }
}
unlock_user(target_smreqn, optval_addr, 0);
-
ret = get_errno(setsockopt(sockfd, level, optname, &ip_mreq, optlen));
break;
}
@@ -6722,13 +6775,13 @@ static int target_to_host_fcntl_cmd(int cmd)
ret = cmd;
break;
case TARGET_F_GETLK:
- ret = F_GETLK64;
+ ret = F_GETLK;
break;
case TARGET_F_SETLK:
- ret = F_SETLK64;
+ ret = F_SETLK;
break;
case TARGET_F_SETLKW:
- ret = F_SETLKW64;
+ ret = F_SETLKW;
break;
case TARGET_F_GETOWN:
ret = F_GETOWN;
@@ -6744,13 +6797,13 @@ static int target_to_host_fcntl_cmd(int cmd)
break;
#if TARGET_ABI_BITS == 32
case TARGET_F_GETLK64:
- ret = F_GETLK64;
+ ret = F_GETLK;
break;
case TARGET_F_SETLK64:
- ret = F_SETLK64;
+ ret = F_SETLK;
break;
case TARGET_F_SETLKW64:
- ret = F_SETLKW64;
+ ret = F_SETLKW;
break;
#endif
case TARGET_F_SETLEASE:
@@ -6804,8 +6857,8 @@ static int target_to_host_fcntl_cmd(int cmd)
* them to 5, 6 and 7 before making the syscall(). Since we make the
* syscall directly, adjust to what is supported by the kernel.
*/
- if (ret >= F_GETLK64 && ret <= F_SETLKW64) {
- ret -= F_GETLK64 - 5;
+ if (ret >= F_GETLK && ret <= F_SETLKW) {
+ ret -= F_GETLK - 5;
}
#endif
@@ -6838,7 +6891,7 @@ static int host_to_target_flock(int type)
return type;
}
-static inline abi_long copy_from_user_flock(struct flock64 *fl,
+static inline abi_long copy_from_user_flock(struct flock *fl,
abi_ulong target_flock_addr)
{
struct target_flock *target_fl;
@@ -6863,7 +6916,7 @@ static inline abi_long copy_from_user_flock(struct flock64 *fl,
}
static inline abi_long copy_to_user_flock(abi_ulong target_flock_addr,
- const struct flock64 *fl)
+ const struct flock *fl)
{
struct target_flock *target_fl;
short l_type;
@@ -6882,8 +6935,8 @@ static inline abi_long copy_to_user_flock(abi_ulong target_flock_addr,
return 0;
}
-typedef abi_long from_flock64_fn(struct flock64 *fl, abi_ulong target_addr);
-typedef abi_long to_flock64_fn(abi_ulong target_addr, const struct flock64 *fl);
+typedef abi_long from_flock64_fn(struct flock *fl, abi_ulong target_addr);
+typedef abi_long to_flock64_fn(abi_ulong target_addr, const struct flock *fl);
#if defined(TARGET_ARM) && TARGET_ABI_BITS == 32
struct target_oabi_flock64 {
@@ -6894,7 +6947,7 @@ struct target_oabi_flock64 {
abi_int l_pid;
} QEMU_PACKED;
-static inline abi_long copy_from_user_oabi_flock64(struct flock64 *fl,
+static inline abi_long copy_from_user_oabi_flock64(struct flock *fl,
abi_ulong target_flock_addr)
{
struct target_oabi_flock64 *target_fl;
@@ -6919,7 +6972,7 @@ static inline abi_long copy_from_user_oabi_flock64(struct flock64 *fl,
}
static inline abi_long copy_to_user_oabi_flock64(abi_ulong target_flock_addr,
- const struct flock64 *fl)
+ const struct flock *fl)
{
struct target_oabi_flock64 *target_fl;
short l_type;
@@ -6939,7 +6992,7 @@ static inline abi_long copy_to_user_oabi_flock64(abi_ulong target_flock_addr,
}
#endif
-static inline abi_long copy_from_user_flock64(struct flock64 *fl,
+static inline abi_long copy_from_user_flock64(struct flock *fl,
abi_ulong target_flock_addr)
{
struct target_flock64 *target_fl;
@@ -6964,7 +7017,7 @@ static inline abi_long copy_from_user_flock64(struct flock64 *fl,
}
static inline abi_long copy_to_user_flock64(abi_ulong target_flock_addr,
- const struct flock64 *fl)
+ const struct flock *fl)
{
struct target_flock64 *target_fl;
short l_type;
@@ -6985,7 +7038,7 @@ static inline abi_long copy_to_user_flock64(abi_ulong target_flock_addr,
static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
{
- struct flock64 fl64;
+ struct flock fl;
#ifdef F_GETOWN_EX
struct f_owner_ex fox;
struct target_f_owner_ex *target_fox;
@@ -6998,45 +7051,45 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
switch(cmd) {
case TARGET_F_GETLK:
- ret = copy_from_user_flock(&fl64, arg);
+ ret = copy_from_user_flock(&fl, arg);
if (ret) {
return ret;
}
- ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
+ ret = get_errno(safe_fcntl(fd, host_cmd, &fl));
if (ret == 0) {
- ret = copy_to_user_flock(arg, &fl64);
+ ret = copy_to_user_flock(arg, &fl);
}
break;
case TARGET_F_SETLK:
case TARGET_F_SETLKW:
- ret = copy_from_user_flock(&fl64, arg);
+ ret = copy_from_user_flock(&fl, arg);
if (ret) {
return ret;
}
- ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
+ ret = get_errno(safe_fcntl(fd, host_cmd, &fl));
break;
case TARGET_F_GETLK64:
case TARGET_F_OFD_GETLK:
- ret = copy_from_user_flock64(&fl64, arg);
+ ret = copy_from_user_flock64(&fl, arg);
if (ret) {
return ret;
}
- ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
+ ret = get_errno(safe_fcntl(fd, host_cmd, &fl));
if (ret == 0) {
- ret = copy_to_user_flock64(arg, &fl64);
+ ret = copy_to_user_flock64(arg, &fl);
}
break;
case TARGET_F_SETLK64:
case TARGET_F_SETLKW64:
case TARGET_F_OFD_SETLK:
case TARGET_F_OFD_SETLKW:
- ret = copy_from_user_flock64(&fl64, arg);
+ ret = copy_from_user_flock64(&fl, arg);
if (ret) {
return ret;
}
- ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
+ ret = get_errno(safe_fcntl(fd, host_cmd, &fl));
break;
case TARGET_F_GETFL:
@@ -7205,12 +7258,24 @@ static inline int tswapid(int id)
#else
#define __NR_sys_setgroups __NR_setgroups
#endif
+#ifdef __NR_sys_setreuid32
+#define __NR_sys_setreuid __NR_setreuid32
+#else
+#define __NR_sys_setreuid __NR_setreuid
+#endif
+#ifdef __NR_sys_setregid32
+#define __NR_sys_setregid __NR_setregid32
+#else
+#define __NR_sys_setregid __NR_setregid
+#endif
_syscall1(int, sys_setuid, uid_t, uid)
_syscall1(int, sys_setgid, gid_t, gid)
_syscall3(int, sys_setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
_syscall3(int, sys_setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid)
_syscall2(int, sys_setgroups, int, size, gid_t *, grouplist)
+_syscall2(int, sys_setreuid, uid_t, ruid, uid_t, euid);
+_syscall2(int, sys_setregid, gid_t, rgid, gid_t, egid);
void syscall_init(void)
{
@@ -7267,7 +7332,7 @@ static inline abi_long target_truncate64(CPUArchState *cpu_env, const char *arg1
arg2 = arg3;
arg3 = arg4;
}
- return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
+ return get_errno(truncate(arg1, target_offset64(arg2, arg3)));
}
#endif
@@ -7281,7 +7346,7 @@ static inline abi_long target_ftruncate64(CPUArchState *cpu_env, abi_long arg1,
arg2 = arg3;
arg3 = arg4;
}
- return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
+ return get_errno(ftruncate(arg1, target_offset64(arg2, arg3)));
}
#endif
@@ -8070,8 +8135,8 @@ static void open_self_maps_4(const struct open_self_maps_data *d,
* Callback for walk_memory_regions, when read_self_maps() fails.
* Proceed without the benefit of host /proc/self/maps cross-check.
*/
-static int open_self_maps_3(void *opaque, target_ulong guest_start,
- target_ulong guest_end, unsigned long flags)
+static int open_self_maps_3(void *opaque, vaddr guest_start,
+ vaddr guest_end, int flags)
{
static const MapInfo mi = { .is_priv = true };
@@ -8082,8 +8147,8 @@ static int open_self_maps_3(void *opaque, target_ulong guest_start,
/*
* Callback for walk_memory_regions, when read_self_maps() succeeds.
*/
-static int open_self_maps_2(void *opaque, target_ulong guest_start,
- target_ulong guest_end, unsigned long flags)
+static int open_self_maps_2(void *opaque, vaddr guest_start,
+ vaddr guest_end, int flags)
{
const struct open_self_maps_data *d = opaque;
uintptr_t host_start = (uintptr_t)g2h_untagged(guest_start);
@@ -8122,17 +8187,19 @@ static int open_self_maps_1(CPUArchState *env, int fd, bool smaps)
{
struct open_self_maps_data d = {
.ts = get_task_state(env_cpu(env)),
- .host_maps = read_self_maps(),
.fd = fd,
.smaps = smaps
};
+ mmap_lock();
+ d.host_maps = read_self_maps();
if (d.host_maps) {
walk_memory_regions(&d, open_self_maps_2);
free_self_maps(d.host_maps);
} else {
walk_memory_regions(&d, open_self_maps_3);
}
+ mmap_unlock();
return 0;
}
@@ -8168,6 +8235,19 @@ static int open_self_stat(CPUArchState *cpu_env, int fd)
} else if (i == 3) {
/* ppid */
g_string_printf(buf, FMT_pid " ", getppid());
+ } else if (i == 4) {
+ /* pgid */
+ g_string_printf(buf, FMT_pid " ", getpgrp());
+ } else if (i == 19) {
+ /* num_threads */
+ int cpus = 0;
+ WITH_RCU_READ_LOCK_GUARD() {
+ CPUState *cpu_iter;
+ CPU_FOREACH(cpu_iter) {
+ cpus++;
+ }
+ }
+ g_string_printf(buf, "%d ", cpus);
} else if (i == 21) {
/* starttime */
g_string_printf(buf, "%" PRIu64 " ", ts->start_boottime);
@@ -8324,8 +8404,9 @@ static int open_net_route(CPUArchState *cpu_env, int fd)
}
#endif
-int do_guest_openat(CPUArchState *cpu_env, int dirfd, const char *fname,
- int flags, mode_t mode, bool safe)
+static int maybe_do_fake_open(CPUArchState *cpu_env, int dirfd,
+ const char *fname, int flags, mode_t mode,
+ int openat2_resolve, bool safe)
{
g_autofree char *proc_name = NULL;
const char *pathname;
@@ -8362,6 +8443,12 @@ int do_guest_openat(CPUArchState *cpu_env, int dirfd, const char *fname,
}
if (is_proc_myself(pathname, "exe")) {
+ /* Honor openat2 resolve flags */
+ if ((openat2_resolve & RESOLVE_NO_MAGICLINKS) ||
+ (openat2_resolve & RESOLVE_NO_SYMLINKS)) {
+ errno = ELOOP;
+ return -1;
+ }
if (safe) {
return safe_openat(dirfd, exec_path, flags, mode);
} else {
@@ -8408,6 +8495,17 @@ int do_guest_openat(CPUArchState *cpu_env, int dirfd, const char *fname,
return fd;
}
+ return -2;
+}
+
+int do_guest_openat(CPUArchState *cpu_env, int dirfd, const char *pathname,
+ int flags, mode_t mode, bool safe)
+{
+ int fd = maybe_do_fake_open(cpu_env, dirfd, pathname, flags, mode, 0, safe);
+ if (fd > -2) {
+ return fd;
+ }
+
if (safe) {
return safe_openat(dirfd, path(pathname), flags, mode);
} else {
@@ -8415,6 +8513,49 @@ int do_guest_openat(CPUArchState *cpu_env, int dirfd, const char *fname,
}
}
+
+static int do_openat2(CPUArchState *cpu_env, abi_long dirfd,
+ abi_ptr guest_pathname, abi_ptr guest_open_how,
+ abi_ulong guest_size)
+{
+ struct open_how_ver0 how = {0};
+ char *pathname;
+ int ret;
+
+ if (guest_size < sizeof(struct target_open_how_ver0)) {
+ return -TARGET_EINVAL;
+ }
+ ret = copy_struct_from_user(&how, sizeof(how), guest_open_how, guest_size);
+ if (ret) {
+ if (ret == -TARGET_E2BIG) {
+ qemu_log_mask(LOG_UNIMP,
+ "Unimplemented openat2 open_how size: "
+ TARGET_ABI_FMT_lu "\n", guest_size);
+ }
+ return ret;
+ }
+ pathname = lock_user_string(guest_pathname);
+ if (!pathname) {
+ return -TARGET_EFAULT;
+ }
+
+ how.flags = target_to_host_bitmask(tswap64(how.flags), fcntl_flags_tbl);
+ how.mode = tswap64(how.mode);
+ how.resolve = tswap64(how.resolve);
+ int fd = maybe_do_fake_open(cpu_env, dirfd, pathname, how.flags, how.mode,
+ how.resolve, true);
+ if (fd > -2) {
+ ret = get_errno(fd);
+ } else {
+ ret = get_errno(safe_openat2(dirfd, pathname, &how,
+ sizeof(struct open_how_ver0)));
+ }
+
+ fd_trans_unregister(ret);
+ unlock_user(pathname, guest_pathname, 0);
+ return ret;
+}
+
ssize_t do_guest_readlink(const char *pathname, char *buf, size_t bufsiz)
{
ssize_t ret;
@@ -8656,7 +8797,7 @@ static int do_getdents(abi_long dirfd, abi_long arg2, abi_long count)
void *tdirp;
int hlen, hoff, toff;
int hreclen, treclen;
- off64_t prev_diroff = 0;
+ off_t prev_diroff = 0;
hdirp = g_try_malloc(count);
if (!hdirp) {
@@ -8709,7 +8850,7 @@ static int do_getdents(abi_long dirfd, abi_long arg2, abi_long count)
* Return what we have, resetting the file pointer to the
* location of the first record not returned.
*/
- lseek64(dirfd, prev_diroff, SEEK_SET);
+ lseek(dirfd, prev_diroff, SEEK_SET);
break;
}
@@ -8743,7 +8884,7 @@ static int do_getdents64(abi_long dirfd, abi_long arg2, abi_long count)
void *tdirp;
int hlen, hoff, toff;
int hreclen, treclen;
- off64_t prev_diroff = 0;
+ off_t prev_diroff = 0;
hdirp = g_try_malloc(count);
if (!hdirp) {
@@ -8785,7 +8926,7 @@ static int do_getdents64(abi_long dirfd, abi_long arg2, abi_long count)
* Return what we have, resetting the file pointer to the
* location of the first record not returned.
*/
- lseek64(dirfd, prev_diroff, SEEK_SET);
+ lseek(dirfd, prev_diroff, SEEK_SET);
break;
}
@@ -8843,7 +8984,7 @@ static int do_getdents64(abi_long dirfd, abi_long arg2, abi_long count)
#define RISCV_HWPROBE_EXT_ZFHMIN (1 << 28)
#define RISCV_HWPROBE_EXT_ZIHINTNTL (1 << 29)
#define RISCV_HWPROBE_EXT_ZVFH (1 << 30)
-#define RISCV_HWPROBE_EXT_ZVFHMIN (1 << 31)
+#define RISCV_HWPROBE_EXT_ZVFHMIN (1ULL << 31)
#define RISCV_HWPROBE_EXT_ZFA (1ULL << 32)
#define RISCV_HWPROBE_EXT_ZTSO (1ULL << 33)
#define RISCV_HWPROBE_EXT_ZACAS (1ULL << 34)
@@ -8982,35 +9123,38 @@ static void risc_hwprobe_fill_pairs(CPURISCVState *env,
}
}
-static int cpu_set_valid(abi_long arg3, abi_long arg4)
+/*
+ * If the cpumask_t of (target_cpus, cpusetsize) cannot be read: -EFAULT.
+ * If the cpumast_t has no bits set: -EINVAL.
+ * Otherwise the cpumask_t contains some bit set: 0.
+ * Unlike the kernel, we do not mask cpumask_t by the set of online cpus,
+ * nor bound the search by cpumask_size().
+ */
+static int nonempty_cpu_set(abi_ulong cpusetsize, abi_ptr target_cpus)
{
- int ret, i, tmp;
- size_t host_mask_size, target_mask_size;
- unsigned long *host_mask;
-
- /*
- * cpu_set_t represent CPU masks as bit masks of type unsigned long *.
- * arg3 contains the cpu count.
- */
- tmp = (8 * sizeof(abi_ulong));
- target_mask_size = ((arg3 + tmp - 1) / tmp) * sizeof(abi_ulong);
- host_mask_size = (target_mask_size + (sizeof(*host_mask) - 1)) &
- ~(sizeof(*host_mask) - 1);
-
- host_mask = alloca(host_mask_size);
+ unsigned char *p = lock_user(VERIFY_READ, target_cpus, cpusetsize, 1);
+ int ret = -TARGET_EFAULT;
- ret = target_to_host_cpu_mask(host_mask, host_mask_size,
- arg4, target_mask_size);
- if (ret != 0) {
- return ret;
- }
-
- for (i = 0 ; i < host_mask_size / sizeof(*host_mask); i++) {
- if (host_mask[i] != 0) {
- return 0;
+ if (p) {
+ ret = -TARGET_EINVAL;
+ /*
+ * Since we only care about the empty/non-empty state of the cpumask_t
+ * not the individual bits, we do not need to repartition the bits
+ * from target abi_ulong to host unsigned long.
+ *
+ * Note that the kernel does not round up cpusetsize to a multiple of
+ * sizeof(abi_ulong). After bounding cpusetsize by cpumask_size(),
+ * it copies exactly cpusetsize bytes into a zeroed buffer.
+ */
+ for (abi_ulong i = 0; i < cpusetsize; ++i) {
+ if (p[i]) {
+ ret = 0;
+ break;
+ }
}
+ unlock_user(p, target_cpus, 0);
}
- return -TARGET_EINVAL;
+ return ret;
}
static abi_long do_riscv_hwprobe(CPUArchState *cpu_env, abi_long arg1,
@@ -9027,7 +9171,7 @@ static abi_long do_riscv_hwprobe(CPUArchState *cpu_env, abi_long arg1,
/* check cpu_set */
if (arg3 != 0) {
- ret = cpu_set_valid(arg3, arg4);
+ ret = nonempty_cpu_set(arg3, arg4);
if (ret != 0) {
return ret;
}
@@ -9187,6 +9331,9 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
fd_trans_unregister(ret);
unlock_user(p, arg2, 0);
return ret;
+ case TARGET_NR_openat2:
+ ret = do_openat2(cpu_env, arg1, arg2, arg3, arg4);
+ return ret;
#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
case TARGET_NR_name_to_handle_at:
ret = do_name_to_handle_at(arg1, arg2, arg3, arg4, arg5);
@@ -10472,10 +10619,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
return ret;
#ifdef TARGET_NR_mmap
case TARGET_NR_mmap:
-#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || \
- (defined(TARGET_ARM) && defined(TARGET_ABI32)) || \
- defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
- || defined(TARGET_S390X)
+#ifdef TARGET_ARCH_WANT_SYS_OLD_MMAP
{
abi_ulong *v;
abi_ulong v1, v2, v3, v4, v5, v6;
@@ -11516,7 +11660,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
return -TARGET_EFAULT;
}
}
- ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
+ ret = get_errno(pread(arg1, p, arg3, target_offset64(arg4, arg5)));
unlock_user(p, arg2, ret);
return ret;
case TARGET_NR_pwrite64:
@@ -11533,7 +11677,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
return -TARGET_EFAULT;
}
}
- ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
+ ret = get_errno(pwrite(arg1, p, arg3, target_offset64(arg4, arg5)));
unlock_user(p, arg2, 0);
return ret;
#endif
@@ -11828,9 +11972,9 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
return get_errno(high2lowgid(getegid()));
#endif
case TARGET_NR_setreuid:
- return get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
+ return get_errno(sys_setreuid(low2highuid(arg1), low2highuid(arg2)));
case TARGET_NR_setregid:
- return get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
+ return get_errno(sys_setregid(low2highgid(arg1), low2highgid(arg2)));
case TARGET_NR_getgroups:
{ /* the same code as for TARGET_NR_getgroups32 */
int gidsetsize = arg1;
@@ -12160,11 +12304,11 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
#endif
#ifdef TARGET_NR_setreuid32
case TARGET_NR_setreuid32:
- return get_errno(setreuid(arg1, arg2));
+ return get_errno(sys_setreuid(arg1, arg2));
#endif
#ifdef TARGET_NR_setregid32
case TARGET_NR_setregid32:
- return get_errno(setregid(arg1, arg2));
+ return get_errno(sys_setregid(arg1, arg2));
#endif
#ifdef TARGET_NR_getgroups32
case TARGET_NR_getgroups32:
@@ -12393,7 +12537,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
case TARGET_NR_fcntl64:
{
int cmd;
- struct flock64 fl;
+ struct flock fl;
from_flock64_fn *copyfrom = copy_from_user_flock64;
to_flock64_fn *copyto = copy_to_user_flock64;
@@ -12628,14 +12772,6 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
#if defined(TARGET_MIPS)
cpu_env->active_tc.CP0_UserLocal = arg1;
return 0;
-#elif defined(TARGET_CRIS)
- if (arg1 & 0xff)
- ret = -TARGET_EINVAL;
- else {
- cpu_env->pregs[PR_PID] = arg1;
- ret = 0;
- }
- return ret;
#elif defined(TARGET_I386) && defined(TARGET_ABI32)
return do_set_thread_area(cpu_env, arg1);
#elif defined(TARGET_M68K)