From: Maoyi Xie <maoyixie.tju@gmail.com>
To: "David S . Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>
Cc: David Ahern <dsahern@kernel.org>,
Kuniyuki Iwashima <kuniyu@google.com>,
Xiao Liang <shaw.leon@gmail.com>,
Steffen Klassert <steffen.klassert@secunet.com>,
Herbert Xu <herbert@gondor.apana.org.au>,
Simon Horman <horms@kernel.org>,
netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
stable@vger.kernel.org
Subject: [PATCH net v4 1/7] net: ip_gre: require CAP_NET_ADMIN in the device netns for changelink
Date: Wed, 10 Jun 2026 00:31:04 +0800 [thread overview]
Message-ID: <20260609163110.1717419-2-maoyixie.tju@gmail.com> (raw)
In-Reply-To: <20260609163110.1717419-1-maoyixie.tju@gmail.com>
A tunnel changelink rewrites the tunnel in its creation netns. After an
IFLA_NET_NS_FD migration that netns is not the caller's. The rtnl
changelink path only checks CAP_NET_ADMIN against the caller's netns. A
caller with caps only in its current netns can then rewrite a tunnel
that lives in another netns, and it picks the endpoint addresses.
Add net_admin_capable(). It requires CAP_NET_ADMIN in the tunnel's netns
and is skipped when that netns is the device's current netns, where the
rtnl path already checked the cap. The other patches in this series use
the same helper.
Gate ipgre_changelink() and erspan_changelink() with it. The check is at
the top of the op, before any attribute is parsed, because the parsers
update live tunnel fields first. ipgre_netlink_parms() sets
t->collect_md before ip_tunnel_changelink() runs.
Commit 8b484efd5cb4 ("ip6: vti: Use ip6_tnl.net in
vti6_siocdevprivate().") added the same check on the ioctl path. This
adds it on RTM_NEWLINK.
Reported-by: Xiao Liang <shaw.leon@gmail.com>
Closes: https://lore.kernel.org/netdev/CABAhCOSzP1vaThGV35_VnsRCb=87_CPjPVsTHbq905k8A+BuUg@mail.gmail.com/
Fixes: d0f418516022 ("net, ip_tunnel: fix namespaces move")
Cc: stable@vger.kernel.org
Signed-off-by: Maoyi Xie <maoyixie.tju@gmail.com>
---
include/net/net_namespace.h | 18 ++++++++++++++++++
net/ipv4/ip_gre.c | 6 ++++++
2 files changed, 24 insertions(+)
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index 80de5e98a66d..17fb71a78cb6 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -358,6 +358,24 @@ static inline bool net_initialized(const struct net *net)
return READ_ONCE(net->list.next);
}
+/**
+ * net_admin_capable - test for CAP_NET_ADMIN over a network namespace
+ * @net: namespace whose state the operation would change
+ * @cur: namespace the operation runs in, e.g. dev_net(dev)
+ *
+ * Returns true when @net is @cur, where CAP_NET_ADMIN was already
+ * checked for the running namespace, or when the caller holds
+ * CAP_NET_ADMIN over @net. rtnl changelink paths use this: a device can
+ * be moved so its state lives in a namespace other than the one the
+ * request runs in, and the cap must then be held over that namespace.
+ */
+static inline bool net_admin_capable(const struct net *net,
+ const struct net *cur)
+{
+ return net_eq(net, cur) ||
+ ns_capable(net->user_ns, CAP_NET_ADMIN);
+}
+
static inline void __netns_tracker_alloc(struct net *net,
netns_tracker *tracker,
bool refcounted,
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 169e2921a851..040a0ef95184 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -1457,6 +1457,9 @@ static int ipgre_changelink(struct net_device *dev, struct nlattr *tb[],
__u32 fwmark = t->fwmark;
int err;
+ if (!net_admin_capable(t->net, dev_net(dev)))
+ return -EPERM;
+
err = ipgre_newlink_encap_setup(dev, data);
if (err)
return err;
@@ -1486,6 +1489,9 @@ static int erspan_changelink(struct net_device *dev, struct nlattr *tb[],
__u32 fwmark = t->fwmark;
int err;
+ if (!net_admin_capable(t->net, dev_net(dev)))
+ return -EPERM;
+
err = ipgre_newlink_encap_setup(dev, data);
if (err)
return err;
--
2.34.1
next prev parent reply other threads:[~2026-06-09 16:31 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-09 16:31 [PATCH net v4 0/7] net: require CAP_NET_ADMIN in the device netns for tunnel changelink Maoyi Xie
2026-06-09 16:31 ` Maoyi Xie [this message]
2026-06-11 5:25 ` [PATCH net v4 1/7] net: ip_gre: require CAP_NET_ADMIN in the device netns for changelink Kuniyuki Iwashima
2026-06-09 16:31 ` [PATCH net v4 2/7] net: ipip: " Maoyi Xie
2026-06-09 16:31 ` [PATCH net v4 3/7] net: ip_vti: " Maoyi Xie
2026-06-09 16:31 ` [PATCH net v4 4/7] net: ip6_tunnel: " Maoyi Xie
2026-06-09 16:31 ` [PATCH net v4 5/7] net: ip6_gre: " Maoyi Xie
2026-06-09 16:31 ` [PATCH net v4 6/7] net: ip6_vti: " Maoyi Xie
2026-06-09 16:31 ` [PATCH net v4 7/7] xfrm: xfrm_interface: " Maoyi Xie
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260609163110.1717419-2-maoyixie.tju@gmail.com \
--to=maoyixie.tju@gmail.com \
--cc=davem@davemloft.net \
--cc=dsahern@kernel.org \
--cc=edumazet@google.com \
--cc=herbert@gondor.apana.org.au \
--cc=horms@kernel.org \
--cc=kuba@kernel.org \
--cc=kuniyu@google.com \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=shaw.leon@gmail.com \
--cc=stable@vger.kernel.org \
--cc=steffen.klassert@secunet.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®