Skip to content

Commit 709b46e

Browse files
ebiedermdavem330
authored andcommitted
net: Add compat ioctl support for the ipv4 multicast ioctl SIOCGETSGCNT
SIOCGETSGCNT is not a unique ioctl value as it it maps tio SIOCPROTOPRIVATE +1, which unfortunately means the existing infrastructure for compat networking ioctls is insufficient. A trivial compact ioctl implementation would conflict with: SIOCAX25ADDUID SIOCAIPXPRISLT SIOCGETSGCNT_IN6 SIOCGETSGCNT SIOCRSSCAUSE SIOCX25SSUBSCRIP SIOCX25SDTEFACILITIES To make this work I have updated the compat_ioctl decode path to mirror the the normal ioctl decode path. I have added an ipv4 inet_compat_ioctl function so that I can have ipv4 specific compat ioctls. I have added a compat_ioctl function into struct proto so I can break out ioctls by which kind of ip socket I am using. I have added a compat_raw_ioctl function because SIOCGETSGCNT only works on raw sockets. I have added a ipmr_compat_ioctl that mirrors the normal ipmr_ioctl. This was necessary because unfortunately the struct layout for the SIOCGETSGCNT has unsigned longs in it so changes between 32bit and 64bit kernels. This change was sufficient to run a 32bit ip multicast routing daemon on a 64bit kernel. Reported-by: Bill Fenner <fenner@aristanetworks.com> Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 13ad177 commit 709b46e

File tree

5 files changed

+84
-0
lines changed

5 files changed

+84
-0
lines changed

include/linux/mroute.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ static inline int ip_mroute_opt(int opt)
150150
extern int ip_mroute_setsockopt(struct sock *, int, char __user *, unsigned int);
151151
extern int ip_mroute_getsockopt(struct sock *, int, char __user *, int __user *);
152152
extern int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg);
153+
extern int ipmr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg);
153154
extern int ip_mr_init(void);
154155
#else
155156
static inline

include/net/sock.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -753,6 +753,8 @@ struct proto {
753753
int level,
754754
int optname, char __user *optval,
755755
int __user *option);
756+
int (*compat_ioctl)(struct sock *sk,
757+
unsigned int cmd, unsigned long arg);
756758
#endif
757759
int (*sendmsg)(struct kiocb *iocb, struct sock *sk,
758760
struct msghdr *msg, size_t len);

net/ipv4/af_inet.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -880,6 +880,19 @@ int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
880880
}
881881
EXPORT_SYMBOL(inet_ioctl);
882882

883+
#ifdef CONFIG_COMPAT
884+
int inet_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
885+
{
886+
struct sock *sk = sock->sk;
887+
int err = -ENOIOCTLCMD;
888+
889+
if (sk->sk_prot->compat_ioctl)
890+
err = sk->sk_prot->compat_ioctl(sk, cmd, arg);
891+
892+
return err;
893+
}
894+
#endif
895+
883896
const struct proto_ops inet_stream_ops = {
884897
.family = PF_INET,
885898
.owner = THIS_MODULE,
@@ -903,6 +916,7 @@ const struct proto_ops inet_stream_ops = {
903916
#ifdef CONFIG_COMPAT
904917
.compat_setsockopt = compat_sock_common_setsockopt,
905918
.compat_getsockopt = compat_sock_common_getsockopt,
919+
.compat_ioctl = inet_compat_ioctl,
906920
#endif
907921
};
908922
EXPORT_SYMBOL(inet_stream_ops);
@@ -929,6 +943,7 @@ const struct proto_ops inet_dgram_ops = {
929943
#ifdef CONFIG_COMPAT
930944
.compat_setsockopt = compat_sock_common_setsockopt,
931945
.compat_getsockopt = compat_sock_common_getsockopt,
946+
.compat_ioctl = inet_compat_ioctl,
932947
#endif
933948
};
934949
EXPORT_SYMBOL(inet_dgram_ops);
@@ -959,6 +974,7 @@ static const struct proto_ops inet_sockraw_ops = {
959974
#ifdef CONFIG_COMPAT
960975
.compat_setsockopt = compat_sock_common_setsockopt,
961976
.compat_getsockopt = compat_sock_common_getsockopt,
977+
.compat_ioctl = inet_compat_ioctl,
962978
#endif
963979
};
964980

net/ipv4/ipmr.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
#include <linux/notifier.h>
6161
#include <linux/if_arp.h>
6262
#include <linux/netfilter_ipv4.h>
63+
#include <linux/compat.h>
6364
#include <net/ipip.h>
6465
#include <net/checksum.h>
6566
#include <net/netlink.h>
@@ -1434,6 +1435,51 @@ int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg)
14341435
}
14351436
}
14361437

