diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2016-07-20 11:32:12 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2016-07-20 11:32:12 +0100 |
commit | 1ecfb24da987b862fd46a5b37292879952ea9e7d (patch) | |
tree | b439cff13dfa5dbcd156501856dd4bdaaa1ec02b | |
parent | 5d3217340adcb6c4f0e4af5d2b865331eb2ff63d (diff) | |
parent | c4e1cbd437776f99d45d7d2ddd7543ee3883ac98 (diff) |
Merge remote-tracking branch 'remotes/riku/tags/pull-linux-user-20160719-2' into staging
linux-user fixes before 2.7 freeze, fix commit message
# gpg: Signature made Tue 19 Jul 2016 14:18:54 BST
# gpg: using RSA key 0xB44890DEDE3C9BC0
# gpg: Good signature from "Riku Voipio <riku.voipio@iki.fi>"
# gpg: aka "Riku Voipio <riku.voipio@linaro.org>"
# Primary key fingerprint: FF82 03C8 C391 98AE 0581 41EF B448 90DE DE3C 9BC0
* remotes/riku/tags/pull-linux-user-20160719-2:
linux-user: AArch64 has sync_file_range, not sync_file_range2
linux-user: Fix type for SIOCATMARK ioctl
linux-user: define missing sparc syscalls
linux-user: Fix terminal control ioctls
linux-user: Add some new blk ioctls
linux-user: Handle short lengths in host_to_target_sockaddr()
linux-user: Forget about synchronous signal once it is delivered
linux-user: Correct type for LOOP_GET_STATUS{,64} ioctls
linux-user: Correct type for BLKSSZGET
linux-user: Add loop control ioctls
linux-user: Check sigsetsize argument to syscalls
linux-user: add nested netlink types
linux-user: convert sockaddr_ll from host to target
linux-user: add fd_trans helper in do_recvfrom()
linux-user: fix netlink memory corruption
linux-user: fd_trans_*_data() returns the length
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r-- | linux-user/aarch64/syscall_nr.h | 3 | ||||
-rw-r--r-- | linux-user/ioctls.h | 41 | ||||
-rw-r--r-- | linux-user/linux_loop.h | 11 | ||||
-rw-r--r-- | linux-user/signal.c | 8 | ||||
-rw-r--r-- | linux-user/sparc/syscall_nr.h | 3 | ||||
-rw-r--r-- | linux-user/syscall.c | 454 | ||||
-rw-r--r-- | linux-user/syscall_defs.h | 15 | ||||
-rw-r--r-- | linux-user/syscall_types.h | 9 | ||||
-rw-r--r-- | linux-user/x86_64/termbits.h | 12 |
9 files changed, 516 insertions, 40 deletions
diff --git a/linux-user/aarch64/syscall_nr.h b/linux-user/aarch64/syscall_nr.h index 59511d855d..a3c9a3b679 100644 --- a/linux-user/aarch64/syscall_nr.h +++ b/linux-user/aarch64/syscall_nr.h @@ -86,8 +86,7 @@ #define TARGET_NR_sync 81 #define TARGET_NR_fsync 82 #define TARGET_NR_fdatasync 83 -#define TARGET_NR_sync_file_range2 84 -/* #define TARGET_NR_sync_file_range 84 */ +#define TARGET_NR_sync_file_range 84 #define TARGET_NR_timerfd_create 85 #define TARGET_NR_timerfd_settime 86 #define TARGET_NR_timerfd_gettime 87 diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h index e672655100..7e2c133ba1 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h @@ -76,10 +76,39 @@ IOCTL(BLKFLSBUF, 0, TYPE_NULL) IOCTL(BLKRASET, 0, TYPE_INT) IOCTL(BLKRAGET, IOC_R, MK_PTR(TYPE_LONG)) - IOCTL(BLKSSZGET, IOC_R, MK_PTR(TYPE_LONG)) + IOCTL(BLKSSZGET, IOC_R, MK_PTR(TYPE_INT)) IOCTL(BLKBSZGET, IOC_R, MK_PTR(TYPE_INT)) IOCTL_SPECIAL(BLKPG, IOC_W, do_ioctl_blkpg, MK_PTR(MK_STRUCT(STRUCT_blkpg_ioctl_arg))) + +#ifdef BLKDISCARD + IOCTL(BLKDISCARD, IOC_W, MK_PTR(MK_ARRAY(TYPE_ULONGLONG, 2))) +#endif +#ifdef BLKIOMIN + IOCTL(BLKIOMIN, IOC_R, MK_PTR(TYPE_INT)) +#endif +#ifdef BLKIOOPT + IOCTL(BLKIOOPT, IOC_R, MK_PTR(TYPE_INT)) +#endif +#ifdef BLKALIGNOFF + IOCTL(BLKALIGNOFF, IOC_R, MK_PTR(TYPE_INT)) +#endif +#ifdef BLKPBSZGET + IOCTL(BLKPBSZGET, IOC_R, MK_PTR(TYPE_INT)) +#endif +#ifdef BLKDISCARDZEROES + IOCTL(BLKDISCARDZEROES, IOC_R, MK_PTR(TYPE_INT)) +#endif +#ifdef BLKSECDISCARD + IOCTL(BLKSECDISCARD, IOC_W, MK_PTR(MK_ARRAY(TYPE_ULONGLONG, 2))) +#endif +#ifdef BLKROTATIONAL + IOCTL(BLKROTATIONAL, IOC_R, MK_PTR(TYPE_SHORT)) +#endif +#ifdef BLKZEROOUT + IOCTL(BLKZEROOUT, IOC_W, MK_PTR(MK_ARRAY(TYPE_ULONGLONG, 2))) +#endif + #ifdef FIBMAP IOCTL(FIBMAP, IOC_W | IOC_R, MK_PTR(TYPE_LONG)) #endif @@ -91,7 +120,7 @@ MK_PTR(MK_STRUCT(STRUCT_fiemap))) #endif - IOCTL(SIOCATMARK, 0, TYPE_NULL) + IOCTL(SIOCATMARK, IOC_R, MK_PTR(TYPE_INT)) IOCTL(SIOCGIFNAME, IOC_RW, MK_PTR(TYPE_INT)) IOCTL(SIOCGIFFLAGS, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_short_ifreq))) IOCTL(SIOCSIFFLAGS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_short_ifreq))) @@ -322,11 +351,15 @@ IOCTL(LOOP_SET_FD, 0, TYPE_INT) IOCTL(LOOP_CLR_FD, 0, TYPE_INT) IOCTL(LOOP_SET_STATUS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_loop_info))) - IOCTL(LOOP_GET_STATUS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_loop_info))) + IOCTL(LOOP_GET_STATUS, IOC_R, MK_PTR(MK_STRUCT(STRUCT_loop_info))) IOCTL(LOOP_SET_STATUS64, IOC_W, MK_PTR(MK_STRUCT(STRUCT_loop_info64))) - IOCTL(LOOP_GET_STATUS64, IOC_W, MK_PTR(MK_STRUCT(STRUCT_loop_info64))) + IOCTL(LOOP_GET_STATUS64, IOC_R, MK_PTR(MK_STRUCT(STRUCT_loop_info64))) IOCTL(LOOP_CHANGE_FD, 0, TYPE_INT) + IOCTL(LOOP_CTL_ADD, 0, TYPE_INT) + IOCTL(LOOP_CTL_REMOVE, 0, TYPE_INT) + IOCTL(LOOP_CTL_GET_FREE, 0, TYPE_NULL) + IOCTL(MTIOCTOP, IOC_W, MK_PTR(MK_STRUCT(STRUCT_mtop))) IOCTL(MTIOCGET, IOC_R, MK_PTR(MK_STRUCT(STRUCT_mtget))) IOCTL(MTIOCPOS, IOC_R, MK_PTR(MK_STRUCT(STRUCT_mtpos))) diff --git a/linux-user/linux_loop.h b/linux-user/linux_loop.h index 1f52403814..c69fea11e4 100644 --- a/linux-user/linux_loop.h +++ b/linux-user/linux_loop.h @@ -1,4 +1,6 @@ -/* Copied from 2.6.25 kernel headers to avoid problems on older hosts. */ +/* Copied from 2.6.25 kernel headers to avoid problems on older hosts, + * and subsequently updated to match newer additions to the API. + */ #ifndef LINUX_LOOP_H #define LINUX_LOOP_H @@ -92,5 +94,12 @@ struct loop_info64 { #define LOOP_SET_STATUS64 0x4C04 #define LOOP_GET_STATUS64 0x4C05 #define LOOP_CHANGE_FD 0x4C06 +#define LOOP_SET_CAPACITY 0x4C07 +#define LOOP_SET_DIRECT_IO 0x4C08 + +/* /dev/loop-control interface */ +#define LOOP_CTL_ADD 0x4C80 +#define LOOP_CTL_REMOVE 0x4C81 +#define LOOP_CTL_GET_FREE 0x4C82 #endif diff --git a/linux-user/signal.c b/linux-user/signal.c index 9d980456ec..9a4d894e3a 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -5826,7 +5826,8 @@ long do_rt_sigreturn(CPUArchState *env) #endif -static void handle_pending_signal(CPUArchState *cpu_env, int sig) +static void handle_pending_signal(CPUArchState *cpu_env, int sig, + struct emulated_sigtable *k) { CPUState *cpu = ENV_GET_CPU(cpu_env); abi_ulong handler; @@ -5834,7 +5835,6 @@ static void handle_pending_signal(CPUArchState *cpu_env, int sig) target_sigset_t target_old_set; struct target_sigaction *sa; TaskState *ts = cpu->opaque; - struct emulated_sigtable *k = &ts->sigtab[sig - 1]; trace_user_handle_signal(cpu_env, sig); /* dequeue signal */ @@ -5937,7 +5937,7 @@ void process_pending_signals(CPUArchState *cpu_env) sigact_table[sig - 1]._sa_handler = TARGET_SIG_DFL; } - handle_pending_signal(cpu_env, sig); + handle_pending_signal(cpu_env, sig, &ts->sync_signal); } for (sig = 1; sig <= TARGET_NSIG; sig++) { @@ -5947,7 +5947,7 @@ void process_pending_signals(CPUArchState *cpu_env) if (ts->sigtab[sig - 1].pending && (!sigismember(blocked_set, target_to_host_signal_table[sig]))) { - handle_pending_signal(cpu_env, sig); + handle_pending_signal(cpu_env, sig, &ts->sigtab[sig - 1]); /* Restart scan from the beginning */ sig = 1; } diff --git a/linux-user/sparc/syscall_nr.h b/linux-user/sparc/syscall_nr.h index 732b1052a4..e713c9d5f4 100644 --- a/linux-user/sparc/syscall_nr.h +++ b/linux-user/sparc/syscall_nr.h @@ -179,6 +179,9 @@ #define TARGET_NR_readahead 205 /* Linux Specific */ #define TARGET_NR_socketcall 206 /* Linux Specific */ #define TARGET_NR_syslog 207 /* Linux Specific */ +#define TARGET_NR_lookup_dcookie 208 /* Linux Specific */ +#define TARGET_NR_fadvise64 209 /* Linux Specific */ +#define TARGET_NR_fadvise64_64 210 /* Linux Specific */ #define TARGET_NR_tgkill 211 /* Linux Specific */ #define TARGET_NR_waitpid 212 /* Linux Specific */ #define TARGET_NR_swapoff 213 /* Linux Specific */ diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 8bf6205dc2..ca6a2b495a 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -100,9 +100,11 @@ int __clone2(int (*fn)(void *), void *child_stack_base, #include <linux/route.h> #include <linux/filter.h> #include <linux/blkpg.h> +#include <netpacket/packet.h> #include <linux/netlink.h> #ifdef CONFIG_RTNETLINK #include <linux/rtnetlink.h> +#include <linux/if_bridge.h> #endif #include <linux/audit.h> #include "linux_loop.h" @@ -1374,15 +1376,26 @@ static inline abi_long host_to_target_sockaddr(abi_ulong target_addr, { struct target_sockaddr *target_saddr; + if (len == 0) { + return 0; + } + target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0); if (!target_saddr) return -TARGET_EFAULT; memcpy(target_saddr, addr, len); - target_saddr->sa_family = tswap16(addr->sa_family); - if (addr->sa_family == AF_NETLINK) { + if (len >= offsetof(struct target_sockaddr, sa_family) + + sizeof(target_saddr->sa_family)) { + target_saddr->sa_family = tswap16(addr->sa_family); + } + if (addr->sa_family == AF_NETLINK && len >= sizeof(struct sockaddr_nl)) { struct sockaddr_nl *target_nl = (struct sockaddr_nl *)target_saddr; target_nl->nl_pid = tswap32(target_nl->nl_pid); target_nl->nl_groups = tswap32(target_nl->nl_groups); + } else if (addr->sa_family == AF_PACKET) { + struct sockaddr_ll *target_ll = (struct sockaddr_ll *)target_saddr; + target_ll->sll_ifindex = tswap32(target_ll->sll_ifindex); + target_ll->sll_hatype = tswap16(target_ll->sll_hatype); } unlock_user(target_saddr, target_addr, len); @@ -1707,6 +1720,33 @@ static abi_long target_to_host_for_each_nlmsg(struct nlmsghdr *nlh, } #ifdef CONFIG_RTNETLINK +static abi_long host_to_target_for_each_nlattr(struct nlattr *nlattr, + size_t len, void *context, + abi_long (*host_to_target_nlattr) + (struct nlattr *, + void *context)) +{ + unsigned short nla_len; + abi_long ret; + + while (len > sizeof(struct nlattr)) { + nla_len = nlattr->nla_len; + if (nla_len < sizeof(struct nlattr) || + nla_len > len) { + break; + } + ret = host_to_target_nlattr(nlattr, context); + nlattr->nla_len = tswap16(nlattr->nla_len); + nlattr->nla_type = tswap16(nlattr->nla_type); + if (ret < 0) { + return ret; + } + len -= NLA_ALIGN(nla_len); + nlattr = (struct nlattr *)(((char *)nlattr) + NLA_ALIGN(nla_len)); + } + return 0; +} + static abi_long host_to_target_for_each_rtattr(struct rtattr *rtattr, size_t len, abi_long (*host_to_target_rtattr) @@ -1733,12 +1773,292 @@ static abi_long host_to_target_for_each_rtattr(struct rtattr *rtattr, return 0; } +#define NLA_DATA(nla) ((void *)((char *)(nla)) + NLA_HDRLEN) + +static abi_long host_to_target_data_bridge_nlattr(struct nlattr *nlattr, + void *context) +{ + uint16_t *u16; + uint32_t *u32; + uint64_t *u64; + + switch (nlattr->nla_type) { + /* no data */ + case IFLA_BR_FDB_FLUSH: + break; + /* binary */ + case IFLA_BR_GROUP_ADDR: + break; + /* uint8_t */ + case IFLA_BR_VLAN_FILTERING: + case IFLA_BR_TOPOLOGY_CHANGE: + case IFLA_BR_TOPOLOGY_CHANGE_DETECTED: + case IFLA_BR_MCAST_ROUTER: + case IFLA_BR_MCAST_SNOOPING: + case IFLA_BR_MCAST_QUERY_USE_IFADDR: + case IFLA_BR_MCAST_QUERIER: + case IFLA_BR_NF_CALL_IPTABLES: + case IFLA_BR_NF_CALL_IP6TABLES: + case IFLA_BR_NF_CALL_ARPTABLES: + break; + /* uint16_t */ + case IFLA_BR_PRIORITY: + case IFLA_BR_VLAN_PROTOCOL: + case IFLA_BR_GROUP_FWD_MASK: + case IFLA_BR_ROOT_PORT: + case IFLA_BR_VLAN_DEFAULT_PVID: + u16 = NLA_DATA(nlattr); + *u16 = tswap16(*u16); + break; + /* uint32_t */ + case IFLA_BR_FORWARD_DELAY: + case IFLA_BR_HELLO_TIME: + case IFLA_BR_MAX_AGE: + case IFLA_BR_AGEING_TIME: + case IFLA_BR_STP_STATE: + case IFLA_BR_ROOT_PATH_COST: + case IFLA_BR_MCAST_HASH_ELASTICITY: + case IFLA_BR_MCAST_HASH_MAX: + case IFLA_BR_MCAST_LAST_MEMBER_CNT: + case IFLA_BR_MCAST_STARTUP_QUERY_CNT: + u32 = NLA_DATA(nlattr); + *u32 = tswap32(*u32); + break; + /* uint64_t */ + case IFLA_BR_HELLO_TIMER: + case IFLA_BR_TCN_TIMER: + case IFLA_BR_GC_TIMER: + case IFLA_BR_TOPOLOGY_CHANGE_TIMER: + case IFLA_BR_MCAST_LAST_MEMBER_INTVL: + case IFLA_BR_MCAST_MEMBERSHIP_INTVL: + case IFLA_BR_MCAST_QUERIER_INTVL: + case IFLA_BR_MCAST_QUERY_INTVL: + case IFLA_BR_MCAST_QUERY_RESPONSE_INTVL: + case IFLA_BR_MCAST_STARTUP_QUERY_INTVL: + u64 = NLA_DATA(nlattr); + *u64 = tswap64(*u64); + break; + /* ifla_bridge_id: uin8_t[] */ + case IFLA_BR_ROOT_ID: + case IFLA_BR_BRIDGE_ID: + break; + default: + gemu_log("Unknown IFLA_BR type %d\n", nlattr->nla_type); + break; + } + return 0; +} + +static abi_long host_to_target_slave_data_bridge_nlattr(struct nlattr *nlattr, + void *context) +{ + uint16_t *u16; + uint32_t *u32; + uint64_t *u64; + + switch (nlattr->nla_type) { + /* uint8_t */ + case IFLA_BRPORT_STATE: + case IFLA_BRPORT_MODE: + case IFLA_BRPORT_GUARD: + case IFLA_BRPORT_PROTECT: + case IFLA_BRPORT_FAST_LEAVE: + case IFLA_BRPORT_LEARNING: + case IFLA_BRPORT_UNICAST_FLOOD: + case IFLA_BRPORT_PROXYARP: + case IFLA_BRPORT_LEARNING_SYNC: + case IFLA_BRPORT_PROXYARP_WIFI: + case IFLA_BRPORT_TOPOLOGY_CHANGE_ACK: + case IFLA_BRPORT_CONFIG_PENDING: + case IFLA_BRPORT_MULTICAST_ROUTER: + break; + /* uint16_t */ + case IFLA_BRPORT_PRIORITY: + case IFLA_BRPORT_DESIGNATED_PORT: + case IFLA_BRPORT_DESIGNATED_COST: + case IFLA_BRPORT_ID: + case IFLA_BRPORT_NO: + u16 = NLA_DATA(nlattr); + *u16 = tswap16(*u16); + break; + /* uin32_t */ + case IFLA_BRPORT_COST: + u32 = NLA_DATA(nlattr); + *u32 = tswap32(*u32); + break; + /* uint64_t */ + case IFLA_BRPORT_MESSAGE_AGE_TIMER: + case IFLA_BRPORT_FORWARD_DELAY_TIMER: + case IFLA_BRPORT_HOLD_TIMER: + u64 = NLA_DATA(nlattr); + *u64 = tswap64(*u64); + break; + /* ifla_bridge_id: uint8_t[] */ + case IFLA_BRPORT_ROOT_ID: + case IFLA_BRPORT_BRIDGE_ID: + break; + default: + gemu_log("Unknown IFLA_BRPORT type %d\n", nlattr->nla_type); + break; + } + return 0; +} + +struct linkinfo_context { + int len; + char *name; + int slave_len; + char *slave_name; +}; + +static abi_long host_to_target_data_linkinfo_nlattr(struct nlattr *nlattr, + void *context) +{ + struct linkinfo_context *li_context = context; + + switch (nlattr->nla_type) { + /* string */ + case IFLA_INFO_KIND: + li_context->name = NLA_DATA(nlattr); + li_context->len = nlattr->nla_len - NLA_HDRLEN; + break; + case IFLA_INFO_SLAVE_KIND: + li_context->slave_name = NLA_DATA(nlattr); + li_context->slave_len = nlattr->nla_len - NLA_HDRLEN; + break; + /* stats */ + case IFLA_INFO_XSTATS: + /* FIXME: only used by CAN */ + break; + /* nested */ + case IFLA_INFO_DATA: + if (strncmp(li_context->name, "bridge", + li_context->len) == 0) { + return host_to_target_for_each_nlattr(NLA_DATA(nlattr), + nlattr->nla_len, + NULL, + host_to_target_data_bridge_nlattr); + } else { + gemu_log("Unknown IFLA_INFO_KIND %s\n", li_context->name); + } + break; + case IFLA_INFO_SLAVE_DATA: + if (strncmp(li_context->slave_name, "bridge", + li_context->slave_len) == 0) { + return host_to_target_for_each_nlattr(NLA_DATA(nlattr), + nlattr->nla_len, + NULL, + host_to_target_slave_data_bridge_nlattr); + } else { + gemu_log("Unknown IFLA_INFO_SLAVE_KIND %s\n", + li_context->slave_name); + } + break; + default: + gemu_log("Unknown host IFLA_INFO type: %d\n", nlattr->nla_type); + break; + } + + return 0; +} + +static abi_long host_to_target_data_inet_nlattr(struct nlattr *nlattr, + void *context) +{ + uint32_t *u32; + int i; + + switch (nlattr->nla_type) { + case IFLA_INET_CONF: + u32 = NLA_DATA(nlattr); + for (i = 0; i < (nlattr->nla_len - NLA_HDRLEN) / sizeof(*u32); + i++) { + u32[i] = tswap32(u32[i]); + } + break; + default: + gemu_log("Unknown host AF_INET type: %d\n", nlattr->nla_type); + } + return 0; +} + +static abi_long host_to_target_data_inet6_nlattr(struct nlattr *nlattr, + void *context) +{ + uint32_t *u32; + uint64_t *u64; + struct ifla_cacheinfo *ci; + int i; + + switch (nlattr->nla_type) { + /* binaries */ + case IFLA_INET6_TOKEN: + break; + /* uint8_t */ + case IFLA_INET6_ADDR_GEN_MODE: + break; + /* uint32_t */ + case IFLA_INET6_FLAGS: + u32 = NLA_DATA(nlattr); + *u32 = tswap32(*u32); + break; + /* uint32_t[] */ + case IFLA_INET6_CONF: + u32 = NLA_DATA(nlattr); + for (i = 0; i < (nlattr->nla_len - NLA_HDRLEN) / sizeof(*u32); + i++) { + u32[i] = tswap32(u32[i]); + } + break; + /* ifla_cacheinfo */ + case IFLA_INET6_CACHEINFO: + ci = NLA_DATA(nlattr); + ci->max_reasm_len = tswap32(ci->max_reasm_len); + ci->tstamp = tswap32(ci->tstamp); + ci->reachable_time = tswap32(ci->reachable_time); + ci->retrans_time = tswap32(ci->retrans_time); + break; + /* uint64_t[] */ + case IFLA_INET6_STATS: + case IFLA_INET6_ICMP6STATS: + u64 = NLA_DATA(nlattr); + for (i = 0; i < (nlattr->nla_len - NLA_HDRLEN) / sizeof(*u64); + i++) { + u64[i] = tswap64(u64[i]); + } + break; + default: + gemu_log("Unknown host AF_INET6 type: %d\n", nlattr->nla_type); + } + return 0; +} + +static abi_long host_to_target_data_spec_nlattr(struct nlattr *nlattr, + void *context) +{ + switch (nlattr->nla_type) { + case AF_INET: + return host_to_target_for_each_nlattr(NLA_DATA(nlattr), nlattr->nla_len, + NULL, + host_to_target_data_inet_nlattr); + case AF_INET6: + return host_to_target_for_each_nlattr(NLA_DATA(nlattr), nlattr->nla_len, + NULL, + host_to_target_data_inet6_nlattr); + default: + gemu_log("Unknown host AF_SPEC type: %d\n", nlattr->nla_type); + break; + } + return 0; +} + static abi_long host_to_target_data_link_rtattr(struct rtattr *rtattr) { uint32_t *u32; struct rtnl_link_stats *st; struct rtnl_link_stats64 *st64; struct rtnl_link_ifmap *map; + struct linkinfo_context li_context; switch (rtattr->rta_type) { /* binary stream */ @@ -1846,11 +2166,15 @@ static abi_long host_to_target_data_link_rtattr(struct rtattr *rtattr) map->irq = tswap16(map->irq); break; /* nested */ - case IFLA_AF_SPEC: case IFLA_LINKINFO: - /* FIXME: implement nested type */ - gemu_log("Unimplemented nested type %d\n", rtattr->rta_type); - break; + memset(&li_context, 0, sizeof(li_context)); + return host_to_target_for_each_nlattr(RTA_DATA(rtattr), rtattr->rta_len, + &li_context, + host_to_target_data_linkinfo_nlattr); + case IFLA_AF_SPEC: + return host_to_target_for_each_nlattr(RTA_DATA(rtattr), rtattr->rta_len, + NULL, + host_to_target_data_spec_nlattr); default: gemu_log("Unknown host IFLA type: %d\n", rtattr->rta_type); break; @@ -2826,12 +3150,26 @@ static TargetFdTrans target_packet_trans = { #ifdef CONFIG_RTNETLINK static abi_long netlink_route_target_to_host(void *buf, size_t len) { - return target_to_host_nlmsg_route(buf, len); + abi_long ret; + + ret = target_to_host_nlmsg_route(buf, len); + if (ret < 0) { + return ret; + } + + return len; } static abi_long netlink_route_host_to_target(void *buf, size_t len) { - return host_to_target_nlmsg_route(buf, len); + abi_long ret; + + ret = host_to_target_nlmsg_route(buf, len); + if (ret < 0) { + return ret; + } + + return len; } static TargetFdTrans target_netlink_route_trans = { @@ -2842,12 +3180,26 @@ static TargetFdTrans target_netlink_route_trans = { static abi_long netlink_audit_target_to_host(void *buf, size_t len) { - return target_to_host_nlmsg_audit(buf, len); + abi_long ret; + + ret = target_to_host_nlmsg_audit(buf, len); + if (ret < 0) { + return ret; + } + + return len; } static abi_long netlink_audit_host_to_target(void *buf, size_t len) { - return host_to_target_nlmsg_audit(buf, len); + abi_long ret; + + ret = host_to_target_nlmsg_audit(buf, len); + if (ret < 0) { + return ret; + } + + return len; } static TargetFdTrans target_netlink_audit_trans = { @@ -2989,13 +3341,22 @@ static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp, if (send) { if (fd_trans_target_to_host_data(fd)) { - ret = fd_trans_target_to_host_data(fd)(msg.msg_iov->iov_base, + void *host_msg; + + host_msg = g_malloc(msg.msg_iov->iov_len); + memcpy(host_msg, msg.msg_iov->iov_base, msg.msg_iov->iov_len); + ret = fd_trans_target_to_host_data(fd)(host_msg, msg.msg_iov->iov_len); + if (ret >= 0) { + msg.msg_iov->iov_base = host_msg; + ret = get_errno(safe_sendmsg(fd, &msg, flags)); + } + g_free(host_msg); } else { ret = target_to_host_cmsg(&msg, msgp); - } - if (ret == 0) { - ret = get_errno(safe_sendmsg(fd, &msg, flags)); + if (ret == 0) { + ret = get_errno(safe_sendmsg(fd, &msg, flags)); + } } } else { ret = get_errno(safe_recvmsg(fd, &msg, flags)); @@ -3211,6 +3572,7 @@ static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags, { void *addr; void *host_msg; + void *copy_msg = NULL; abi_long ret; if ((int)addrlen < 0) { @@ -3221,23 +3583,29 @@ static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags, if (!host_msg) return -TARGET_EFAULT; if (fd_trans_target_to_host_data(fd)) { + copy_msg = host_msg; + host_msg = g_malloc(len); + memcpy(host_msg, copy_msg, len); ret = fd_trans_target_to_host_data(fd)(host_msg, len); if (ret < 0) { - unlock_user(host_msg, msg, 0); - return ret; + goto fail; } } if (target_addr) { addr = alloca(addrlen+1); ret = target_to_host_sockaddr(fd, addr, target_addr, addrlen); if (ret) { - unlock_user(host_msg, msg, 0); - return ret; + goto fail; } ret = get_errno(safe_sendto(fd, host_msg, len, flags, addr, addrlen)); } else { ret = get_errno(safe_sendto(fd, host_msg, len, flags, NULL, 0)); } +fail: + if (copy_msg) { + g_free(host_msg); + host_msg = copy_msg; + } unlock_user(host_msg, msg, 0); return ret; } @@ -3272,6 +3640,9 @@ static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags, ret = get_errno(safe_recvfrom(fd, host_msg, len, flags, NULL, 0)); } if (!is_error(ret)) { + if (fd_trans_host_to_target_data(fd)) { + ret = fd_trans_host_to_target_data(fd)(host_msg, ret); + } if (target_addr) { host_to_target_sockaddr(target_addr, addr, addrlen); if (put_user_u32(addrlen, target_addrlen)) { @@ -7614,7 +7985,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #if defined(TARGET_ALPHA) struct target_sigaction act, oact, *pact = 0; struct target_rt_sigaction *rt_act; - /* ??? arg4 == sizeof(sigset_t). */ + + if (arg4 != sizeof(target_sigset_t)) { + ret = -TARGET_EINVAL; + break; + } if (arg2) { if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1)) goto efault; @@ -7638,6 +8013,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct target_sigaction *act; struct target_sigaction *oact; + if (arg4 != sizeof(target_sigset_t)) { + ret = -TARGET_EINVAL; + break; + } if (arg2) { if (!lock_user_struct(VERIFY_READ, act, arg2, 1)) goto efault; @@ -7769,6 +8148,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, int how = arg1; sigset_t set, oldset, *set_ptr; + if (arg4 != sizeof(target_sigset_t)) { + ret = -TARGET_EINVAL; + break; + } + if (arg2) { switch(how) { case TARGET_SIG_BLOCK: @@ -7819,6 +8203,17 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_rt_sigpending: { sigset_t set; + + /* Yes, this check is >, not != like most. We follow the kernel's + * logic and it does it like this because it implements + * NR_sigpending through the same code path, and in that case + * the old_sigset_t is smaller in size. + */ + if (arg2 > sizeof(target_sigset_t)) { + ret = -TARGET_EINVAL; + break; + } + ret = get_errno(sigpending(&set)); if (!is_error(ret)) { if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0))) @@ -7852,6 +8247,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_rt_sigsuspend: { TaskState *ts = cpu->opaque; + + if (arg2 != sizeof(target_sigset_t)) { + ret = -TARGET_EINVAL; + break; + } if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1))) goto efault; target_to_host_sigset(&ts->sigsuspend_mask, p); @@ -7869,6 +8269,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct timespec uts, *puts; siginfo_t uinfo; + if (arg4 != sizeof(target_sigset_t)) { + ret = -TARGET_EINVAL; + break; + } + if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1))) goto efault; target_to_host_sigset(&set, p); @@ -9120,6 +9525,12 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } if (arg4) { + if (arg5 != sizeof(target_sigset_t)) { + unlock_user(target_pfd, arg1, 0); + ret = -TARGET_EINVAL; + break; + } + target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1); if (!target_set) { unlock_user(target_pfd, arg1, 0); @@ -10939,6 +11350,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, sigset_t _set, *set = &_set; if (arg5) { + if (arg6 != sizeof(target_sigset_t)) { + ret = -TARGET_EINVAL; + break; + } + target_set = lock_user(VERIFY_READ, arg5, sizeof(target_sigset_t), 1); if (!target_set) { diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index b43966ece0..783565463f 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -985,6 +985,17 @@ struct target_pollfd { #define TARGET_BLKGETSIZE64 TARGET_IOR(0x12,114,abi_ulong) /* return device size in bytes (u64 *arg) */ + +#define TARGET_BLKDISCARD TARGET_IO(0x12, 119) +#define TARGET_BLKIOMIN TARGET_IO(0x12, 120) +#define TARGET_BLKIOOPT TARGET_IO(0x12, 121) +#define TARGET_BLKALIGNOFF TARGET_IO(0x12, 122) +#define TARGET_BLKPBSZGET TARGET_IO(0x12, 123) +#define TARGET_BLKDISCARDZEROES TARGET_IO(0x12, 124) +#define TARGET_BLKSECDISCARD TARGET_IO(0x12, 125) +#define TARGET_BLKROTATIONAL TARGET_IO(0x12, 126) +#define TARGET_BLKZEROOUT TARGET_IO(0x12, 127) + #define TARGET_FIBMAP TARGET_IO(0x00,1) /* bmap access */ #define TARGET_FIGETBSZ TARGET_IO(0x00,2) /* get the block size used for bmap */ #define TARGET_FS_IOC_FIEMAP TARGET_IOWR('f',11,struct fiemap) @@ -1117,6 +1128,10 @@ struct target_pollfd { #define TARGET_LOOP_GET_STATUS64 0x4C05 #define TARGET_LOOP_CHANGE_FD 0x4C06 +#define TARGET_LOOP_CTL_ADD 0x4C80 +#define TARGET_LOOP_CTL_REMOVE 0x4C81 +#define TARGET_LOOP_CTL_GET_FREE 0x4C82 + /* fb ioctls */ #define TARGET_FBIOGET_VSCREENINFO 0x4600 #define TARGET_FBIOPUT_VSCREENINFO 0x4601 diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h index 1fd4ee0bfd..af79fbf1de 100644 --- a/linux-user/syscall_types.h +++ b/linux-user/syscall_types.h @@ -103,10 +103,11 @@ STRUCT(loop_info64, TYPE_ULONGLONG, /* lo_inode */ TYPE_ULONGLONG, /* lo_rdevice */ TYPE_ULONGLONG, /* lo_offset */ - TYPE_ULONG, /* lo_number */ - TYPE_ULONG, /* lo_encrypt_type */ - TYPE_ULONG, /* lo_encrypt_key_size */ - TYPE_ULONG, /* lo_flags */ + TYPE_ULONGLONG, /* lo_sizelimit */ + TYPE_INT, /* lo_number */ + TYPE_INT, /* lo_encrypt_type */ + TYPE_INT, /* lo_encrypt_key_size */ + TYPE_INT, /* lo_flags */ MK_ARRAY(TYPE_CHAR, 64), /* lo_name */ MK_ARRAY(TYPE_CHAR, 64), /* lo_crypt_name */ MK_ARRAY(TYPE_CHAR, 32), /* lo_encrypt_key */ diff --git a/linux-user/x86_64/termbits.h b/linux-user/x86_64/termbits.h index 1c3445c6a2..387e742592 100644 --- a/linux-user/x86_64/termbits.h +++ b/linux-user/x86_64/termbits.h @@ -209,12 +209,12 @@ struct target_termios { #define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */ #define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */ #define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */ -#define TARGET_TCGETS2 _IOR('T',0x2A, struct termios2) -#define TARGET_TCSETS2 _IOW('T',0x2B, struct termios2) -#define TARGET_TCSETSW2 _IOW('T',0x2C, struct termios2) -#define TARGET_TCSETSF2 _IOW('T',0x2D, struct termios2) -#define TARGET_TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ -#define TARGET_TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ +#define TARGET_TCGETS2 TARGET_IOR('T',0x2A, struct termios2) +#define TARGET_TCSETS2 TARGET_IOW('T',0x2B, struct termios2) +#define TARGET_TCSETSW2 TARGET_IOW('T',0x2C, struct termios2) +#define TARGET_TCSETSF2 TARGET_IOW('T',0x2D, struct termios2) +#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ +#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */ #define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */ #define TARGET_FIOCLEX 0x5451 |