[NET]: Fix ipx/econet/appletalk/irda ioctl crashes
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>
This commit is contained in:
committed by
David S. Miller
parent
f1465f7ea9
commit
f6c90b71a3
@@ -1819,6 +1819,22 @@ static int atalk_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
|
|||||||
return rc;
|
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 = {
|
static struct net_proto_family atalk_family_ops = {
|
||||||
.family = PF_APPLETALK,
|
.family = PF_APPLETALK,
|
||||||
.create = atalk_create,
|
.create = atalk_create,
|
||||||
@@ -1836,6 +1852,9 @@ static const struct proto_ops SOCKOPS_WRAPPED(atalk_dgram_ops) = {
|
|||||||
.getname = atalk_getname,
|
.getname = atalk_getname,
|
||||||
.poll = datagram_poll,
|
.poll = datagram_poll,
|
||||||
.ioctl = atalk_ioctl,
|
.ioctl = atalk_ioctl,
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
.compat_ioctl = atalk_compat_ioctl,
|
||||||
|
#endif
|
||||||
.listen = sock_no_listen,
|
.listen = sock_no_listen,
|
||||||
.shutdown = sock_no_shutdown,
|
.shutdown = sock_no_shutdown,
|
||||||
.setsockopt = sock_no_setsockopt,
|
.setsockopt = sock_no_setsockopt,
|
||||||
|
@@ -693,6 +693,19 @@ static int econet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg
|
|||||||
return 0;
|
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 = {
|
static struct net_proto_family econet_family_ops = {
|
||||||
.family = PF_ECONET,
|
.family = PF_ECONET,
|
||||||
.create = econet_create,
|
.create = econet_create,
|
||||||
@@ -710,6 +723,9 @@ static const struct proto_ops SOCKOPS_WRAPPED(econet_ops) = {
|
|||||||
.getname = econet_getname,
|
.getname = econet_getname,
|
||||||
.poll = datagram_poll,
|
.poll = datagram_poll,
|
||||||
.ioctl = econet_ioctl,
|
.ioctl = econet_ioctl,
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
.compat_ioctl = econet_compat_ioctl,
|
||||||
|
#endif
|
||||||
.listen = sock_no_listen,
|
.listen = sock_no_listen,
|
||||||
.shutdown = sock_no_shutdown,
|
.shutdown = sock_no_shutdown,
|
||||||
.setsockopt = sock_no_setsockopt,
|
.setsockopt = sock_no_setsockopt,
|
||||||
|
@@ -1892,6 +1892,29 @@ static int ipx_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
|
|||||||
return rc;
|
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
|
* Socket family declarations
|
||||||
*/
|
*/
|
||||||
@@ -1913,6 +1936,9 @@ static const struct proto_ops SOCKOPS_WRAPPED(ipx_dgram_ops) = {
|
|||||||
.getname = ipx_getname,
|
.getname = ipx_getname,
|
||||||
.poll = datagram_poll,
|
.poll = datagram_poll,
|
||||||
.ioctl = ipx_ioctl,
|
.ioctl = ipx_ioctl,
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
.compat_ioctl = ipx_compat_ioctl,
|
||||||
|
#endif
|
||||||
.listen = sock_no_listen,
|
.listen = sock_no_listen,
|
||||||
.shutdown = sock_no_shutdown, /* FIXME: support shutdown */
|
.shutdown = sock_no_shutdown, /* FIXME: support shutdown */
|
||||||
.setsockopt = ipx_setsockopt,
|
.setsockopt = ipx_setsockopt,
|
||||||
|
@@ -1830,6 +1830,19 @@ static int irda_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
|
|||||||
return 0;
|
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)
|
* 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,
|
.getname = irda_getname,
|
||||||
.poll = irda_poll,
|
.poll = irda_poll,
|
||||||
.ioctl = irda_ioctl,
|
.ioctl = irda_ioctl,
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
.compat_ioctl = irda_compat_ioctl,
|
||||||
|
#endif
|
||||||
.listen = irda_listen,
|
.listen = irda_listen,
|
||||||
.shutdown = irda_shutdown,
|
.shutdown = irda_shutdown,
|
||||||
.setsockopt = irda_setsockopt,
|
.setsockopt = irda_setsockopt,
|
||||||
@@ -2497,6 +2513,9 @@ static const struct proto_ops SOCKOPS_WRAPPED(irda_seqpacket_ops) = {
|
|||||||
.getname = irda_getname,
|
.getname = irda_getname,
|
||||||
.poll = datagram_poll,
|
.poll = datagram_poll,
|
||||||
.ioctl = irda_ioctl,
|
.ioctl = irda_ioctl,
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
.compat_ioctl = irda_compat_ioctl,
|
||||||
|
#endif
|
||||||
.listen = irda_listen,
|
.listen = irda_listen,
|
||||||
.shutdown = irda_shutdown,
|
.shutdown = irda_shutdown,
|
||||||
.setsockopt = irda_setsockopt,
|
.setsockopt = irda_setsockopt,
|
||||||
@@ -2518,6 +2537,9 @@ static const struct proto_ops SOCKOPS_WRAPPED(irda_dgram_ops) = {
|
|||||||
.getname = irda_getname,
|
.getname = irda_getname,
|
||||||
.poll = datagram_poll,
|
.poll = datagram_poll,
|
||||||
.ioctl = irda_ioctl,
|
.ioctl = irda_ioctl,
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
.compat_ioctl = irda_compat_ioctl,
|
||||||
|
#endif
|
||||||
.listen = irda_listen,
|
.listen = irda_listen,
|
||||||
.shutdown = irda_shutdown,
|
.shutdown = irda_shutdown,
|
||||||
.setsockopt = irda_setsockopt,
|
.setsockopt = irda_setsockopt,
|
||||||
@@ -2540,6 +2562,9 @@ static const struct proto_ops SOCKOPS_WRAPPED(irda_ultra_ops) = {
|
|||||||
.getname = irda_getname,
|
.getname = irda_getname,
|
||||||
.poll = datagram_poll,
|
.poll = datagram_poll,
|
||||||
.ioctl = irda_ioctl,
|
.ioctl = irda_ioctl,
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
.compat_ioctl = irda_compat_ioctl,
|
||||||
|
#endif
|
||||||
.listen = sock_no_listen,
|
.listen = sock_no_listen,
|
||||||
.shutdown = irda_shutdown,
|
.shutdown = irda_shutdown,
|
||||||
.setsockopt = irda_setsockopt,
|
.setsockopt = irda_setsockopt,
|
||||||
|
Reference in New Issue
Block a user