Message ID | 1369680516-18544-1-git-send-email-laurent@vivier.eu |
---|---|
State | New |
Headers | show |
Ping Le 27/05/2013 20:48, Laurent Vivier a écrit : > This allows to pass the device name. > > You can test this with the "route" command. > > WITHOUT this patch: > > $ sudo route add -net default gw 10.0.3.1 eth0 > SIOCADDRT: Bad address > $ netstat -nr > Kernel IP routing table > Destination Gateway Genmask Flags MSS Window irtt Ifa > 10.0.3.0 0.0.0.0 255.255.255.0 U 0 0 0 eth > > WITH this patch: > > $ sudo route add -net default gw 10.0.3.1 eth0 > $ netstat -nr > Kernel IP routing table > Destination Gateway Genmask Flags MSS Window irtt Ifa > 0.0.0.0 10.0.3.1 0.0.0.0 UG 0 0 0 eth > 10.0.3.0 0.0.0.0 255.255.255.0 U 0 0 0 eth > > Signed-off-by: Laurent Vivier <laurent@vivier.eu> > --- > linux-user/ioctls.h | 6 +++-- > linux-user/syscall.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 68 insertions(+), 2 deletions(-) > > diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h > index 8a47767..439c2a9 100644 > --- a/linux-user/ioctls.h > +++ b/linux-user/ioctls.h > @@ -88,8 +88,6 @@ > #endif > > IOCTL(SIOCATMARK, 0, TYPE_NULL) > - IOCTL(SIOCADDRT, IOC_W, MK_PTR(MK_STRUCT(STRUCT_rtentry))) > - IOCTL(SIOCDELRT, IOC_W, MK_PTR(MK_STRUCT(STRUCT_rtentry))) > 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))) > @@ -379,3 +377,7 @@ > MK_PTR(MK_STRUCT(STRUCT_dm_ioctl))) > IOCTL_SPECIAL(DM_DEV_SET_GEOMETRY, IOC_RW, do_ioctl_dm, > MK_PTR(MK_STRUCT(STRUCT_dm_ioctl))) > + IOCTL_SPECIAL(SIOCADDRT, IOC_W, do_ioctl_rt, > + MK_PTR(MK_STRUCT(STRUCT_rtentry))) > + IOCTL_SPECIAL(SIOCDELRT, IOC_W, do_ioctl_rt, > + MK_PTR(MK_STRUCT(STRUCT_rtentry))) > diff --git a/linux-user/syscall.c b/linux-user/syscall.c > index 1b3c0ed..a5cd166 100644 > --- a/linux-user/syscall.c > +++ b/linux-user/syscall.c > @@ -105,6 +105,7 @@ int __clone2(int (*fn)(void *), void *child_stack_base, > #include <linux/vt.h> > #include <linux/dm-ioctl.h> > #include <linux/reboot.h> > +#include <linux/route.h> > #include "linux_loop.h" > #include "cpu-uname.h" > > @@ -3714,6 +3715,69 @@ out: > return ret; > } > > +static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp, > + int fd, abi_long cmd, abi_long arg) > +{ > + const argtype *arg_type = ie->arg_type; > + const StructEntry *se; > + const argtype *field_types; > + const int *dst_offsets, *src_offsets; > + int target_size; > + void *argptr; > + abi_ulong *target_rt_dev_ptr; > + unsigned long *host_rt_dev_ptr; > + abi_long ret; > + int i; > + > + assert(ie->access == IOC_W); > + assert(*arg_type == TYPE_PTR); > + arg_type++; > + assert(*arg_type == TYPE_STRUCT); > + target_size = thunk_type_size(arg_type, 0); > + argptr = lock_user(VERIFY_READ, arg, target_size, 1); > + if (!argptr) { > + return -TARGET_EFAULT; > + } > + arg_type++; > + assert(*arg_type == (int)STRUCT_rtentry); > + se = struct_entries + *arg_type++; > + assert(se->convert[0] == NULL); > + /* convert struct here to be able to catch rt_dev string */ > + field_types = se->field_types; > + dst_offsets = se->field_offsets[THUNK_HOST]; > + src_offsets = se->field_offsets[THUNK_TARGET]; > + for (i = 0; i < se->nb_fields; i++) { > + if (dst_offsets[i] == offsetof(struct rtentry, rt_dev)) { > + assert(*field_types == TYPE_PTRVOID); > + target_rt_dev_ptr = (abi_ulong *)(argptr + src_offsets[i]); > + host_rt_dev_ptr = (unsigned long *)(buf_temp + dst_offsets[i]); > + if (*target_rt_dev_ptr != 0) { > + *host_rt_dev_ptr = (unsigned long)lock_user_string( > + tswapal(*target_rt_dev_ptr)); > + if (!*host_rt_dev_ptr) { > + unlock_user(argptr, arg, 0); > + return -TARGET_EFAULT; > + } > + } else { > + *host_rt_dev_ptr = 0; > + } > + field_types++; > + continue; > + } > + field_types = thunk_convert(buf_temp + dst_offsets[i], > + argptr + src_offsets[i], > + field_types, THUNK_HOST); > + } > + unlock_user(argptr, arg, 0); > + > + ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); > + if (*host_rt_dev_ptr != 0) { > + unlock_user((void *)*host_rt_dev_ptr, > + *target_rt_dev_ptr, 0); > + } > + return ret; > +} > + > static IOCTLEntry ioctl_entries[] = { > #define IOCTL(cmd, access, ...) \ > { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
On 27 May 2013 19:48, Laurent Vivier <laurent@vivier.eu> wrote: > This allows to pass the device name. > > You can test this with the "route" command. > > WITHOUT this patch: > > $ sudo route add -net default gw 10.0.3.1 eth0 > SIOCADDRT: Bad address > $ netstat -nr > Kernel IP routing table > Destination Gateway Genmask Flags MSS Window irtt Ifa > 10.0.3.0 0.0.0.0 255.255.255.0 U 0 0 0 eth > > WITH this patch: > > $ sudo route add -net default gw 10.0.3.1 eth0 > $ netstat -nr > Kernel IP routing table > Destination Gateway Genmask Flags MSS Window irtt Ifa > 0.0.0.0 10.0.3.1 0.0.0.0 UG 0 0 0 eth > 10.0.3.0 0.0.0.0 255.255.255.0 U 0 0 0 eth > > Signed-off-by: Laurent Vivier <laurent@vivier.eu> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Incidentally, the command works without the patch if the guest base is zero (eg x86_64-on-x86_64); but now we use guest base more often so the patch is required. (Having thunk_convert treat pointers in structs just like longs, ie simple byteswap, is a bit dubious. I'd be tempted to put in a warning at least if we hit that code path, except I suspect we have some current uses which do a thunk_convert of the whole struct and then fix up the pointer afterwards.) thanks -- PMM
diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h index 8a47767..439c2a9 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h @@ -88,8 +88,6 @@ #endif IOCTL(SIOCATMARK, 0, TYPE_NULL) - IOCTL(SIOCADDRT, IOC_W, MK_PTR(MK_STRUCT(STRUCT_rtentry))) - IOCTL(SIOCDELRT, IOC_W, MK_PTR(MK_STRUCT(STRUCT_rtentry))) 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))) @@ -379,3 +377,7 @@ MK_PTR(MK_STRUCT(STRUCT_dm_ioctl))) IOCTL_SPECIAL(DM_DEV_SET_GEOMETRY, IOC_RW, do_ioctl_dm, MK_PTR(MK_STRUCT(STRUCT_dm_ioctl))) + IOCTL_SPECIAL(SIOCADDRT, IOC_W, do_ioctl_rt, + MK_PTR(MK_STRUCT(STRUCT_rtentry))) + IOCTL_SPECIAL(SIOCDELRT, IOC_W, do_ioctl_rt, + MK_PTR(MK_STRUCT(STRUCT_rtentry))) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 1b3c0ed..a5cd166 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -105,6 +105,7 @@ int __clone2(int (*fn)(void *), void *child_stack_base, #include <linux/vt.h> #include <linux/dm-ioctl.h> #include <linux/reboot.h> +#include <linux/route.h> #include "linux_loop.h" #include "cpu-uname.h" @@ -3714,6 +3715,69 @@ out: return ret; } +static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp, + int fd, abi_long cmd, abi_long arg) +{ + const argtype *arg_type = ie->arg_type; + const StructEntry *se; + const argtype *field_types; + const int *dst_offsets, *src_offsets; + int target_size; + void *argptr; + abi_ulong *target_rt_dev_ptr; + unsigned long *host_rt_dev_ptr; + abi_long ret; + int i; + + assert(ie->access == IOC_W); + assert(*arg_type == TYPE_PTR); + arg_type++; + assert(*arg_type == TYPE_STRUCT); + target_size = thunk_type_size(arg_type, 0); + argptr = lock_user(VERIFY_READ, arg, target_size, 1); + if (!argptr) { + return -TARGET_EFAULT; + } + arg_type++; + assert(*arg_type == (int)STRUCT_rtentry); + se = struct_entries + *arg_type++; + assert(se->convert[0] == NULL); + /* convert struct here to be able to catch rt_dev string */ + field_types = se->field_types; + dst_offsets = se->field_offsets[THUNK_HOST]; + src_offsets = se->field_offsets[THUNK_TARGET]; + for (i = 0; i < se->nb_fields; i++) { + if (dst_offsets[i] == offsetof(struct rtentry, rt_dev)) { + assert(*field_types == TYPE_PTRVOID); + target_rt_dev_ptr = (abi_ulong *)(argptr + src_offsets[i]); + host_rt_dev_ptr = (unsigned long *)(buf_temp + dst_offsets[i]); + if (*target_rt_dev_ptr != 0) { + *host_rt_dev_ptr = (unsigned long)lock_user_string( + tswapal(*target_rt_dev_ptr)); + if (!*host_rt_dev_ptr) { + unlock_user(argptr, arg, 0); + return -TARGET_EFAULT; + } + } else { + *host_rt_dev_ptr = 0; + } + field_types++; + continue; + } + field_types = thunk_convert(buf_temp + dst_offsets[i], + argptr + src_offsets[i], + field_types, THUNK_HOST); + } + unlock_user(argptr, arg, 0); + + ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); + if (*host_rt_dev_ptr != 0) { + unlock_user((void *)*host_rt_dev_ptr, + *target_rt_dev_ptr, 0); + } + return ret; +} + static IOCTLEntry ioctl_entries[] = { #define IOCTL(cmd, access, ...) \ { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
This allows to pass the device name. You can test this with the "route" command. WITHOUT this patch: $ sudo route add -net default gw 10.0.3.1 eth0 SIOCADDRT: Bad address $ netstat -nr Kernel IP routing table Destination Gateway Genmask Flags MSS Window irtt Ifa 10.0.3.0 0.0.0.0 255.255.255.0 U 0 0 0 eth WITH this patch: $ sudo route add -net default gw 10.0.3.1 eth0 $ netstat -nr Kernel IP routing table Destination Gateway Genmask Flags MSS Window irtt Ifa 0.0.0.0 10.0.3.1 0.0.0.0 UG 0 0 0 eth 10.0.3.0 0.0.0.0 255.255.255.0 U 0 0 0 eth Signed-off-by: Laurent Vivier <laurent@vivier.eu> --- linux-user/ioctls.h | 6 +++-- linux-user/syscall.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 2 deletions(-)