diff options
author | Shu-Chun Weng <scw@google.com> | 2020-09-28 18:48:01 -0700 |
---|---|---|
committer | Laurent Vivier <laurent@vivier.eu> | 2020-12-18 11:23:10 +0100 |
commit | 6addf06a3c4dad68d8d7032e31714e81b438c7d9 (patch) | |
tree | 9157864d4f9eb5b318ceb377c11158e66308e8ec /linux-user/syscall.c | |
parent | 8494645797ac3c61d8693ac4164a87c8790a8717 (diff) |
linux-user: Add most IFTUN ioctls
The three options handling `struct sock_fprog` (TUNATTACHFILTER,
TUNDETACHFILTER, and TUNGETFILTER) are not implemented. Linux kernel
keeps a user space pointer in them which we cannot correctly handle.
Signed-off-by: Josh Kunz <jkz@google.com>
Signed-off-by: Shu-Chun Weng <scw@google.com>
Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Message-Id: <20200929014801.655524-1-scw@google.com>
[lv: use 0 size in unlock_user()]
Signed-off-by: Laurent Vivier <laurent@vivier.eu>
Diffstat (limited to 'linux-user/syscall.c')
-rw-r--r-- | linux-user/syscall.c | 37 |
1 files changed, 37 insertions, 0 deletions
diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 6091a449fb..d182890ff0 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -56,6 +56,7 @@ #include <linux/wireless.h> #include <linux/icmp.h> #include <linux/icmpv6.h> +#include <linux/if_tun.h> #include <linux/errqueue.h> #include <linux/random.h> #ifdef CONFIG_TIMERFD @@ -5709,6 +5710,42 @@ static abi_long do_ioctl_drm_i915(const IOCTLEntry *ie, uint8_t *buf_temp, #endif +static abi_long do_ioctl_TUNSETTXFILTER(const IOCTLEntry *ie, uint8_t *buf_temp, + int fd, int cmd, abi_long arg) +{ + struct tun_filter *filter = (struct tun_filter *)buf_temp; + struct tun_filter *target_filter; + char *target_addr; + + assert(ie->access == IOC_W); + + target_filter = lock_user(VERIFY_READ, arg, sizeof(*target_filter), 1); + if (!target_filter) { + return -TARGET_EFAULT; + } + filter->flags = tswap16(target_filter->flags); + filter->count = tswap16(target_filter->count); + unlock_user(target_filter, arg, 0); + + if (filter->count) { + if (offsetof(struct tun_filter, addr) + filter->count * ETH_ALEN > + MAX_STRUCT_SIZE) { + return -TARGET_EFAULT; + } + + target_addr = lock_user(VERIFY_READ, + arg + offsetof(struct tun_filter, addr), + filter->count * ETH_ALEN, 1); + if (!target_addr) { + return -TARGET_EFAULT; + } + memcpy(filter->addr, target_addr, filter->count * ETH_ALEN); + unlock_user(target_addr, arg + offsetof(struct tun_filter, addr), 0); + } + + return get_errno(safe_ioctl(fd, ie->host_cmd, filter)); +} + IOCTLEntry ioctl_entries[] = { #define IOCTL(cmd, access, ...) \ { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } }, |