diff options
author | Aleksandar Markovic <aleksandar.markovic@imgtec.com> | 2016-09-22 18:56:57 +0200 |
---|---|---|
committer | Riku Voipio <riku.voipio@linaro.org> | 2016-10-21 15:19:40 +0300 |
commit | ff71a4545c0d9b452e77a91ab1c46f79a10a9eca (patch) | |
tree | 1ef9e290fcfde01d191da39f12bfbd2f171b6195 | |
parent | da39db63e4468e39bb56d04d191866c5276aa7fa (diff) |
linux-user: Fix socketcall() syscall support
Since not all Linux host platforms support socketcall() (most notably
Intel), do_socketcall() function in Qemu's syscalls.c is implemented to
mirror the corespondant implementation of socketcall() in Linux kernel,
and to utilise individual socket operations that are supported on all
Linux platforms. (see kernel source file net/socket.c, definition of
socketcall).
However, error codes produced by Qemu implementation are wrong for the
cases of invalid values of the first argument. Also, naming of constants
is not consistent with kernel one, and not consistant with Qemu convention
of prefixing such constants with "TARGET_". This patch in that light
brings do_socketcall() closer to its kernel counterpart, and in that way
fixes the errors and yields more consisrtent Qemu code.
There were also three missing cases (among 20) for strace support for
socketcall(). The array that contains pointers for appropriate printing
functions is updated with 3 elements, however pointers to functions are
left NULL, and its implementation is left for future.
Also, this patch fixes failure of LTP test socketcall02, if executed on some
Qemu emulated sywstems (uer mode).
Signed-off-by: Aleksandar Markovic <aleksandar.markovic@imgtec.com>
Signed-off-by: Riku Voipio <riku.voipio@linaro.org>
-rw-r--r-- | linux-user/strace.c | 39 | ||||
-rw-r--r-- | linux-user/syscall.c | 119 | ||||
-rw-r--r-- | linux-user/syscall_defs.h | 42 |
3 files changed, 105 insertions, 95 deletions
diff --git a/linux-user/strace.c b/linux-user/strace.c index f37b386bda..a0e45b55d1 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -1675,29 +1675,32 @@ print_optint: } #define PRINT_SOCKOP(name, func) \ - [SOCKOP_##name] = { #name, func } + [TARGET_SYS_##name] = { #name, func } static struct { const char *name; void (*print)(const char *, abi_long); } scall[] = { - PRINT_SOCKOP(socket, do_print_socket), - PRINT_SOCKOP(bind, do_print_sockaddr), - PRINT_SOCKOP(connect, do_print_sockaddr), - PRINT_SOCKOP(listen, do_print_listen), - PRINT_SOCKOP(accept, do_print_sockaddr), - PRINT_SOCKOP(getsockname, do_print_sockaddr), - PRINT_SOCKOP(getpeername, do_print_sockaddr), - PRINT_SOCKOP(socketpair, do_print_socketpair), - PRINT_SOCKOP(send, do_print_sendrecv), - PRINT_SOCKOP(recv, do_print_sendrecv), - PRINT_SOCKOP(sendto, do_print_msgaddr), - PRINT_SOCKOP(recvfrom, do_print_msgaddr), - PRINT_SOCKOP(shutdown, do_print_shutdown), - PRINT_SOCKOP(sendmsg, do_print_msg), - PRINT_SOCKOP(recvmsg, do_print_msg), - PRINT_SOCKOP(setsockopt, do_print_sockopt), - PRINT_SOCKOP(getsockopt, do_print_sockopt), + PRINT_SOCKOP(SOCKET, do_print_socket), + PRINT_SOCKOP(BIND, do_print_sockaddr), + PRINT_SOCKOP(CONNECT, do_print_sockaddr), + PRINT_SOCKOP(LISTEN, do_print_listen), + PRINT_SOCKOP(ACCEPT, do_print_sockaddr), + PRINT_SOCKOP(GETSOCKNAME, do_print_sockaddr), + PRINT_SOCKOP(GETPEERNAME, do_print_sockaddr), + PRINT_SOCKOP(SOCKETPAIR, do_print_socketpair), + PRINT_SOCKOP(SEND, do_print_sendrecv), + PRINT_SOCKOP(RECV, do_print_sendrecv), + PRINT_SOCKOP(SENDTO, do_print_msgaddr), + PRINT_SOCKOP(RECVFROM, do_print_msgaddr), + PRINT_SOCKOP(SHUTDOWN, do_print_shutdown), + PRINT_SOCKOP(SETSOCKOPT, do_print_sockopt), + PRINT_SOCKOP(GETSOCKOPT, do_print_sockopt), + PRINT_SOCKOP(SENDMSG, do_print_msg), + PRINT_SOCKOP(RECVMSG, do_print_msg), + PRINT_SOCKOP(ACCEPT4, NULL), + PRINT_SOCKOP(RECVMMSG, NULL), + PRINT_SOCKOP(SENDMMSG, NULL), }; static void diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 36ca921a7e..7ea23ad6ce 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -3897,89 +3897,94 @@ fail: } #ifdef TARGET_NR_socketcall -/* do_socketcall() Must return target values and target errnos. */ +/* do_socketcall() must return target values and target errnos. */ static abi_long do_socketcall(int num, abi_ulong vptr) { - static const unsigned ac[] = { /* number of arguments per call */ - [SOCKOP_socket] = 3, /* domain, type, protocol */ - [SOCKOP_bind] = 3, /* sockfd, addr, addrlen */ - [SOCKOP_connect] = 3, /* sockfd, addr, addrlen */ - [SOCKOP_listen] = 2, /* sockfd, backlog */ - [SOCKOP_accept] = 3, /* sockfd, addr, addrlen */ - [SOCKOP_accept4] = 4, /* sockfd, addr, addrlen, flags */ - [SOCKOP_getsockname] = 3, /* sockfd, addr, addrlen */ - [SOCKOP_getpeername] = 3, /* sockfd, addr, addrlen */ - [SOCKOP_socketpair] = 4, /* domain, type, protocol, tab */ - [SOCKOP_send] = 4, /* sockfd, msg, len, flags */ - [SOCKOP_recv] = 4, /* sockfd, msg, len, flags */ - [SOCKOP_sendto] = 6, /* sockfd, msg, len, flags, addr, addrlen */ - [SOCKOP_recvfrom] = 6, /* sockfd, msg, len, flags, addr, addrlen */ - [SOCKOP_shutdown] = 2, /* sockfd, how */ - [SOCKOP_sendmsg] = 3, /* sockfd, msg, flags */ - [SOCKOP_recvmsg] = 3, /* sockfd, msg, flags */ - [SOCKOP_sendmmsg] = 4, /* sockfd, msgvec, vlen, flags */ - [SOCKOP_recvmmsg] = 4, /* sockfd, msgvec, vlen, flags */ - [SOCKOP_setsockopt] = 5, /* sockfd, level, optname, optval, optlen */ - [SOCKOP_getsockopt] = 5, /* sockfd, level, optname, optval, optlen */ + static const unsigned nargs[] = { /* number of arguments per operation */ + [TARGET_SYS_SOCKET] = 3, /* domain, type, protocol */ + [TARGET_SYS_BIND] = 3, /* fd, addr, addrlen */ + [TARGET_SYS_CONNECT] = 3, /* fd, addr, addrlen */ + [TARGET_SYS_LISTEN] = 2, /* fd, backlog */ + [TARGET_SYS_ACCEPT] = 3, /* fd, addr, addrlen */ + [TARGET_SYS_GETSOCKNAME] = 3, /* fd, addr, addrlen */ + [TARGET_SYS_GETPEERNAME] = 3, /* fd, addr, addrlen */ + [TARGET_SYS_SOCKETPAIR] = 4, /* domain, type, protocol, tab */ + [TARGET_SYS_SEND] = 4, /* fd, msg, len, flags */ + [TARGET_SYS_RECV] = 4, /* fd, msg, len, flags */ + [TARGET_SYS_SENDTO] = 6, /* fd, msg, len, flags, addr, addrlen */ + [TARGET_SYS_RECVFROM] = 6, /* fd, msg, len, flags, addr, addrlen */ + [TARGET_SYS_SHUTDOWN] = 2, /* fd, how */ + [TARGET_SYS_SETSOCKOPT] = 5, /* fd, level, optname, optval, optlen */ + [TARGET_SYS_GETSOCKOPT] = 5, /* fd, level, optname, optval, optlen */ + [TARGET_SYS_SENDMSG] = 3, /* fd, msg, flags */ + [TARGET_SYS_RECVMSG] = 3, /* fd, msg, flags */ + [TARGET_SYS_ACCEPT4] = 4, /* fd, addr, addrlen, flags */ + [TARGET_SYS_RECVMMSG] = 4, /* fd, msgvec, vlen, flags */ + [TARGET_SYS_SENDMMSG] = 4, /* fd, msgvec, vlen, flags */ }; abi_long a[6]; /* max 6 args */ + unsigned i; - /* first, collect the arguments in a[] according to ac[] */ - if (num >= 0 && num < ARRAY_SIZE(ac)) { - unsigned i; - assert(ARRAY_SIZE(a) >= ac[num]); /* ensure we have space for args */ - for (i = 0; i < ac[num]; ++i) { - if (get_user_ual(a[i], vptr + i * sizeof(abi_long)) != 0) { - return -TARGET_EFAULT; - } + /* check the range of the first argument num */ + /* (TARGET_SYS_SENDMMSG is the highest among TARGET_SYS_xxx) */ + if (num < 1 || num > TARGET_SYS_SENDMMSG) { + return -TARGET_EINVAL; + } + /* ensure we have space for args */ + if (nargs[num] > ARRAY_SIZE(a)) { + return -TARGET_EINVAL; + } + /* collect the arguments in a[] according to nargs[] */ + for (i = 0; i < nargs[num]; ++i) { + if (get_user_ual(a[i], vptr + i * sizeof(abi_long)) != 0) { + return -TARGET_EFAULT; } } - - /* now when we have the args, actually handle the call */ + /* now when we have the args, invoke the appropriate underlying function */ switch (num) { - case SOCKOP_socket: /* domain, type, protocol */ + case TARGET_SYS_SOCKET: /* domain, type, protocol */ return do_socket(a[0], a[1], a[2]); - case SOCKOP_bind: /* sockfd, addr, addrlen */ + case TARGET_SYS_BIND: /* sockfd, addr, addrlen */ return do_bind(a[0], a[1], a[2]); - case SOCKOP_connect: /* sockfd, addr, addrlen */ + case TARGET_SYS_CONNECT: /* sockfd, addr, addrlen */ return do_connect(a[0], a[1], a[2]); - case SOCKOP_listen: /* sockfd, backlog */ + case TARGET_SYS_LISTEN: /* sockfd, backlog */ return get_errno(listen(a[0], a[1])); - case SOCKOP_accept: /* sockfd, addr, addrlen */ + case TARGET_SYS_ACCEPT: /* sockfd, addr, addrlen */ return do_accept4(a[0], a[1], a[2], 0); - case SOCKOP_accept4: /* sockfd, addr, addrlen, flags */ - return do_accept4(a[0], a[1], a[2], a[3]); - case SOCKOP_getsockname: /* sockfd, addr, addrlen */ + case TARGET_SYS_GETSOCKNAME: /* sockfd, addr, addrlen */ return do_getsockname(a[0], a[1], a[2]); - case SOCKOP_getpeername: /* sockfd, addr, addrlen */ + case TARGET_SYS_GETPEERNAME: /* sockfd, addr, addrlen */ return do_getpeername(a[0], a[1], a[2]); - case SOCKOP_socketpair: /* domain, type, protocol, tab */ + case TARGET_SYS_SOCKETPAIR: /* domain, type, protocol, tab */ return do_socketpair(a[0], a[1], a[2], a[3]); - case SOCKOP_send: /* sockfd, msg, len, flags */ + case TARGET_SYS_SEND: /* sockfd, msg, len, flags */ return do_sendto(a[0], a[1], a[2], a[3], 0, 0); - case SOCKOP_recv: /* sockfd, msg, len, flags */ + case TARGET_SYS_RECV: /* sockfd, msg, len, flags */ return do_recvfrom(a[0], a[1], a[2], a[3], 0, 0); - case SOCKOP_sendto: /* sockfd, msg, len, flags, addr, addrlen */ + case TARGET_SYS_SENDTO: /* sockfd, msg, len, flags, addr, addrlen */ return do_sendto(a[0], a[1], a[2], a[3], a[4], a[5]); - case SOCKOP_recvfrom: /* sockfd, msg, len, flags, addr, addrlen */ + case TARGET_SYS_RECVFROM: /* sockfd, msg, len, flags, addr, addrlen */ return do_recvfrom(a[0], a[1], a[2], a[3], a[4], a[5]); - case SOCKOP_shutdown: /* sockfd, how */ + case TARGET_SYS_SHUTDOWN: /* sockfd, how */ return get_errno(shutdown(a[0], a[1])); - case SOCKOP_sendmsg: /* sockfd, msg, flags */ + case TARGET_SYS_SETSOCKOPT: /* sockfd, level, optname, optval, optlen */ + return do_setsockopt(a[0], a[1], a[2], a[3], a[4]); + case TARGET_SYS_GETSOCKOPT: /* sockfd, level, optname, optval, optlen */ + return do_getsockopt(a[0], a[1], a[2], a[3], a[4]); + case TARGET_SYS_SENDMSG: /* sockfd, msg, flags */ return do_sendrecvmsg(a[0], a[1], a[2], 1); - case SOCKOP_recvmsg: /* sockfd, msg, flags */ + case TARGET_SYS_RECVMSG: /* sockfd, msg, flags */ return do_sendrecvmsg(a[0], a[1], a[2], 0); - case SOCKOP_sendmmsg: /* sockfd, msgvec, vlen, flags */ - return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 1); - case SOCKOP_recvmmsg: /* sockfd, msgvec, vlen, flags */ + case TARGET_SYS_ACCEPT4: /* sockfd, addr, addrlen, flags */ + return do_accept4(a[0], a[1], a[2], a[3]); + case TARGET_SYS_RECVMMSG: /* sockfd, msgvec, vlen, flags */ return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 0); - case SOCKOP_setsockopt: /* sockfd, level, optname, optval, optlen */ - return do_setsockopt(a[0], a[1], a[2], a[3], a[4]); - case SOCKOP_getsockopt: /* sockfd, level, optname, optval, optlen */ - return do_getsockopt(a[0], a[1], a[2], a[3], a[4]); + case TARGET_SYS_SENDMMSG: /* sockfd, msgvec, vlen, flags */ + return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 1); default: gemu_log("Unsupported socketcall: %d\n", num); - return -TARGET_ENOSYS; + return -TARGET_EINVAL; } } #endif diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index ca8fa6ee91..e70977169f 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -9,26 +9,28 @@ #include "syscall_nr.h" -#define SOCKOP_socket 1 -#define SOCKOP_bind 2 -#define SOCKOP_connect 3 -#define SOCKOP_listen 4 -#define SOCKOP_accept 5 -#define SOCKOP_getsockname 6 -#define SOCKOP_getpeername 7 -#define SOCKOP_socketpair 8 -#define SOCKOP_send 9 -#define SOCKOP_recv 10 -#define SOCKOP_sendto 11 -#define SOCKOP_recvfrom 12 -#define SOCKOP_shutdown 13 -#define SOCKOP_setsockopt 14 -#define SOCKOP_getsockopt 15 -#define SOCKOP_sendmsg 16 -#define SOCKOP_recvmsg 17 -#define SOCKOP_accept4 18 -#define SOCKOP_recvmmsg 19 -#define SOCKOP_sendmmsg 20 + +/* socket operations for socketcall() */ +#define TARGET_SYS_SOCKET 1 /* socket() */ +#define TARGET_SYS_BIND 2 /* bind() */ +#define TARGET_SYS_CONNECT 3 /* connect() */ +#define TARGET_SYS_LISTEN 4 /* listen() */ +#define TARGET_SYS_ACCEPT 5 /* accept() */ +#define TARGET_SYS_GETSOCKNAME 6 /* getsockname() */ +#define TARGET_SYS_GETPEERNAME 7 /* getpeername() */ +#define TARGET_SYS_SOCKETPAIR 8 /* socketpair() */ +#define TARGET_SYS_SEND 9 /* send() */ +#define TARGET_SYS_RECV 10 /* recv() */ +#define TARGET_SYS_SENDTO 11 /* sendto() */ +#define TARGET_SYS_RECVFROM 12 /* recvfrom() */ +#define TARGET_SYS_SHUTDOWN 13 /* shutdown() */ +#define TARGET_SYS_SETSOCKOPT 14 /* setsockopt() */ +#define TARGET_SYS_GETSOCKOPT 15 /* getsockopt() */ +#define TARGET_SYS_SENDMSG 16 /* sendmsg() */ +#define TARGET_SYS_RECVMSG 17 /* recvmsg() */ +#define TARGET_SYS_ACCEPT4 18 /* accept4() */ +#define TARGET_SYS_RECVMMSG 19 /* recvmmsg() */ +#define TARGET_SYS_SENDMMSG 20 /* sendmmsg() */ #define IPCOP_semop 1 #define IPCOP_semget 2 |