Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Eric W. Biederman and committed by
David S. Miller
709b46e8 13ad1774

+84
+1
include/linux/mroute.h
··· 150 150 extern int ip_mroute_setsockopt(struct sock *, int, char __user *, unsigned int); 151 151 extern int ip_mroute_getsockopt(struct sock *, int, char __user *, int __user *); 152 152 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); 153 154 extern int ip_mr_init(void); 154 155 #else 155 156 static inline
+2
include/net/sock.h
··· 753 753 int level, 754 754 int optname, char __user *optval, 755 755 int __user *option); 756 + int (*compat_ioctl)(struct sock *sk, 757 + unsigned int cmd, unsigned long arg); 756 758 #endif 757 759 int (*sendmsg)(struct kiocb *iocb, struct sock *sk, 758 760 struct msghdr *msg, size_t len);
+16
net/ipv4/af_inet.c
··· 880 880 } 881 881 EXPORT_SYMBOL(inet_ioctl); 882 882 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 + 883 896 const struct proto_ops inet_stream_ops = { 884 897 .family = PF_INET, 885 898 .owner = THIS_MODULE, ··· 916 903 #ifdef CONFIG_COMPAT 917 904 .compat_setsockopt = compat_sock_common_setsockopt, 918 905 .compat_getsockopt = compat_sock_common_getsockopt, 906 + .compat_ioctl = inet_compat_ioctl, 919 907 #endif 920 908 }; 921 909 EXPORT_SYMBOL(inet_stream_ops); ··· 943 929 #ifdef CONFIG_COMPAT 944 930 .compat_setsockopt = compat_sock_common_setsockopt, 945 931 .compat_getsockopt = compat_sock_common_getsockopt, 932 + .compat_ioctl = inet_compat_ioctl, 946 933 #endif 947 934 }; 948 935 EXPORT_SYMBOL(inet_dgram_ops); ··· 974 959 #ifdef CONFIG_COMPAT 975 960 .compat_setsockopt = compat_sock_common_setsockopt, 976 961 .compat_getsockopt = compat_sock_common_getsockopt, 962 + .compat_ioctl = inet_compat_ioctl, 977 963 #endif 978 964 }; 979 965
+46
net/ipv4/ipmr.c
··· 60 60 #include <linux/notifier.h> 61 61 #include <linux/if_arp.h> 62 62 #include <linux/netfilter_ipv4.h> 63 + #include <linux/compat.h> 63 64 #include <net/ipip.h> 64 65 #include <net/checksum.h> 65 66 #include <net/netlink.h> ··· 1434 1433 return -ENOIOCTLCMD; 1435 1434 } 1436 1435 } 1436 + 1437 + #ifdef CONFIG_COMPAT 1438 + struct compat_sioc_sg_req { 1439 + struct in_addr src; 1440 + struct in_addr grp; 1441 + compat_ulong_t pktcnt; 1442 + compat_ulong_t bytecnt; 1443 + compat_ulong_t wrong_if; 1444 + }; 1445 + 1446 + int ipmr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg) 1447 + { 1448 + struct sioc_sg_req sr; 1449 + struct mfc_cache *c; 1450 + struct net *net = sock_net(sk); 1451 + struct mr_table *mrt; 1452 + 1453 + mrt = ipmr_get_table(net, raw_sk(sk)->ipmr_table ? : RT_TABLE_DEFAULT); 1454 + if (mrt == NULL) 1455 + return -ENOENT; 1456 + 1457 + switch (cmd) { 1458 + case SIOCGETSGCNT: 1459 + if (copy_from_user(&sr, arg, sizeof(sr))) 1460 + return -EFAULT; 1461 + 1462 + rcu_read_lock(); 1463 + c = ipmr_cache_find(mrt, sr.src.s_addr, sr.grp.s_addr); 1464 + if (c) { 1465 + sr.pktcnt = c->mfc_un.res.pkt; 1466 + sr.bytecnt = c->mfc_un.res.bytes; 1467 + sr.wrong_if = c->mfc_un.res.wrong_if; 1468 + rcu_read_unlock(); 1469 + 1470 + if (copy_to_user(arg, &sr, sizeof(sr))) 1471 + return -EFAULT; 1472 + return 0; 1473 + } 1474 + rcu_read_unlock(); 1475 + return -EADDRNOTAVAIL; 1476 + default: 1477 + return -ENOIOCTLCMD; 1478 + } 1479 + } 1480 + #endif 1437 1481 1438 1482 1439 1483 static int ipmr_device_event(struct notifier_block *this, unsigned long event, void *ptr)
+19
net/ipv4/raw.c
··· 76 76 #include <linux/seq_file.h> 77 77 #include <linux/netfilter.h> 78 78 #include <linux/netfilter_ipv4.h> 79 + #include <linux/compat.h> 79 80 80 81 static struct raw_hashinfo raw_v4_hashinfo = { 81 82 .lock = __RW_LOCK_UNLOCKED(raw_v4_hashinfo.lock), ··· 839 838 } 840 839 } 841 840 841 + #ifdef CONFIG_COMPAT 842 + static int compat_raw_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg) 843 + { 844 + switch (cmd) { 845 + case SIOCOUTQ: 846 + case SIOCINQ: 847 + return -ENOIOCTLCMD; 848 + default: 849 + #ifdef CONFIG_IP_MROUTE 850 + return ipmr_compat_ioctl(sk, cmd, compat_ptr(arg)); 851 + #else 852 + return -ENOIOCTLCMD; 853 + #endif 854 + } 855 + } 856 + #endif 857 + 842 858 struct proto raw_prot = { 843 859 .name = "RAW", 844 860 .owner = THIS_MODULE, ··· 878 860 #ifdef CONFIG_COMPAT 879 861 .compat_setsockopt = compat_raw_setsockopt, 880 862 .compat_getsockopt = compat_raw_getsockopt, 863 + .compat_ioctl = compat_raw_ioctl, 881 864 #endif 882 865 }; 883 866