linux-user/ioctls.h | 45 +++++++++++++++++++++++++++++++++++++++ linux-user/syscall.c | 36 +++++++++++++++++++++++++++++++ linux-user/syscall_defs.h | 32 ++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+)
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:
Title changed from "linux-user: Add several IFTUN ioctls"
Properly specify the argument types for various options, including a custom
implementation for TUNSETTXFILTER.
#ifdef guards for macros introduced up to 5 years ago.
linux-user/ioctls.h | 45 +++++++++++++++++++++++++++++++++++++++
linux-user/syscall.c | 36 +++++++++++++++++++++++++++++++
linux-user/syscall_defs.h | 32 ++++++++++++++++++++++++++++
3 files changed, 113 insertions(+)
diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h
index 0713ae1311..b9fb01f558 100644
--- a/linux-user/ioctls.h
+++ b/linux-user/ioctls.h
@@ -593,3 +593,48 @@
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
+ * this empty. do_ioctl_TUNSETTXFILTER will do the conversion.
+ */
+ TYPE_NULL)
+ 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 1211e759c2..7f1efed189 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
@@ -5422,6 +5423,41 @@ 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(*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, sizeof(*filter));
+
+ if (filter->count) {
+ if (sizeof(*filter) + filter->count * ETH_ALEN > MAX_STRUCT_SIZE) {
+ return -TARGET_EFAULT;
+ }
+
+ target_addr = lock_user(VERIFY_READ, arg + sizeof(*filter),
+ 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 + sizeof(*filter),
+ 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)
--
2.28.0.rc0.142.g3c755180ce-goog
Le 24/07/2020 à 01:10, Shu-Chun Weng 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: > Title changed from "linux-user: Add several IFTUN ioctls" > > Properly specify the argument types for various options, including a custom > implementation for TUNSETTXFILTER. > > #ifdef guards for macros introduced up to 5 years ago. > > linux-user/ioctls.h | 45 +++++++++++++++++++++++++++++++++++++++ > linux-user/syscall.c | 36 +++++++++++++++++++++++++++++++ > linux-user/syscall_defs.h | 32 ++++++++++++++++++++++++++++ > 3 files changed, 113 insertions(+) > > diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h > index 0713ae1311..b9fb01f558 100644 > --- a/linux-user/ioctls.h > +++ b/linux-user/ioctls.h > @@ -593,3 +593,48 @@ > 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))) Why is this IOC_RW? > + 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) Why is this long? > + IOCTL_SPECIAL(TUNSETTXFILTER, IOC_W, do_ioctl_TUNSETTXFILTER, > + /* > + * We can't represent `struct tun_filter` in thunk so leaving > + * this empty. do_ioctl_TUNSETTXFILTER will do the conversion. > + */ > + TYPE_NULL) You should use TYPE_PTRVOID to allow QEMU_STRACE to display the pointer. Or implement the function to dump the structure (see STRUCT_termios and struct_termios_def). > + 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 1211e759c2..7f1efed189 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 > @@ -5422,6 +5423,41 @@ 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(*filter), 1); sizeof(*target_filter) vould be more coherent: we lock the target memory so use the size of the type of the target. > + if (!target_filter) { > + return -TARGET_EFAULT; > + } > + filter->flags = tswap16(target_filter->flags); > + filter->count = tswap16(target_filter->count); > + unlock_user(target_filter, arg, sizeof(*filter)); unlock_user(target_filter, arg, 0) as we don't need to copy the value back to the target. > + > + if (filter->count) { > + if (sizeof(*filter) + filter->count * ETH_ALEN > MAX_STRUCT_SIZE) { Rather than sizeof() use offsetof(struct tun_filter, addr) > + return -TARGET_EFAULT; > + } > + > + target_addr = lock_user(VERIFY_READ, arg + sizeof(*filter), Rather than sizeof() use 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 + sizeof(*filter), offsetof(struct tun_filter, addr) Thanks, Laurent
On Sat, Sep 26, 2020 at 9:44 AM Laurent Vivier <laurent@vivier.eu> wrote: > Le 24/07/2020 à 01:10, Shu-Chun Weng 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: > > Title changed from "linux-user: Add several IFTUN ioctls" > > > > Properly specify the argument types for various options, including a > custom > > implementation for TUNSETTXFILTER. > > > > #ifdef guards for macros introduced up to 5 years ago. > > > > linux-user/ioctls.h | 45 +++++++++++++++++++++++++++++++++++++++ > > linux-user/syscall.c | 36 +++++++++++++++++++++++++++++++ > > linux-user/syscall_defs.h | 32 ++++++++++++++++++++++++++++ > > 3 files changed, 113 insertions(+) > > > > diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h > > index 0713ae1311..b9fb01f558 100644 > > --- a/linux-user/ioctls.h > > +++ b/linux-user/ioctls.h > > @@ -593,3 +593,48 @@ > > 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))) > > Why is this IOC_RW? > R: https://github.com/torvalds/linux/blob/a1b8638ba1320e6684aa98233c15255eb803fac7/drivers/net/tun.c#L3010 W: https://github.com/torvalds/linux/blob/a1b8638ba1320e6684aa98233c15255eb803fac7/drivers/net/tun.c#L3046 More specifically, the call may update ifr->ifr_name: https://github.com/torvalds/linux/blob/a1b8638ba1320e6684aa98233c15255eb803fac7/drivers/net/tun.c#L2821 > > > + 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) > > Why is this long? > Appears to be a bitmask: https://github.com/torvalds/linux/blob/a1b8638ba1320e6684aa98233c15255eb803fac7/drivers/net/tun.c#L2853 > > > + IOCTL_SPECIAL(TUNSETTXFILTER, IOC_W, do_ioctl_TUNSETTXFILTER, > > + /* > > + * We can't represent `struct tun_filter` in thunk so > leaving > > + * this empty. do_ioctl_TUNSETTXFILTER will do the > conversion. > > + */ > > + TYPE_NULL) > > You should use TYPE_PTRVOID to allow QEMU_STRACE to display the pointer. > Or implement the function to dump the structure (see STRUCT_termios and > struct_termios_def). > Will change to TYPE_PTRVOID. `struct tun_filter` uses flexible arrays ( https://github.com/torvalds/linux/blob/a4d63c3732f1a0c91abcf5b7f32b4ef7dcd82025/include/uapi/linux/if_tun.h#L111) and can't even be written with custom converters because the structure size isn't fixed. IIRC, it can be implemented on top of my other patch which adds flexible array support to the thunk infrastructure https://lists.nongnu.org/archive/html/qemu-devel/2020-08/msg01949.html > > > + 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 1211e759c2..7f1efed189 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 > > @@ -5422,6 +5423,41 @@ 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(*filter), 1); > > sizeof(*target_filter) vould be more coherent: we lock the target memory > so use the size of the type of the target. > > > + if (!target_filter) { > > + return -TARGET_EFAULT; > > + } > > + filter->flags = tswap16(target_filter->flags); > > + filter->count = tswap16(target_filter->count); > > + unlock_user(target_filter, arg, sizeof(*filter)); > > unlock_user(target_filter, arg, 0) as we don't need to copy the value > back to the target. > > > + > > + if (filter->count) { > > + if (sizeof(*filter) + filter->count * ETH_ALEN > > MAX_STRUCT_SIZE) { > > Rather than sizeof() use offsetof(struct tun_filter, addr) > > > + return -TARGET_EFAULT; > > + } > > + > > + target_addr = lock_user(VERIFY_READ, arg + sizeof(*filter), > > Rather than sizeof() use 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 + sizeof(*filter), > > offsetof(struct tun_filter, addr) > All changes in syscall.c applied. Will send out v3 soon. Thank you very much! Shu-Chun > > Thanks, > Laurent >
Ping: https://patchew.org/QEMU/20200723231020.769893-1-scw@google.com/ On Thu, Jul 23, 2020 at 4:10 PM Shu-Chun Weng <scw@google.com> wrote: > 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: > Title changed from "linux-user: Add several IFTUN ioctls" > > Properly specify the argument types for various options, including a > custom > implementation for TUNSETTXFILTER. > > #ifdef guards for macros introduced up to 5 years ago. > > linux-user/ioctls.h | 45 +++++++++++++++++++++++++++++++++++++++ > linux-user/syscall.c | 36 +++++++++++++++++++++++++++++++ > linux-user/syscall_defs.h | 32 ++++++++++++++++++++++++++++ > 3 files changed, 113 insertions(+) > > diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h > index 0713ae1311..b9fb01f558 100644 > --- a/linux-user/ioctls.h > +++ b/linux-user/ioctls.h > @@ -593,3 +593,48 @@ > 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 > + * this empty. do_ioctl_TUNSETTXFILTER will do the > conversion. > + */ > + TYPE_NULL) > + 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 1211e759c2..7f1efed189 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 > @@ -5422,6 +5423,41 @@ 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(*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, sizeof(*filter)); > + > + if (filter->count) { > + if (sizeof(*filter) + filter->count * ETH_ALEN > MAX_STRUCT_SIZE) > { > + return -TARGET_EFAULT; > + } > + > + target_addr = lock_user(VERIFY_READ, arg + sizeof(*filter), > + 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 + sizeof(*filter), > + 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) > -- > 2.28.0.rc0.142.g3c755180ce-goog > >
Ping. On Wed, Aug 5, 2020 at 4:22 PM Shu-Chun Weng <scw@google.com> wrote: > Ping: https://patchew.org/QEMU/20200723231020.769893-1-scw@google.com/ > > On Thu, Jul 23, 2020 at 4:10 PM Shu-Chun Weng <scw@google.com> wrote: > >> 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: >> Title changed from "linux-user: Add several IFTUN ioctls" >> >> Properly specify the argument types for various options, including a >> custom >> implementation for TUNSETTXFILTER. >> >> #ifdef guards for macros introduced up to 5 years ago. >> >> linux-user/ioctls.h | 45 +++++++++++++++++++++++++++++++++++++++ >> linux-user/syscall.c | 36 +++++++++++++++++++++++++++++++ >> linux-user/syscall_defs.h | 32 ++++++++++++++++++++++++++++ >> 3 files changed, 113 insertions(+) >> >> diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h >> index 0713ae1311..b9fb01f558 100644 >> --- a/linux-user/ioctls.h >> +++ b/linux-user/ioctls.h >> @@ -593,3 +593,48 @@ >> 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 >> + * this empty. do_ioctl_TUNSETTXFILTER will do the >> conversion. >> + */ >> + TYPE_NULL) >> + 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 1211e759c2..7f1efed189 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 >> @@ -5422,6 +5423,41 @@ 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(*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, sizeof(*filter)); >> + >> + if (filter->count) { >> + if (sizeof(*filter) + filter->count * ETH_ALEN > >> MAX_STRUCT_SIZE) { >> + return -TARGET_EFAULT; >> + } >> + >> + target_addr = lock_user(VERIFY_READ, arg + sizeof(*filter), >> + 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 + sizeof(*filter), >> + 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) >> -- >> 2.28.0.rc0.142.g3c755180ce-goog >> >>
© 2016 - 2024 Red Hat, Inc.