diff options
| author | Alexander Viro <viro@parcelfarce.linux.theplanet.co.uk> | 2004-05-30 06:09:42 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2004-05-30 06:09:42 -0700 |
| commit | ea481f6f7b19ed8407d1223f705f37b691108d11 (patch) | |
| tree | 937649574b5d73e3cb776ab236ba01f756b1c8c2 | |
| parent | eaeaf871396c3e345d293dda3b1b2cd195eadf59 (diff) | |
[PATCH] sparse: SIOCGIFCONF handling - the rest of it
Fixed the type of SIOCGIFCONF callback; inet instance was already
correctly annotated, decnet one was _not_. Moreover, decnet callback
needed fixing - dereferencing userland address.
| -rw-r--r-- | include/linux/netdevice.h | 2 | ||||
| -rw-r--r-- | net/core/dev.c | 2 | ||||
| -rw-r--r-- | net/decnet/dn_dev.c | 24 |
3 files changed, 18 insertions, 10 deletions
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index ad059d78d5ff..d2c25ff41010 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -558,7 +558,7 @@ extern int dev_restart(struct net_device *dev); extern int netpoll_trap(void); #endif -typedef int gifconf_func_t(struct net_device * dev, char * bufptr, int len); +typedef int gifconf_func_t(struct net_device * dev, char __user * bufptr, int len); extern int register_gifconf(unsigned int family, gifconf_func_t * gifconf); static inline int unregister_gifconf(unsigned int family) { diff --git a/net/core/dev.c b/net/core/dev.c index 84384802ce9b..dfd505c1c511 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1958,7 +1958,7 @@ static int dev_ifconf(char __user *arg) { struct ifconf ifc; struct net_device *dev; - char *pos; + char __user *pos; int len; int total; int i; diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index bc27c4efd022..6941da9f5256 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c @@ -1294,35 +1294,43 @@ int unregister_dnaddr_notifier(struct notifier_block *nb) * it as a compile time option. Probably you should use the * rtnetlink interface instead. */ -int dnet_gifconf(struct net_device *dev, char *buf, int len) +int dnet_gifconf(struct net_device *dev, char __user *buf, int len) { struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr; struct dn_ifaddr *ifa; - struct ifreq *ifr = (struct ifreq *)buf; + char buffer[DN_IFREQ_SIZE]; + struct ifreq *ifr = (struct ifreq *)buffer; + struct sockaddr_dn *addr = (struct sockaddr_dn *)&ifr->ifr_addr; int done = 0; if ((dn_db == NULL) || ((ifa = dn_db->ifa_list) == NULL)) return 0; for(; ifa; ifa = ifa->ifa_next) { - if (!ifr) { + if (!buf) { done += sizeof(DN_IFREQ_SIZE); continue; } if (len < DN_IFREQ_SIZE) return done; - memset(ifr, 0, DN_IFREQ_SIZE); + memset(buffer, 0, DN_IFREQ_SIZE); if (ifa->ifa_label) strcpy(ifr->ifr_name, ifa->ifa_label); else strcpy(ifr->ifr_name, dev->name); - (*(struct sockaddr_dn *) &ifr->ifr_addr).sdn_family = AF_DECnet; - (*(struct sockaddr_dn *) &ifr->ifr_addr).sdn_add.a_len = 2; - (*(dn_address *)(*(struct sockaddr_dn *) &ifr->ifr_addr).sdn_add.a_addr) = ifa->ifa_local; + addr->sdn_family = AF_DECnet; + addr->sdn_add.a_len = 2; + memcpy(addr->sdn_add.a_addr, &ifa->ifa_local, + sizeof(dn_address)); + + if (copy_to_user(buf, buffer, DN_IFREQ_SIZE)) { + done = -EFAULT; + break; + } - ifr = (struct ifreq *)((char *)ifr + DN_IFREQ_SIZE); + buf += DN_IFREQ_SIZE; len -= DN_IFREQ_SIZE; done += DN_IFREQ_SIZE; } |
