Messages in this thread Patch in this message |  | | | Date | Thu, 7 Jan 1999 04:21:52 +0100 (CET) | | From | Daniel Kobras <> | | Subject | [PATCH] userspace access in net-ioctl()s. |
| |
Hi,
I hope I'm not missing something here... Recently when messing around with my network card, I found the ioctl routine in rtl8139.c needed some copy_(from|to)_user() calls to behave the way I'd expected it to. Digging a little bit further, I found the same in various other ioctl()-code in drivers/net/. Patch is attached. I'm pretty sure it does the Right Thing[TM] for me in the rtl8139.c case, couldn't test the others though so please check. Thanks,
Daniel.
--- drivers/net/3c59x.c.orig Thu Jan 7 02:00:49 1999 +++ drivers/net/3c59x.c Thu Jan 7 02:57:37 1999 @@ -83,6 +83,7 @@ #include <asm/irq.h> /* For NR_IRQS only. */ #include <asm/bitops.h> #include <asm/io.h> +#include <asm/uaccess.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> @@ -2003,9 +2004,12 @@ { struct vortex_private *vp = (struct vortex_private *)dev->priv; int ioaddr = dev->base_addr; - u16 *data = (u16 *)&rq->ifr_data; + u16 data[4]; int phy = vp->phys[0] & 0x1f; + if (copy_from_user(data,rq->ifr_data,8)) + return -EFAULT; + if (vortex_debug > 2) printk(KERN_DEBUG "%s: In ioct(%-.6s, %#4.4x) %4.4x %4.4x %4.4x %4.4x.\n", dev->name, rq->ifr_ifrn.ifrn_name, cmd, @@ -2017,9 +2021,11 @@ case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ EL3WINDOW(4); data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f); + if (copy_to_user(rq->ifr_data,data,8)) + return -EFAULT; return 0; case SIOCDEVPRIVATE+2: /* Write the specified MII register */ - if (!suser()) + if (!capable(CAP_NET_ADMIN)) return -EPERM; mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]); return 0; --- drivers/net/eepro100.c.orig Thu Jan 7 02:28:47 1999 +++ drivers/net/eepro100.c Thu Jan 7 02:30:52 1999 @@ -62,6 +62,7 @@ #include <asm/spinlock.h> #include <asm/bitops.h> #include <asm/io.h> +#include <asm/uaccess.h> /* * Module documentation @@ -1374,14 +1375,19 @@ { struct speedo_private *sp = (struct speedo_private *)dev->priv; long ioaddr = dev->base_addr; - u16 *data = (u16 *)&rq->ifr_data; + u16 data[4]; int phy = sp->phy[0] & 0x1f; + if (copy_from_user(data,rq->ifr_data,8)) + return -EFAULT; + switch(cmd) { case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ data[0] = phy; case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ data[3] = mdio_read(ioaddr, data[0], data[1]); + if (copy_to_user(rq->ifr_data,data,8)) + return -EFAULT; return 0; case SIOCDEVPRIVATE+2: /* Write the specified MII register */ if (!capable(CAP_NET_ADMIN)) --- drivers/net/epic100.c.orig Thu Jan 7 02:31:03 1999 +++ drivers/net/epic100.c Thu Jan 7 02:35:08 1999 @@ -78,6 +78,7 @@ #include <asm/bitops.h> #include <asm/io.h> #include <asm/dma.h> +#include <asm/uaccess.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> @@ -1275,7 +1276,10 @@ static int mii_ioctl(struct device *dev, struct ifreq *rq, int cmd) { long ioaddr = dev->base_addr; - u16 *data = (u16 *)&rq->ifr_data; + u16 data[4]; + + if (copy_from_user(data,rq->ifr_data,8)) + return -EFAULT; switch(cmd) { case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ @@ -1293,9 +1297,11 @@ outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL); #endif } + if (copy_to_user(rq->ifr_data,data,8)) + return -EFAULT; return 0; case SIOCDEVPRIVATE+2: /* Write the specified MII register */ - if (!suser()) + if (!capable(CAP_NET_ADMIN)) return -EPERM; if (! dev->start) { outl(0x0200, ioaddr + GENCTL); --- drivers/net/plip.c.orig Thu Jan 7 02:44:48 1999 +++ drivers/net/plip.c Thu Jan 7 03:03:18 1999 @@ -108,6 +108,7 @@ #include <asm/irq.h> #include <asm/byteorder.h> #include <asm/spinlock.h> +#include <asm/uaccess.h> #include <linux/parport.h> @@ -1111,16 +1112,21 @@ plip_ioctl(struct device *dev, struct ifreq *rq, int cmd) { struct net_local *nl = (struct net_local *) dev->priv; - struct plipconf *pc = (struct plipconf *) &rq->ifr_data; + struct plipconf pc; - switch(pc->pcmd) { + if (copy_from_user(&pc,rq->ifr_data,sizeof(struct plipconf))) + return -EFAULT; + + switch(pc.pcmd) { case PLIP_GET_TIMEOUT: - pc->trigger = nl->trigger; - pc->nibble = nl->nibble; + pc.trigger = nl->trigger; + pc.nibble = nl->nibble; + if (copy_to_user(rq->ifr_data,&pc,sizeof(struct plipconf))) + return -EFAULT; break; case PLIP_SET_TIMEOUT: - nl->trigger = pc->trigger; - nl->nibble = pc->nibble; + nl->trigger = pc.trigger; + nl->nibble = pc.nibble; break; default: return -EOPNOTSUPP; --- drivers/net/rtl8139.c.orig Fri Jan 1 02:25:59 1999 +++ drivers/net/rtl8139.c Thu Jan 7 03:00:05 1999 @@ -73,6 +73,7 @@ #include <asm/processor.h> /* Processor type for cache alignment. */ #include <asm/bitops.h> #include <asm/io.h> +#include <asm/uaccess.h> /* Kernel compatibility defines, some common to David Hind's PCMCIA package. This is only in the support-all-kernels source code. */ @@ -1277,7 +1278,10 @@ static int mii_ioctl(struct device *dev, struct ifreq *rq, int cmd) { struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; - u16 *data = (u16 *)&rq->ifr_data; + u16 data[4]; + + if (copy_from_user(data,rq->ifr_data,8)) + return -EFAULT; switch(cmd) { case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ @@ -1285,11 +1289,13 @@ /* Fall Through */ case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); + if (copy_to_user(rq->ifr_data,data,8)) + return -EFAULT; return 0; case SIOCDEVPRIVATE+2: /* Write the specified MII register */ - if (!suser()) + if (!capable(CAP_NET_ADMIN)) return -EPERM; - mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); + mdio_write(dev, data[0] & 0x3f, data[1] & 0x1f, data[2]); return 0; default: return -EOPNOTSUPP; --- drivers/net/shaper.c.orig Thu Jan 7 02:45:18 1999 +++ drivers/net/shaper.c Thu Jan 7 03:02:36 1999 @@ -72,6 +72,7 @@ #include <net/dst.h> #include <net/arp.h> #include <linux/if_shaper.h> +#include <asm/uaccess.h> int sh_debug; /* Debug flag */ @@ -553,13 +554,17 @@ static int shaper_ioctl(struct device *dev, struct ifreq *ifr, int cmd) { - struct shaperconf *ss= (struct shaperconf *)&ifr->ifr_data; + struct shaperconf ss; struct shaper *sh=dev->priv; - switch(ss->ss_cmd) + + if (copy_from_user(&ss,ifr->ifr_data,sizeof(struct shaperconf))) + return -EFAULT; + + switch(ss.ss_cmd) { case SHAPER_SET_DEV: { - struct device *them=dev_get(ss->ss_name); + struct device *them=dev_get(ss.ss_name); if(them==NULL) return -ENODEV; if(sh->dev) @@ -569,13 +574,18 @@ case SHAPER_GET_DEV: if(sh->dev==NULL) return -ENODEV; - strcpy(ss->ss_name, sh->dev->name); + strcpy(ss.ss_name, sh->dev->name); + if (copy_to_user(ifr->ifr_data,&ss,sizeof(struct shaperconf))) + return -EFAULT; return 0; case SHAPER_SET_SPEED: - shaper_setspeed(sh,ss->ss_speed); + shaper_setspeed(sh,ss.ss_speed); return 0; case SHAPER_GET_SPEED: - ss->ss_speed=sh->bitspersec; + ss.ss_speed=sh->bitspersec; + if (copy_to_user(ifr->ifr_data,&ss,sizeof(struct shaperconf))) + return -EFAULT; + return 0; default: return -EINVAL; --- drivers/net/via-rhine.c.orig Thu Jan 7 02:50:01 1999 +++ drivers/net/via-rhine.c Thu Jan 7 02:52:48 1999 @@ -79,6 +79,7 @@ #include <asm/processor.h> /* Processor type for cache alignment. */ #include <asm/bitops.h> #include <asm/io.h> +#include <asm/uaccess.h> /* This driver was written to use PCI memory space, however some boards only work with I/O space accesses. */ @@ -1187,17 +1188,22 @@ static int mii_ioctl(struct device *dev, struct ifreq *rq, int cmd) { - u16 *data = (u16 *)&rq->ifr_data; + u16 data[4]; + if (copy_from_user(data,rq->ifr_data,8)) + return -EFAULT; + switch(cmd) { case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ data[0] = ((struct netdev_private *)dev->priv)->phys[0] & 0x1f; /* Fall Through */ case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); + if (copy_to_user(rq->ifr_data,data,8)) + return -EFAULT; return 0; case SIOCDEVPRIVATE+2: /* Write the specified MII register */ - if (!suser()) + if (!capable(CAP_NET_ADMIN)) return -EPERM; mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); return 0; --- drivers/net/yellowfin.c.orig Thu Jan 7 02:53:02 1999 +++ drivers/net/yellowfin.c Thu Jan 7 02:54:32 1999 @@ -77,6 +77,7 @@ #include <asm/processor.h> /* Processor type for cache alignment. */ #include <asm/bitops.h> #include <asm/io.h> +#include <asm/uaccess.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> @@ -1353,17 +1354,22 @@ static int mii_ioctl(struct device *dev, struct ifreq *rq, int cmd) { long ioaddr = dev->base_addr; - u16 *data = (u16 *)&rq->ifr_data; + u16 data[4]; + if (copy_from_user(data,rq->ifr_data,8)) + return -EFAULT; + switch(cmd) { case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ data[0] = ((struct yellowfin_private *)dev->priv)->phys[0] & 0x1f; /* Fall Through */ case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f); + if (copy_to_user(rq->ifr_data,data,8)) + return -EFAULT; return 0; case SIOCDEVPRIVATE+2: /* Write the specified MII register */ - if (!suser()) + if (!capable(CAP_NET_ADMIN)) return -EPERM; mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]); return 0; |  |