[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20260123071635.16976-1-suchitkarunakaran@gmail.com>
Date: Fri, 23 Jan 2026 12:46:35 +0530
From: Suchit Karunakaran <suchitkarunakaran@...il.com>
To: davem@...emloft.net,
dsahern@...nel.org,
edumazet@...gle.com,
kuba@...nel.org,
pabeni@...hat.com
Cc: horms@...nel.org,
netdev@...r.kernel.org,
linux-kernel@...r.kernel.org,
Suchit Karunakaran <suchitkarunakaran@...il.com>
Subject: [PATCH] ipv4: ipmr: add socket type checks to ipmr_ioctl()
This is the IPv4 counterpart to commit ("ipv6: ip6mr: add socket type
checks to ip6mr_ioctl()") [1].
Similar to the IPv6 issue, ipmr_ioctl() and ipmr_compat_ioctl() access
raw_sk(sk)->ipmr_table without first verifying that the socket is a raw
socket with IPPROTO_IGMP protocol.
This allows a permission bypass where a user with CAP_NET_RAW can create
a non-IGMP raw socket (e.g., IPPROTO_UDP, IPPROTO_TCP, or any other
protocol) and use SIOCGETVIFCNT or SIOCGETSGCNT ioctls to query IPv4
multicast routing statistics. This bypasses the access control that
restricts mroute operations to IGMP sockets only.
Add socket type and protocol checks at the beginning of both
ipmr_ioctl() and ipmr_compat_ioctl() to ensure only IGMP raw sockets
can access multicast routing ioctls.
Signed-off-by: Suchit Karunakaran <suchitkarunakaran@...il.com>
[1] https://lore.kernel.org/all/20260123011444.2044-2-qikeyu2017@gmail.com/
---
net/ipv4/ipmr.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index ca9eaee4c2ef..eae03a1b8f66 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -1643,6 +1643,10 @@ int ipmr_ioctl(struct sock *sk, int cmd, void *arg)
struct sioc_sg_req *sr;
struct mr_table *mrt;
+ if (sk->sk_type != SOCK_RAW ||
+ inet_sk(sk)->inet_num != IPPROTO_IGMP)
+ return -EOPNOTSUPP;
+
mrt = ipmr_get_table(net, raw_sk(sk)->ipmr_table ? : RT_TABLE_DEFAULT);
if (!mrt)
return -ENOENT;
@@ -1711,6 +1715,10 @@ int ipmr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg)
struct net *net = sock_net(sk);
struct mr_table *mrt;
+ if (sk->sk_type != SOCK_RAW ||
+ inet_sk(sk)->inet_num != IPPROTO_IGMP)
+ return -EOPNOTSUPP;
+
mrt = ipmr_get_table(net, raw_sk(sk)->ipmr_table ? : RT_TABLE_DEFAULT);
if (!mrt)
return -ENOENT;
--
2.52.0
Powered by blists - more mailing lists