Message ID | 20200929014801.655524-1-scw@google.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | [v4] linux-user: Add most IFTUN ioctls | expand |
Le 29/09/2020 à 03:48, Shu-Chun Weng via a écrit : > 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> > --- > v2->v3: > IOCTL_SPECIAL(TUNSETTXFILTER) type changed to MK_PTR(TYPE_PTRVOID) for strace > to display the raw pointer. > > Updated do_ioctl_TUNSETTXFILTER for correct usages of unlock_user() and > offsetof(). > > v3->v4: > IOCTL_SPECIAL(TUNSETTXFILTER) corrected to TYPE_PTRVOID. > > linux-user/ioctls.h | 46 +++++++++++++++++++++++++++++++++++++++ > linux-user/syscall.c | 38 ++++++++++++++++++++++++++++++++ > linux-user/syscall_defs.h | 32 +++++++++++++++++++++++++++ > 3 files changed, 116 insertions(+) > ... > diff --git a/linux-user/syscall.c b/linux-user/syscall.c > index 945fc25279..1c955bc675 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 > @@ -5415,6 +5416,43 @@ static abi_long do_ioctl_drm(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), > + filter->count * ETH_ALEN); As we don't modify target_addr memory content (locked with VERIFY_READ), we can replace "filter->count * ETH_ALEN" by 0. With that modified: Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Le 29/09/2020 à 03:48, Shu-Chun Weng via a écrit : > 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> > --- > v2->v3: > IOCTL_SPECIAL(TUNSETTXFILTER) type changed to MK_PTR(TYPE_PTRVOID) for strace > to display the raw pointer. > > Updated do_ioctl_TUNSETTXFILTER for correct usages of unlock_user() and > offsetof(). > > v3->v4: > IOCTL_SPECIAL(TUNSETTXFILTER) corrected to TYPE_PTRVOID. > > linux-user/ioctls.h | 46 +++++++++++++++++++++++++++++++++++++++ > linux-user/syscall.c | 38 ++++++++++++++++++++++++++++++++ > linux-user/syscall_defs.h | 32 +++++++++++++++++++++++++++ > 3 files changed, 116 insertions(+) > > diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h > index 0713ae1311..c6e5926eb4 100644 > --- a/linux-user/ioctls.h > +++ b/linux-user/ioctls.h > @@ -593,3 +593,49 @@ > IOCTL(KCOV_DISABLE, 0, TYPE_NULL) > IOCTL(KCOV_INIT_TRACE, IOC_R, TYPE_ULONG) > #endif > + > + IOCTL(TUNSETDEBUG, IOC_W, TYPE_INT) > + IOCTL(TUNSETIFF, IOC_RW, MK_PTR(MK_STRUCT(STRUCT_short_ifreq))) > + IOCTL(TUNSETPERSIST, IOC_W, TYPE_INT) > + IOCTL(TUNSETOWNER, IOC_W, TYPE_INT) > + IOCTL(TUNSETLINK, IOC_W, TYPE_INT) > + IOCTL(TUNSETGROUP, IOC_W, TYPE_INT) > + IOCTL(TUNGETFEATURES, IOC_R, MK_PTR(TYPE_INT)) > + IOCTL(TUNSETOFFLOAD, IOC_W, TYPE_LONG) > + IOCTL_SPECIAL(TUNSETTXFILTER, IOC_W, do_ioctl_TUNSETTXFILTER, > + /* > + * We can't represent `struct tun_filter` in thunk so leaving > + * it uninterpreted. do_ioctl_TUNSETTXFILTER will do the > + * conversion. > + */ > + TYPE_PTRVOID) > + IOCTL(TUNGETIFF, IOC_R, MK_PTR(MK_STRUCT(STRUCT_short_ifreq))) > + IOCTL(TUNGETSNDBUF, IOC_R, MK_PTR(TYPE_INT)) > + IOCTL(TUNSETSNDBUF, IOC_W, MK_PTR(TYPE_INT)) > + /* > + * TUNATTACHFILTER and TUNDETACHFILTER are not supported. Linux kernel keeps a > + * user pointer in TUNATTACHFILTER, which we are not able to correctly handle. > + */ > + IOCTL(TUNGETVNETHDRSZ, IOC_R, MK_PTR(TYPE_INT)) > + IOCTL(TUNSETVNETHDRSZ, IOC_W, MK_PTR(TYPE_INT)) > + IOCTL(TUNSETQUEUE, IOC_W, MK_PTR(MK_STRUCT(STRUCT_short_ifreq))) > + IOCTL(TUNSETIFINDEX , IOC_W, MK_PTR(TYPE_INT)) > + /* TUNGETFILTER is not supported: see TUNATTACHFILTER. */ > + IOCTL(TUNSETVNETLE, IOC_W, MK_PTR(TYPE_INT)) > + IOCTL(TUNGETVNETLE, IOC_R, MK_PTR(TYPE_INT)) > +#ifdef TUNSETVNETBE > + IOCTL(TUNSETVNETBE, IOC_W, MK_PTR(TYPE_INT)) > + IOCTL(TUNGETVNETBE, IOC_R, MK_PTR(TYPE_INT)) > +#endif > +#ifdef TUNSETSTEERINGEBPF > + IOCTL(TUNSETSTEERINGEBPF, IOC_W, MK_PTR(TYPE_INT)) > +#endif > +#ifdef TUNSETFILTEREBPF > + IOCTL(TUNSETFILTEREBPF, IOC_W, MK_PTR(TYPE_INT)) > +#endif > +#ifdef TUNSETCARRIER > + IOCTL(TUNSETCARRIER, IOC_W, MK_PTR(TYPE_INT)) > +#endif > +#ifdef TUNGETDEVNETNS > + IOCTL(TUNGETDEVNETNS, IOC_R, TYPE_NULL) > +#endif > diff --git a/linux-user/syscall.c b/linux-user/syscall.c > index 945fc25279..1c955bc675 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 > @@ -5415,6 +5416,43 @@ static abi_long do_ioctl_drm(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), > + filter->count * ETH_ALEN); > + } > + > + 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__ } }, > diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h > index 3c261cff0e..7ef0ff0328 100644 > --- a/linux-user/syscall_defs.h > +++ b/linux-user/syscall_defs.h > @@ -891,6 +891,38 @@ struct target_rtc_pll_info { > > #define TARGET_SIOCGIWNAME 0x8B01 /* get name == wireless protocol */ > > +/* From <linux/if_tun.h> */ > + > +#define TARGET_TUNSETDEBUG TARGET_IOW('T', 201, int) > +#define TARGET_TUNSETIFF TARGET_IOW('T', 202, int) > +#define TARGET_TUNSETPERSIST TARGET_IOW('T', 203, int) > +#define TARGET_TUNSETOWNER TARGET_IOW('T', 204, int) > +#define TARGET_TUNSETLINK TARGET_IOW('T', 205, int) > +#define TARGET_TUNSETGROUP TARGET_IOW('T', 206, int) > +#define TARGET_TUNGETFEATURES TARGET_IOR('T', 207, unsigned int) > +#define TARGET_TUNSETOFFLOAD TARGET_IOW('T', 208, unsigned int) > +#define TARGET_TUNSETTXFILTER TARGET_IOW('T', 209, unsigned int) > +#define TARGET_TUNGETIFF TARGET_IOR('T', 210, unsigned int) > +#define TARGET_TUNGETSNDBUF TARGET_IOR('T', 211, int) > +#define TARGET_TUNSETSNDBUF TARGET_IOW('T', 212, int) > +/* > + * TUNATTACHFILTER and TUNDETACHFILTER are not supported. Linux kernel keeps a > + * user pointer in TUNATTACHFILTER, which we are not able to correctly handle. > + */ > +#define TARGET_TUNGETVNETHDRSZ TARGET_IOR('T', 215, int) > +#define TARGET_TUNSETVNETHDRSZ TARGET_IOW('T', 216, int) > +#define TARGET_TUNSETQUEUE TARGET_IOW('T', 217, int) > +#define TARGET_TUNSETIFINDEX TARGET_IOW('T', 218, unsigned int) > +/* TUNGETFILTER is not supported: see TUNATTACHFILTER. */ > +#define TARGET_TUNSETVNETLE TARGET_IOW('T', 220, int) > +#define TARGET_TUNGETVNETLE TARGET_IOR('T', 221, int) > +#define TARGET_TUNSETVNETBE TARGET_IOW('T', 222, int) > +#define TARGET_TUNGETVNETBE TARGET_IOR('T', 223, int) > +#define TARGET_TUNSETSTEERINGEBPF TARGET_IOR('T', 224, int) > +#define TARGET_TUNSETFILTEREBPF TARGET_IOR('T', 225, int) > +#define TARGET_TUNSETCARRIER TARGET_IOW('T', 226, int) > +#define TARGET_TUNGETDEVNETNS TARGET_IO('T', 227) > + > /* From <linux/random.h> */ > > #define TARGET_RNDGETENTCNT TARGET_IOR('R', 0x00, int) > Applied to my linux-user-for-6.0 branch Thanks, Laurent
diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h index 0713ae1311..c6e5926eb4 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h @@ -593,3 +593,49 @@ IOCTL(KCOV_DISABLE, 0, TYPE_NULL) IOCTL(KCOV_INIT_TRACE, IOC_R, TYPE_ULONG) #endif + + IOCTL(TUNSETDEBUG, IOC_W, TYPE_INT) + IOCTL(TUNSETIFF, IOC_RW, MK_PTR(MK_STRUCT(STRUCT_short_ifreq))) + IOCTL(TUNSETPERSIST, IOC_W, TYPE_INT) + IOCTL(TUNSETOWNER, IOC_W, TYPE_INT) + IOCTL(TUNSETLINK, IOC_W, TYPE_INT) + IOCTL(TUNSETGROUP, IOC_W, TYPE_INT) + IOCTL(TUNGETFEATURES, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(TUNSETOFFLOAD, IOC_W, TYPE_LONG) + IOCTL_SPECIAL(TUNSETTXFILTER, IOC_W, do_ioctl_TUNSETTXFILTER, + /* + * We can't represent `struct tun_filter` in thunk so leaving + * it uninterpreted. do_ioctl_TUNSETTXFILTER will do the + * conversion. + */ + TYPE_PTRVOID) + IOCTL(TUNGETIFF, IOC_R, MK_PTR(MK_STRUCT(STRUCT_short_ifreq))) + IOCTL(TUNGETSNDBUF, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(TUNSETSNDBUF, IOC_W, MK_PTR(TYPE_INT)) + /* + * TUNATTACHFILTER and TUNDETACHFILTER are not supported. Linux kernel keeps a + * user pointer in TUNATTACHFILTER, which we are not able to correctly handle. + */ + IOCTL(TUNGETVNETHDRSZ, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(TUNSETVNETHDRSZ, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(TUNSETQUEUE, IOC_W, MK_PTR(MK_STRUCT(STRUCT_short_ifreq))) + IOCTL(TUNSETIFINDEX , IOC_W, MK_PTR(TYPE_INT)) + /* TUNGETFILTER is not supported: see TUNATTACHFILTER. */ + IOCTL(TUNSETVNETLE, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(TUNGETVNETLE, IOC_R, MK_PTR(TYPE_INT)) +#ifdef TUNSETVNETBE + IOCTL(TUNSETVNETBE, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(TUNGETVNETBE, IOC_R, MK_PTR(TYPE_INT)) +#endif +#ifdef TUNSETSTEERINGEBPF + IOCTL(TUNSETSTEERINGEBPF, IOC_W, MK_PTR(TYPE_INT)) +#endif +#ifdef TUNSETFILTEREBPF + IOCTL(TUNSETFILTEREBPF, IOC_W, MK_PTR(TYPE_INT)) +#endif +#ifdef TUNSETCARRIER + IOCTL(TUNSETCARRIER, IOC_W, MK_PTR(TYPE_INT)) +#endif +#ifdef TUNGETDEVNETNS + IOCTL(TUNGETDEVNETNS, IOC_R, TYPE_NULL) +#endif diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 945fc25279..1c955bc675 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 @@ -5415,6 +5416,43 @@ static abi_long do_ioctl_drm(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), + filter->count * ETH_ALEN); + } + + 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__ } }, diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 3c261cff0e..7ef0ff0328 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -891,6 +891,38 @@ struct target_rtc_pll_info { #define TARGET_SIOCGIWNAME 0x8B01 /* get name == wireless protocol */ +/* From <linux/if_tun.h> */ + +#define TARGET_TUNSETDEBUG TARGET_IOW('T', 201, int) +#define TARGET_TUNSETIFF TARGET_IOW('T', 202, int) +#define TARGET_TUNSETPERSIST TARGET_IOW('T', 203, int) +#define TARGET_TUNSETOWNER TARGET_IOW('T', 204, int) +#define TARGET_TUNSETLINK TARGET_IOW('T', 205, int) +#define TARGET_TUNSETGROUP TARGET_IOW('T', 206, int) +#define TARGET_TUNGETFEATURES TARGET_IOR('T', 207, unsigned int) +#define TARGET_TUNSETOFFLOAD TARGET_IOW('T', 208, unsigned int) +#define TARGET_TUNSETTXFILTER TARGET_IOW('T', 209, unsigned int) +#define TARGET_TUNGETIFF TARGET_IOR('T', 210, unsigned int) +#define TARGET_TUNGETSNDBUF TARGET_IOR('T', 211, int) +#define TARGET_TUNSETSNDBUF TARGET_IOW('T', 212, int) +/* + * TUNATTACHFILTER and TUNDETACHFILTER are not supported. Linux kernel keeps a + * user pointer in TUNATTACHFILTER, which we are not able to correctly handle. + */ +#define TARGET_TUNGETVNETHDRSZ TARGET_IOR('T', 215, int) +#define TARGET_TUNSETVNETHDRSZ TARGET_IOW('T', 216, int) +#define TARGET_TUNSETQUEUE TARGET_IOW('T', 217, int) +#define TARGET_TUNSETIFINDEX TARGET_IOW('T', 218, unsigned int) +/* TUNGETFILTER is not supported: see TUNATTACHFILTER. */ +#define TARGET_TUNSETVNETLE TARGET_IOW('T', 220, int) +#define TARGET_TUNGETVNETLE TARGET_IOR('T', 221, int) +#define TARGET_TUNSETVNETBE TARGET_IOW('T', 222, int) +#define TARGET_TUNGETVNETBE TARGET_IOR('T', 223, int) +#define TARGET_TUNSETSTEERINGEBPF TARGET_IOR('T', 224, int) +#define TARGET_TUNSETFILTEREBPF TARGET_IOR('T', 225, int) +#define TARGET_TUNSETCARRIER TARGET_IOW('T', 226, int) +#define TARGET_TUNGETDEVNETNS TARGET_IO('T', 227) + /* From <linux/random.h> */ #define TARGET_RNDGETENTCNT TARGET_IOR('R', 0x00, int)