From: "user.email" <suruurism@gmail.com>
To: netdev@vger.kernel.org, linux-kernel@vger.kernel.org
Cc: subash.a.kasiviswanathan@oss.qualcomm.com,
sean.tranchetti@oss.qualcomm.com, horms@kernel.org
Subject: [PATCH net v3] net: qualcomm: rmnet: require CAP_NET_ADMIN in the real device netns for config ops
Date: Sat, 29 Aug 2026 20:06:56 +0300 [thread overview]
Message-ID: <20260829170656.15548-1-suruurism@gmail.com> (raw)
From: Abdifatah Suruur <suruurism@gmail.com>
An rmnet device may be created with its real device in a different
netns than the rmnet device itself (rmnet_newlink() resolves it in
link_net), and the rtnl config paths below only check CAP_NET_ADMIN
against dev_net(dev), while mutating rmnet port state attached to the
real device:
- rmnet_changelink() rewrites the endpoint mux table and
port->data_format and, via rmnet_vnd_update_dev_mtu(), can shrink the
MTU of the rmnet endpoint netdevs.
- rmnet_add_bridge() and rmnet_del_bridge(), reachable via
ndo_add_slave/ndo_del_slave through RTM_SETLINK IFLA_MASTER, flip
port->rmnet_mode and port->bridge_ep on the real device's port; with
bridge_ep pointing at a caller-owned device, rmnet_rx_handler() then
forwards real-device ingress frames to it.
A caller privileged only in the rmnet device's netns can therefore
rewrite the shared cellular data-path state owned by another netns, and
steer its ingress traffic.
Gate all three with rtnl_dev_link_net_capable(), matching the "require
CAP_NET_ADMIN in the device netns for changelink" series (vxlan/geneve,
CVE-2026-68432).
Fixes: 2abb5792387e ("net: qualcomm: rmnet: Allow configuration updates to existing devices")
Fixes: 60d58f971c1077 ("net: qualcomm: rmnet: Implement bridge mode")
Cc: stable@vger.kernel.org
Signed-off-by: Abdifatah Suruur <suruurism@gmail.com>
---
v3:
- cover rmnet_add_bridge() and rmnet_del_bridge() with the same gate;
they mutate the same real-device port state via ndo_add_slave/
ndo_del_slave and have no capability check of their own
- correct the impact wording: rmnet_vnd_update_dev_mtu() only reads
real_dev->mtu; the MTU store lands on the rmnet endpoint netdevs via
rmnet_vnd_change_mtu(), not on the real device
v2:
- drop Reported-by: (implied for the author), per Jakub Kicinski
---
.../ethernet/qualcomm/rmnet/rmnet_config.c | 30 ++++++++++++++++++-
1 file changed, 29 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
index 78d4df55740a1..50c60e553d09f 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
@@ -312,6 +312,14 @@ static int rmnet_changelink(struct net_device *dev, struct nlattr *tb[],
if (!rmnet_is_real_dev_registered(real_dev))
return -ENODEV;
+ /*
+ * The rtnl path only checks CAP_NET_ADMIN against dev_net(dev),
+ * but the port state mutated below is attached to real_dev, which
+ * may live in a different netns.
+ */
+ if (!rtnl_dev_link_net_capable(dev, dev_net(real_dev)))
+ return -EPERM;
+
port = rmnet_get_port_rtnl(real_dev);
if (data[IFLA_RMNET_MUX_ID]) {
@@ -440,6 +448,14 @@ int rmnet_add_bridge(struct net_device *rmnet_dev,
struct rmnet_port *port, *slave_port;
int err;
+ /*
+ * The rtnl path only checks CAP_NET_ADMIN against dev_net(dev),
+ * but the port state mutated below is attached to real_dev, which
+ * may live in a different netns.
+ */
+ if (!rtnl_dev_link_net_capable(rmnet_dev, dev_net(real_dev)))
+ return -EPERM;
+
port = rmnet_get_port_rtnl(real_dev);
/* If there is more than one rmnet dev attached, its probably being
@@ -488,7 +504,19 @@ int rmnet_add_bridge(struct net_device *rmnet_dev,
int rmnet_del_bridge(struct net_device *rmnet_dev,
struct net_device *slave_dev)
{
- struct rmnet_port *port = rmnet_get_port_rtnl(slave_dev);
+ struct rmnet_priv *priv = netdev_priv(rmnet_dev);
+ struct net_device *real_dev = priv->real_dev;
+ struct rmnet_port *port;
+
+ /*
+ * The rtnl path only checks CAP_NET_ADMIN against dev_net(dev),
+ * but rmnet_unregister_bridge() below clears the bridge state of
+ * the real device's port, which may live in a different netns.
+ */
+ if (!rtnl_dev_link_net_capable(rmnet_dev, dev_net(real_dev)))
+ return -EPERM;
+
+ port = rmnet_get_port_rtnl(slave_dev);
rmnet_unregister_bridge(port);
--
2.53.0
reply other threads:[~2026-08-29 17:07 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
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=20260829170656.15548-1-suruurism@gmail.com \
--to=suruurism@gmail.com \
--cc=horms@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=sean.tranchetti@oss.qualcomm.com \
--cc=subash.a.kasiviswanathan@oss.qualcomm.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®