summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Viro <viro@parcelfarce.linux.theplanet.co.uk>2004-05-30 06:09:42 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-05-30 06:09:42 -0700
commitea481f6f7b19ed8407d1223f705f37b691108d11 (patch)
tree937649574b5d73e3cb776ab236ba01f756b1c8c2
parenteaeaf871396c3e345d293dda3b1b2cd195eadf59 (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.h2
-rw-r--r--net/core/dev.c2
-rw-r--r--net/decnet/dn_dev.c24
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;
}