1438+
#ifdef CONFIG_COMPAT
1439+
struct compat_sioc_sg_req {
1440+
struct in_addr src;
1441+
struct in_addr grp;
1442+
compat_ulong_t pktcnt;
1443+
compat_ulong_t bytecnt;
1444+
compat_ulong_t wrong_if;
1445+
};
1446+
1447+
int ipmr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg)
1448+
{
1449+
struct sioc_sg_req sr;
1450+
struct mfc_cache *c;
1451+
struct net *net = sock_net(sk);
1452+
struct mr_table *mrt;
1453+
1454+
mrt = ipmr_get_table(net, raw_sk(sk)->ipmr_table ? : RT_TABLE_DEFAULT);
1455+
if (mrt == NULL)
1456+
return -ENOENT;
1457+
1458+
switch (cmd) {
1459+
case SIOCGETSGCNT:
1460+
if (copy_from_user(&sr, arg, sizeof(sr)))
1461+
return -EFAULT;
1462+
1463+
rcu_read_lock();
1464+
c = ipmr_cache_find(mrt, sr.src.s_addr, sr.grp.s_addr);
1465+
if (c) {
1466+
sr.pktcnt = c->mfc_un.res.pkt;
1467+
sr.bytecnt = c->mfc_un.res.bytes;
1468+
sr.wrong_if = c->mfc_un.res.wrong_if;
1469+
rcu_read_unlock();
1470+
1471+
if (copy_to_user(arg, &sr, sizeof(sr)))
1472+
return -EFAULT;
1473+
return 0;
1474+
}
1475+
rcu_read_unlock();
1476+
return -EADDRNOTAVAIL;
1477+
default:
1478+
return -ENOIOCTLCMD;
1479+
}
1480+
}
1481+
#endif
1482+
14371483

14381484
static int ipmr_device_event(struct notifier_block *this, unsigned long event, void *ptr)
14391485
{

net/ipv4/raw.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
#include <linux/seq_file.h>
7777
#include <linux/netfilter.h>
7878
#include <linux/netfilter_ipv4.h>
79+
#include <linux/compat.h>
7980

8081
static struct raw_hashinfo raw_v4_hashinfo = {
8182
.lock = __RW_LOCK_UNLOCKED(raw_v4_hashinfo.lock),
@@ -838,6 +839,23 @@ static int raw_ioctl(struct sock *sk, int cmd, unsigned long arg)
838839
}
839840
}
840841

842+
#ifdef CONFIG_COMPAT
843+
static int compat_raw_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg)
844+
{
845+
switch (cmd) {
846+
case SIOCOUTQ:
847+
case SIOCINQ:
848+
return -ENOIOCTLCMD;
849+
default:
850+
#ifdef CONFIG_IP_MROUTE
851+
return ipmr_compat_ioctl(sk, cmd, compat_ptr(arg));
852+
#else
853+
return -ENOIOCTLCMD;
854+
#endif
855+
}
856+
}
857+
#endif
858+
841859
struct proto raw_prot = {
842860
.name = "RAW",
843861
.owner = THIS_MODULE,
@@ -860,6 +878,7 @@ struct proto raw_prot = {
860878
#ifdef CONFIG_COMPAT
861879
.compat_setsockopt = compat_raw_setsockopt,
862880
.compat_getsockopt = compat_raw_getsockopt,
881+
.compat_ioctl = compat_raw_ioctl,
863882
#endif
864883
};
865884

0 commit comments

Comments
 (0)