From 524fa3408ed745a2fed0642fb0d92c934d10ff64 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Wed, 29 May 2019 10:48:04 +0200 Subject: linux-user: emulate msgsnd(), msgrcv() and semtimedop() When we have updated kernel headers to 5.2-rc1 we have introduced new syscall numbers that can be not supported by older kernels and fail with ENOSYS while the guest emulation succeeded before because the syscalls were emulated with ipc(). This patch fixes the problem by using ipc() if the new syscall returns ENOSYS. Fixes: 86e636951ddc ("linux-user: fix __NR_semtimedop undeclared error") Signed-off-by: Laurent Vivier Reviewed-by: Cornelia Huck Message-Id: <20190529084804.25950-1-laurent@vivier.eu> Signed-off-by: Laurent Vivier --- linux-user/syscall.c | 61 +++++++++++++++++++++++------------------------ linux-user/syscall_defs.h | 1 + 2 files changed, 31 insertions(+), 31 deletions(-) (limited to 'linux-user') diff --git a/linux-user/syscall.c b/linux-user/syscall.c index b187c12..e942049 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -762,50 +762,21 @@ safe_syscall2(int, nanosleep, const struct timespec *, req, safe_syscall4(int, clock_nanosleep, const clockid_t, clock, int, flags, const struct timespec *, req, struct timespec *, rem) #endif -#if !defined(__NR_msgsnd) || !defined(__NR_msgrcv) || !defined(__NR_semtimedop) -/* This host kernel architecture uses a single ipc syscall; fake up - * wrappers for the sub-operations to hide this implementation detail. - * Annoyingly we can't include linux/ipc.h to get the constant definitions - * for the call parameter because some structs in there conflict with the - * sys/ipc.h ones. So we just define them here, and rely on them being - * the same for all host architectures. - */ -#define Q_SEMTIMEDOP 4 -#define Q_MSGSND 11 -#define Q_MSGRCV 12 -#define Q_IPCCALL(VERSION, OP) ((VERSION) << 16 | (OP)) - +#ifdef __NR_ipc safe_syscall6(int, ipc, int, call, long, first, long, second, long, third, void *, ptr, long, fifth) #endif #ifdef __NR_msgsnd safe_syscall4(int, msgsnd, int, msgid, const void *, msgp, size_t, sz, int, flags) -#else -static int safe_msgsnd(int msgid, const void *msgp, size_t sz, int flags) -{ - return safe_ipc(Q_IPCCALL(0, Q_MSGSND), msgid, sz, flags, (void *)msgp, 0); -} #endif #ifdef __NR_msgrcv safe_syscall5(int, msgrcv, int, msgid, void *, msgp, size_t, sz, long, msgtype, int, flags) -#else -static int safe_msgrcv(int msgid, void *msgp, size_t sz, long type, int flags) -{ - return safe_ipc(Q_IPCCALL(1, Q_MSGRCV), msgid, sz, flags, msgp, type); -} #endif #ifdef __NR_semtimedop safe_syscall4(int, semtimedop, int, semid, struct sembuf *, tsops, unsigned, nsops, const struct timespec *, timeout) -#else -static int safe_semtimedop(int semid, struct sembuf *tsops, unsigned nsops, - const struct timespec *timeout) -{ - return safe_ipc(Q_IPCCALL(0, Q_SEMTIMEDOP), semid, nsops, 0, tsops, - (long)timeout); -} #endif #if defined(TARGET_NR_mq_open) && defined(__NR_mq_open) safe_syscall5(int, mq_timedsend, int, mqdes, const char *, msg_ptr, @@ -3529,11 +3500,21 @@ static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf, static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops) { struct sembuf sops[nsops]; + abi_long ret; if (target_to_host_sembuf(sops, ptr, nsops)) return -TARGET_EFAULT; - return get_errno(safe_semtimedop(semid, sops, nsops, NULL)); + ret = -TARGET_ENOSYS; +#ifdef __NR_semtimedop + ret = get_errno(safe_semtimedop(semid, sops, nsops, NULL)); +#endif +#ifdef __NR_ipc + if (ret == -TARGET_ENOSYS) { + ret = get_errno(safe_ipc(IPCOP_semtimedop, semid, nsops, 0, sops, 0)); + } +#endif + return ret; } struct target_msqid_ds @@ -3688,7 +3669,16 @@ static inline abi_long do_msgsnd(int msqid, abi_long msgp, } host_mb->mtype = (abi_long) tswapal(target_mb->mtype); memcpy(host_mb->mtext, target_mb->mtext, msgsz); + ret = -TARGET_ENOSYS; +#ifdef __NR_msgsnd ret = get_errno(safe_msgsnd(msqid, host_mb, msgsz, msgflg)); +#endif +#ifdef __NR_ipc + if (ret == -TARGET_ENOSYS) { + ret = get_errno(safe_ipc(IPCOP_msgsnd, msqid, msgsz, msgflg, + host_mb, 0)); + } +#endif g_free(host_mb); unlock_user_struct(target_mb, msgp, 0); @@ -3716,7 +3706,16 @@ static inline abi_long do_msgrcv(int msqid, abi_long msgp, ret = -TARGET_ENOMEM; goto end; } + ret = -TARGET_ENOSYS; +#ifdef __NR_msgrcv ret = get_errno(safe_msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg)); +#endif +#ifdef __NR_ipc + if (ret == -TARGET_ENOSYS) { + ret = get_errno(safe_ipc(IPCOP_CALL(1, IPCOP_msgrcv), msqid, msgsz, + msgflg, host_mb, msgtyp)); + } +#endif if (ret > 0) { abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong); diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 7f141f6..3175440 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -32,6 +32,7 @@ #define TARGET_SYS_RECVMMSG 19 /* recvmmsg() */ #define TARGET_SYS_SENDMMSG 20 /* sendmmsg() */ +#define IPCOP_CALL(VERSION, OP) ((VERSION) << 16 | (OP)) #define IPCOP_semop 1 #define IPCOP_semget 2 #define IPCOP_semctl 3 -- cgit v1.1 From f31dddd2fc0a9cd40cdb9203662f75a785220268 Mon Sep 17 00:00:00 2001 From: Yunqiang Su Date: Wed, 19 Jun 2019 16:17:11 +0200 Subject: linux-user: Add support for setsockopt() option SOL_ALG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for options SOL_ALG of the syscall setsockopt(). This option is used in relation to Linux kernel Crypto API, and allows a user to set additional information for the cipher operation via syscall setsockopt(). The field "optname" must be one of the following: - ALG_SET_KEY – seting the key - ALG_SET_AEAD_AUTHSIZE – set the authentication tag size SOL_ALG is relatively newer setsockopt() option. Therefore, the code that handles SOL_ALG is enclosed in "ifdef" so that the build does not fail for older kernels that do not contain support for SOL_ALG. "ifdef" also contains check if ALG_SET_KEY and ALG_SET_AEAD_AUTHSIZE are defined. Signed-off-by: Yunqiang Su Signed-off-by: Aleksandar Markovic Reviewed-by: Laurent Vivier Message-Id: <1560953834-29584-3-git-send-email-aleksandar.markovic@rt-rk.com> Signed-off-by: Laurent Vivier --- linux-user/syscall.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'linux-user') diff --git a/linux-user/syscall.c b/linux-user/syscall.c index e942049..ed1c9b0 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -102,6 +102,7 @@ #include #include #include +#include #include "linux_loop.h" #include "uname.h" @@ -1941,6 +1942,36 @@ static abi_long do_setsockopt(int sockfd, int level, int optname, goto unimplemented; } break; +#if defined(SOL_ALG) && defined(ALG_SET_KEY) && defined(ALG_SET_AEAD_AUTHSIZE) + case SOL_ALG: + switch (optname) { + case ALG_SET_KEY: + { + char *alg_key = g_malloc(optlen); + + if (!alg_key) { + return -TARGET_ENOMEM; + } + if (copy_from_user(alg_key, optval_addr, optlen)) { + g_free(alg_key); + return -TARGET_EFAULT; + } + ret = get_errno(setsockopt(sockfd, level, optname, + alg_key, optlen)); + g_free(alg_key); + break; + } + case ALG_SET_AEAD_AUTHSIZE: + { + ret = get_errno(setsockopt(sockfd, level, optname, + NULL, optlen)); + break; + } + default: + goto unimplemented; + } + break; +#endif case TARGET_SOL_SOCKET: switch (optname) { case TARGET_SO_RCVTIMEO: -- cgit v1.1 From 22bf4ee9039be1df0febdb1b27e14b72acc6321b Mon Sep 17 00:00:00 2001 From: Neng Chen Date: Wed, 19 Jun 2019 16:17:10 +0200 Subject: linux-user: Add support for setsockopt() options IPV6__MEMBERSHIP Add support for the option IPV6__MEMBERSHIP of the syscall setsockopt(). This option controls membership in multicast groups. Argument is a pointer to a struct ipv6_mreq. The glibc header defines the ipv6_mreq structure, which includes the following members: struct in6_addr ipv6mr_multiaddr; unsigned int ipv6mr_interface; Whereas the kernel in its header defines following members of the same structure: struct in6_addr ipv6mr_multiaddr; int ipv6mr_ifindex; POSIX defines ipv6mr_interface [1]. __UAPI_DEF_IVP6_MREQ appears in kernel headers with v3.12: cfd280c91253 net: sync some IP headers with glibc Without __UAPI_DEF_IVP6_MREQ, kernel defines ipv6mr_ifindex, and this is explained in cfd280c91253: "If you include the kernel headers first you get those, and if you include the glibc headers first you get those, and the following patch arranges a coordination and synchronization between the two." So before 3.12, a program can't include both and . In linux-user/syscall.c, we only include (glibc) and not (kernel headers), so ipv6mr_interface is the one to use. [1] http://pubs.opengroup.org/onlinepubs/009695399/basedefs/netinet/in.h.html Signed-off-by: Neng Chen Signed-off-by: Aleksandar Markovic Reviewed-by: Laurent Vivier Message-Id: <1560953834-29584-2-git-send-email-aleksandar.markovic@rt-rk.com> Signed-off-by: Laurent Vivier --- linux-user/syscall.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'linux-user') diff --git a/linux-user/syscall.c b/linux-user/syscall.c index ed1c9b0..d2c9817 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1892,6 +1892,25 @@ static abi_long do_setsockopt(int sockfd, int level, int optname, &pki, sizeof(pki))); break; } + case IPV6_ADD_MEMBERSHIP: + case IPV6_DROP_MEMBERSHIP: + { + struct ipv6_mreq ipv6mreq; + + if (optlen < sizeof(ipv6mreq)) { + return -TARGET_EINVAL; + } + + if (copy_from_user(&ipv6mreq, optval_addr, sizeof(ipv6mreq))) { + return -TARGET_EFAULT; + } + + ipv6mreq.ipv6mr_interface = tswap32(ipv6mreq.ipv6mr_interface); + + ret = get_errno(setsockopt(sockfd, level, optname, + &ipv6mreq, sizeof(ipv6mreq))); + break; + } default: goto unimplemented; } -- cgit v1.1 From 24c373ec59f79a1cc32fc260e71b5b37efc99dd7 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Sun, 9 Jun 2019 16:35:20 +0200 Subject: linux-user: update PPC64 HWCAP2 feature list QEMU_PPC_FEATURE2_VEC_CRYPTO enables the use of VSX instructions in libcrypto that are accelerated by the TCG vector instructions now. QEMU_PPC_FEATURE2_DARN allows to use the new builtin qemu_guest_getrandom() function. Signed-off-by: Laurent Vivier Message-Id: <20190609143521.19374-1-laurent@vivier.eu> Signed-off-by: Laurent Vivier --- linux-user/elfload.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'linux-user') diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 9fd6570..bd43c48 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -768,7 +768,13 @@ enum { QEMU_PPC_FEATURE2_HAS_EBB = 0x10000000, /* Event Base Branching */ QEMU_PPC_FEATURE2_HAS_ISEL = 0x08000000, /* Integer Select */ QEMU_PPC_FEATURE2_HAS_TAR = 0x04000000, /* Target Address Register */ + QEMU_PPC_FEATURE2_VEC_CRYPTO = 0x02000000, + QEMU_PPC_FEATURE2_HTM_NOSC = 0x01000000, QEMU_PPC_FEATURE2_ARCH_3_00 = 0x00800000, /* ISA 3.00 */ + QEMU_PPC_FEATURE2_HAS_IEEE128 = 0x00400000, /* VSX IEEE Bin Float 128-bit */ + QEMU_PPC_FEATURE2_DARN = 0x00200000, /* darn random number insn */ + QEMU_PPC_FEATURE2_SCV = 0x00100000, /* scv syscall */ + QEMU_PPC_FEATURE2_HTM_NO_SUSPEND = 0x00080000, /* TM w/o suspended state */ }; #define ELF_HWCAP get_elf_hwcap() @@ -822,8 +828,10 @@ static uint32_t get_elf_hwcap2(void) GET_FEATURE(PPC_ISEL, QEMU_PPC_FEATURE2_HAS_ISEL); GET_FEATURE2(PPC2_BCTAR_ISA207, QEMU_PPC_FEATURE2_HAS_TAR); GET_FEATURE2((PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207 | - PPC2_ISA207S), QEMU_PPC_FEATURE2_ARCH_2_07); - GET_FEATURE2(PPC2_ISA300, QEMU_PPC_FEATURE2_ARCH_3_00); + PPC2_ISA207S), QEMU_PPC_FEATURE2_ARCH_2_07 | + QEMU_PPC_FEATURE2_VEC_CRYPTO); + GET_FEATURE2(PPC2_ISA300, QEMU_PPC_FEATURE2_ARCH_3_00 | + QEMU_PPC_FEATURE2_DARN); #undef GET_FEATURE #undef GET_FEATURE2 -- cgit v1.1 From b50d1e42a4a7dc746ecd42c34c386d81a997759c Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Sun, 9 Jun 2019 16:35:21 +0200 Subject: linux-user: set default PPC64 CPU The default CPU for pseries has been set to POWER9 by default. We can use the same default for linux-user Signed-off-by: Laurent Vivier Message-Id: <20190609143521.19374-2-laurent@vivier.eu> Signed-off-by: Laurent Vivier --- linux-user/ppc/target_elf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-user') diff --git a/linux-user/ppc/target_elf.h b/linux-user/ppc/target_elf.h index 576a5b9..0616618 100644 --- a/linux-user/ppc/target_elf.h +++ b/linux-user/ppc/target_elf.h @@ -10,7 +10,7 @@ static inline const char *cpu_get_model(uint32_t eflags) { #ifdef TARGET_PPC64 - return "POWER8"; + return "POWER9"; #else return "750"; #endif -- cgit v1.1