[NET]: Fix ipx/econet/appletalk/irda ioctl crashes
authorPetr Vandrovec <petr@vandrovec.name>
Tue, 28 Mar 2006 07:39:31 +0000 (23:39 -0800)
committerDavid S. Miller <davem@sunset.davemloft.net>
Wed, 29 Mar 2006 01:02:43 +0000 (17:02 -0800)
Fix kernel oopses whenever somebody issues compatible ioctl on AppleTalk,
Econet, IPX or IRDA socket.  For AppleTalk/Econet/IRDA it restores state
in which these sockets were before compat_ioctl was introduced to the socket
ops, for IPX it implements support for 4 ioctls which were not implemented
before - as these ioctls use structures which match between 32bit and 64bit
userspace, no special code is needed, just call 64bit ioctl handler.

Signed-off-by: Petr Vandrovec <petr@vandrovec.name>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/appletalk/ddp.c
net/econet/af_econet.c
net/ipx/af_ipx.c
net/irda/af_irda.c

index 697ac55e29dc6ec6061ab3d1972dc91ec8e13c70..7b1eb9a4fc96881a68f9c23e92ea1679edc8cb4d 100644 (file)
@@ -1819,6 +1819,22 @@ static int atalk_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
        return rc;
 }
 
+
+#ifdef CONFIG_COMPAT
+static int atalk_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+       /*
+        * All Appletalk ioctls except SIOCATALKDIFADDR are standard.  And
+        * SIOCATALKDIFADDR is handled by upper layer as well, so there is
+        * nothing to do.  Eventually SIOCATALKDIFADDR should be moved
+        * here so there is no generic SIOCPROTOPRIVATE translation in the
+        * system.
+        */
+       return -ENOIOCTLCMD;
+}
+#endif
+
+
 static struct net_proto_family atalk_family_ops = {
        .family         = PF_APPLETALK,
        .create         = atalk_create,
@@ -1836,6 +1852,9 @@ static const struct proto_ops SOCKOPS_WRAPPED(atalk_dgram_ops) = {
        .getname        = atalk_getname,
        .poll           = datagram_poll,
        .ioctl          = atalk_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = atalk_compat_ioctl,
+#endif
        .listen         = sock_no_listen,
        .shutdown       = sock_no_shutdown,
        .setsockopt     = sock_no_setsockopt,
index c792994d795257a90aaa87ad33d305db31613dd2..0c4c83bb2a59f528b5ea84f054395e36a4047709 100644 (file)
@@ -693,6 +693,19 @@ static int econet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg
        return 0;
 }
 
+#ifdef CONFIG_COMPAT
+static int econet_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+       /*
+        * All ioctls provided by econet are standard.  There is one gotcha, sockaddr_ec
+        * differs between 32bit and 64bit.  Fortunately nobody in kernel uses portion
+        * of sockaddr which differs between 32bit and 64bit, so we do not need special
+        * handling.
+        */
+       return -ENOIOCTLCMD;
+}
+#endif
+
 static struct net_proto_family econet_family_ops = {
        .family =       PF_ECONET,
        .create =       econet_create,
@@ -710,6 +723,9 @@ static const struct proto_ops SOCKOPS_WRAPPED(econet_ops) = {
        .getname =      econet_getname, 
        .poll =         datagram_poll,
        .ioctl =        econet_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl = econet_compat_ioctl,
+#endif
        .listen =       sock_no_listen,
        .shutdown =     sock_no_shutdown,
        .setsockopt =   sock_no_setsockopt,
index 0fb513a34d11acc84f239545faa65b9a9a0eb9da..2dbf134d5266068e633896e909a71d2f5572c8b4 100644 (file)
@@ -1892,6 +1892,29 @@ static int ipx_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
        return rc;
 }
 
+
+#ifdef CONFIG_COMPAT
+static int ipx_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+       /*
+        * These 4 commands use same structure on 32bit and 64bit.  Rest of IPX
+        * commands is handled by generic ioctl code.  As these commands are
+        * SIOCPROTOPRIVATE..SIOCPROTOPRIVATE+3, they cannot be handled by generic
+        * code.
+        */
+       switch (cmd) {
+       case SIOCAIPXITFCRT:
+       case SIOCAIPXPRISLT:
+       case SIOCIPXCFGDATA:
+       case SIOCIPXNCPCONN:
+               return ipx_ioctl(sock, cmd, arg);
+       default:
+               return -ENOIOCTLCMD;
+       }
+}
+#endif
+
+
 /*
  * Socket family declarations
  */
@@ -1913,6 +1936,9 @@ static const struct proto_ops SOCKOPS_WRAPPED(ipx_dgram_ops) = {
        .getname        = ipx_getname,
        .poll           = datagram_poll,
        .ioctl          = ipx_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = ipx_compat_ioctl,
+#endif
        .listen         = sock_no_listen,
        .shutdown       = sock_no_shutdown, /* FIXME: support shutdown */
        .setsockopt     = ipx_setsockopt,
index 627b11342233d2abba2a606fcf982d93ccc57677..2f37c9f35e272a5e9026947835584806ff3324cc 100644 (file)
@@ -1830,6 +1830,19 @@ static int irda_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
        return 0;
 }
 
+#ifdef CONFIG_COMPAT
+/*
+ * Function irda_ioctl (sock, cmd, arg)
+ */
+static int irda_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+       /*
+        * All IRDA's ioctl are standard ones.
+        */
+       return -ENOIOCTLCMD;
+}
+#endif
+
 /*
  * Function irda_setsockopt (sock, level, optname, optval, optlen)
  *
@@ -2476,6 +2489,9 @@ static const struct proto_ops SOCKOPS_WRAPPED(irda_stream_ops) = {
        .getname =      irda_getname,
        .poll =         irda_poll,
        .ioctl =        irda_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl = irda_compat_ioctl,
+#endif
        .listen =       irda_listen,
        .shutdown =     irda_shutdown,
        .setsockopt =   irda_setsockopt,
@@ -2497,6 +2513,9 @@ static const struct proto_ops SOCKOPS_WRAPPED(irda_seqpacket_ops) = {
        .getname =      irda_getname,
        .poll =         datagram_poll,
        .ioctl =        irda_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl = irda_compat_ioctl,
+#endif
        .listen =       irda_listen,
        .shutdown =     irda_shutdown,
        .setsockopt =   irda_setsockopt,
@@ -2518,6 +2537,9 @@ static const struct proto_ops SOCKOPS_WRAPPED(irda_dgram_ops) = {
        .getname =      irda_getname,
        .poll =         datagram_poll,
        .ioctl =        irda_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl = irda_compat_ioctl,
+#endif
        .listen =       irda_listen,
        .shutdown =     irda_shutdown,
        .setsockopt =   irda_setsockopt,
@@ -2540,6 +2562,9 @@ static const struct proto_ops SOCKOPS_WRAPPED(irda_ultra_ops) = {
        .getname =      irda_getname,
        .poll =         datagram_poll,
        .ioctl =        irda_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl = irda_compat_ioctl,
+#endif
        .listen =       sock_no_listen,
        .shutdown =     irda_shutdown,
        .setsockopt =   irda_setsockopt,