diff mbox series

[v2] linux-user: emulate msgsnd(), msgrcv() and semtimedop()

Message ID 20190529084804.25950-1-laurent@vivier.eu
State New
Headers show
Series [v2] linux-user: emulate msgsnd(), msgrcv() and semtimedop() | expand

Commit Message

Laurent Vivier May 29, 2019, 8:48 a.m. UTC
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 <laurent@vivier.eu>
---

Notes:
    v2: replace ENOSYS by TARGET_ENOSYS

 linux-user/syscall.c      | 61 +++++++++++++++++++--------------------
 linux-user/syscall_defs.h |  1 +
 2 files changed, 31 insertions(+), 31 deletions(-)

Comments

Cornelia Huck May 29, 2019, 9:31 a.m. UTC | #1
On Wed, 29 May 2019 10:48:04 +0200
Laurent Vivier <laurent@vivier.eu> wrote:

> 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 <laurent@vivier.eu>
> ---
> 
> Notes:
>     v2: replace ENOSYS by TARGET_ENOSYS
> 
>  linux-user/syscall.c      | 61 +++++++++++++++++++--------------------
>  linux-user/syscall_defs.h |  1 +
>  2 files changed, 31 insertions(+), 31 deletions(-)

I hope this headers update is now done with bringing joy :)

Not a linux-user expert, but it does look reasonable.

Reviewed-by: Cornelia Huck <cohuck@redhat.com>
Laurent Vivier June 24, 2019, 9 p.m. UTC | #2
Le 29/05/2019 à 10:48, Laurent Vivier a écrit :
> 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 <laurent@vivier.eu>
> ---
> 
> Notes:
>     v2: replace ENOSYS by TARGET_ENOSYS
> 
>  linux-user/syscall.c      | 61 +++++++++++++++++++--------------------
>  linux-user/syscall_defs.h |  1 +
>  2 files changed, 31 insertions(+), 31 deletions(-)
> 
> diff --git a/linux-user/syscall.c b/linux-user/syscall.c
> index 5e29e675e9cf..9ecbac463385 100644
> --- a/linux-user/syscall.c
> +++ b/linux-user/syscall.c
> @@ -763,50 +763,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,
> @@ -3530,11 +3501,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
> @@ -3689,7 +3670,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);
>  
> @@ -3717,7 +3707,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 7f141f699c1a..3175440e9dd9 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
> 

Applied to my linux-user branch.

Thanks,
Laurent
diff mbox series

Patch

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 5e29e675e9cf..9ecbac463385 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -763,50 +763,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,
@@ -3530,11 +3501,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
@@ -3689,7 +3670,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);
 
@@ -3717,7 +3707,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 7f141f699c1a..3175440e9dd9 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