From 417c3522b3202dacce4873cfb0190459fbce95c5 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 18 Nov 2013 17:04:58 +0000 Subject: net/compat: Fix minor information leak in siocdevprivate_ioctl() We don't need to check that ifr_data itself is a valid user pointer, but we should check &ifr_data is. Thankfully the copy of ifr_name is checked, so this can only leak a few bytes from immediately above the user address limit. Signed-off-by: Ben Hutchings --- net/socket.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/socket.c b/net/socket.c index c226aceee65b..fbb6ec13b1f4 100644 --- a/net/socket.c +++ b/net/socket.c @@ -3015,19 +3015,16 @@ static int siocdevprivate_ioctl(struct net *net, unsigned int cmd, if (copy_from_user(&tmp_buf[0], &(u_ifreq32->ifr_ifrn.ifrn_name[0]), IFNAMSIZ)) return -EFAULT; - if (__get_user(data32, &u_ifreq32->ifr_ifru.ifru_data)) + if (get_user(data32, &u_ifreq32->ifr_ifru.ifru_data)) return -EFAULT; data64 = compat_ptr(data32); u_ifreq64 = compat_alloc_user_space(sizeof(*u_ifreq64)); - /* Don't check these user accesses, just let that get trapped - * in the ioctl handler instead. - */ if (copy_to_user(&u_ifreq64->ifr_ifrn.ifrn_name[0], &tmp_buf[0], IFNAMSIZ)) return -EFAULT; - if (__put_user(data64, &u_ifreq64->ifr_ifru.ifru_data)) + if (put_user(data64, &u_ifreq64->ifr_ifru.ifru_data)) return -EFAULT; return dev_ioctl(net, cmd, u_ifreq64); -- cgit v1.2.3 From 590d4693fb1c96ce441d11c6d1acb413a90b62e5 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 18 Nov 2013 17:04:13 +0000 Subject: net/compat: Merge multiple implementations of ifreq::ifr_data conversion Signed-off-by: Ben Hutchings --- net/socket.c | 49 ++++++------------------------------------------- 1 file changed, 6 insertions(+), 43 deletions(-) (limited to 'net') diff --git a/net/socket.c b/net/socket.c index fbb6ec13b1f4..7a766ab83ca5 100644 --- a/net/socket.c +++ b/net/socket.c @@ -2964,11 +2964,8 @@ static int bond_ioctl(struct net *net, unsigned int cmd, struct compat_ifreq __user *ifr32) { struct ifreq kifr; - struct ifreq __user *uifr; mm_segment_t old_fs; int err; - u32 data; - void __user *datap; switch (cmd) { case SIOCBONDENSLAVE: @@ -2985,26 +2982,13 @@ static int bond_ioctl(struct net *net, unsigned int cmd, set_fs(old_fs); return err; - case SIOCBONDSLAVEINFOQUERY: - case SIOCBONDINFOQUERY: - uifr = compat_alloc_user_space(sizeof(*uifr)); - if (copy_in_user(&uifr->ifr_name, &ifr32->ifr_name, IFNAMSIZ)) - return -EFAULT; - - if (get_user(data, &ifr32->ifr_ifru.ifru_data)) - return -EFAULT; - - datap = compat_ptr(data); - if (put_user(datap, &uifr->ifr_ifru.ifru_data)) - return -EFAULT; - - return dev_ioctl(net, cmd, uifr); default: return -ENOIOCTLCMD; } } -static int siocdevprivate_ioctl(struct net *net, unsigned int cmd, +/* Handle ioctls that use ifreq::ifr_data and just need struct ifreq converted */ +static int compat_ifr_data_ioctl(struct net *net, unsigned int cmd, struct compat_ifreq __user *u_ifreq32) { struct ifreq __user *u_ifreq64; @@ -3104,27 +3088,6 @@ static int compat_sioc_ifmap(struct net *net, unsigned int cmd, return err; } -static int compat_siocshwtstamp(struct net *net, struct compat_ifreq __user *uifr32) -{ - void __user *uptr; - compat_uptr_t uptr32; - struct ifreq __user *uifr; - - uifr = compat_alloc_user_space(sizeof(*uifr)); - if (copy_in_user(uifr, uifr32, sizeof(struct compat_ifreq))) - return -EFAULT; - - if (get_user(uptr32, &uifr32->ifr_data)) - return -EFAULT; - - uptr = compat_ptr(uptr32); - - if (put_user(uptr, &uifr->ifr_data)) - return -EFAULT; - - return dev_ioctl(net, SIOCSHWTSTAMP, uifr); -} - struct rtentry32 { u32 rt_pad1; struct sockaddr rt_dst; /* target address */ @@ -3236,7 +3199,7 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock, struct net *net = sock_net(sk); if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) - return siocdevprivate_ioctl(net, cmd, argp); + return compat_ifr_data_ioctl(net, cmd, argp); switch (cmd) { case SIOCSIFBR: @@ -3256,8 +3219,6 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock, case SIOCBONDENSLAVE: case SIOCBONDRELEASE: case SIOCBONDSETHWADDR: - case SIOCBONDSLAVEINFOQUERY: - case SIOCBONDINFOQUERY: case SIOCBONDCHANGEACTIVE: return bond_ioctl(net, cmd, argp); case SIOCADDRT: @@ -3267,8 +3228,10 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock, return do_siocgstamp(net, sock, cmd, argp); case SIOCGSTAMPNS: return do_siocgstampns(net, sock, cmd, argp); + case SIOCBONDSLAVEINFOQUERY: + case SIOCBONDINFOQUERY: case SIOCSHWTSTAMP: - return compat_siocshwtstamp(net, argp); + return compat_ifr_data_ioctl(net, cmd, argp); case FIOSETOWN: case SIOCSPGRP: -- cgit v1.2.3 From fd468c74bd4d6949736810a80d6ca05eb20fba84 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 14 Nov 2013 01:19:29 +0000 Subject: net_tstamp: Add SIOCGHWTSTAMP ioctl to match SIOCSHWTSTAMP SIOCSHWTSTAMP returns the real configuration to the application using it, but there is currently no way for any other application to find out the configuration non-destructively. Add a new ioctl for this, making it unprivileged. Signed-off-by: Ben Hutchings --- Documentation/networking/timestamping.txt | 9 +++++++-- include/uapi/linux/net_tstamp.h | 14 +++++++------- include/uapi/linux/sockios.h | 3 ++- net/core/dev_ioctl.c | 2 ++ net/socket.c | 1 + 5 files changed, 19 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/Documentation/networking/timestamping.txt b/Documentation/networking/timestamping.txt index 98097d8cb910..661d3c316a17 100644 --- a/Documentation/networking/timestamping.txt +++ b/Documentation/networking/timestamping.txt @@ -85,7 +85,7 @@ Filled in if SOF_TIMESTAMPING_SYS_HARDWARE is set. Requires support by the network device and will be empty without that support. -SIOCSHWTSTAMP: +SIOCSHWTSTAMP, SIOCGHWTSTAMP: Hardware time stamping must also be initialized for each device driver that is expected to do hardware time stamping. The parameter is defined in @@ -115,6 +115,10 @@ Only a processes with admin rights may change the configuration. User space is responsible to ensure that multiple processes don't interfere with each other and that the settings are reset. +Any process can read the actual configuration by passing this +structure to ioctl(SIOCGHWTSTAMP) in the same way. However, this has +not been implemented in all drivers. + /* possible values for hwtstamp_config->tx_type */ enum { /* @@ -157,7 +161,8 @@ DEVICE IMPLEMENTATION A driver which supports hardware time stamping must support the SIOCSHWTSTAMP ioctl and update the supplied struct hwtstamp_config with -the actual values as described in the section on SIOCSHWTSTAMP. +the actual values as described in the section on SIOCSHWTSTAMP. It +should also support SIOCGHWTSTAMP. Time stamps for received packets must be stored in the skb. To get a pointer to the shared time stamp structure of the skb call skb_hwtstamps(). Then diff --git a/include/uapi/linux/net_tstamp.h b/include/uapi/linux/net_tstamp.h index c9a7de2a6276..f53879c0f590 100644 --- a/include/uapi/linux/net_tstamp.h +++ b/include/uapi/linux/net_tstamp.h @@ -26,17 +26,17 @@ enum { }; /** - * struct hwtstamp_config - %SIOCSHWTSTAMP parameter + * struct hwtstamp_config - %SIOCGHWTSTAMP and %SIOCSHWTSTAMP parameter * - * @flags: no flags defined right now, must be zero + * @flags: no flags defined right now, must be zero for %SIOCSHWTSTAMP * @tx_type: one of HWTSTAMP_TX_* * @rx_filter: one of HWTSTAMP_FILTER_* * - * %SIOCSHWTSTAMP expects a &struct ifreq with a ifr_data pointer to - * this structure. If the driver or hardware does not support the - * requested @rx_filter value, the driver may use a more general - * filter mode. In this case @rx_filter will indicate the actual mode - * on return. + * %SIOCGHWTSTAMP and %SIOCSHWTSTAMP expect a &struct ifreq with a + * ifr_data pointer to this structure. For %SIOCSHWTSTAMP, if the + * driver or hardware does not support the requested @rx_filter value, + * the driver may use a more general filter mode. In this case + * @rx_filter will indicate the actual mode on return. */ struct hwtstamp_config { int flags; diff --git a/include/uapi/linux/sockios.h b/include/uapi/linux/sockios.h index 7997a506ad41..e888b1aed69f 100644 --- a/include/uapi/linux/sockios.h +++ b/include/uapi/linux/sockios.h @@ -125,7 +125,8 @@ #define SIOCBRDELIF 0x89a3 /* remove interface from bridge */ /* hardware time stamping: parameters in linux/net_tstamp.h */ -#define SIOCSHWTSTAMP 0x89b0 +#define SIOCSHWTSTAMP 0x89b0 /* set and get config */ +#define SIOCGHWTSTAMP 0x89b1 /* get config */ /* Device private ioctl calls */ diff --git a/net/core/dev_ioctl.c b/net/core/dev_ioctl.c index 5b7d0e1d0664..cf999e09bcd2 100644 --- a/net/core/dev_ioctl.c +++ b/net/core/dev_ioctl.c @@ -327,6 +327,7 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd) cmd == SIOCBRADDIF || cmd == SIOCBRDELIF || cmd == SIOCSHWTSTAMP || + cmd == SIOCGHWTSTAMP || cmd == SIOCWANDEV) { err = -EOPNOTSUPP; if (ops->ndo_do_ioctl) { @@ -546,6 +547,7 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg) */ default: if (cmd == SIOCWANDEV || + cmd == SIOCGHWTSTAMP || (cmd >= SIOCDEVPRIVATE && cmd <= SIOCDEVPRIVATE + 15)) { dev_load(net, ifr.ifr_name); diff --git a/net/socket.c b/net/socket.c index 7a766ab83ca5..1a548b70ef3a 100644 --- a/net/socket.c +++ b/net/socket.c @@ -3231,6 +3231,7 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock, case SIOCBONDSLAVEINFOQUERY: case SIOCBONDINFOQUERY: case SIOCSHWTSTAMP: + case SIOCGHWTSTAMP: return compat_ifr_data_ioctl(net, cmd, argp); case FIOSETOWN: -- cgit v1.2.3