]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
drbd: don't leak the shared secret to unprivileged netlink dumps
authorChristoph Böhmwalder <christoph.boehmwalder@linbit.com>
Fri, 14 Aug 2026 15:16:17 +0000 (17:16 +0200)
committerJens Axboe <axboe@kernel.dk>
Sun, 16 Aug 2026 02:00:10 +0000 (20:00 -0600)
The conversion to explicit netlink serialization dropped the
exclude_sensitive parameter from net_conf_to_skb(), so each caller has
to sanitize by hand. Two dump paths were missed:
drbd_nl_get_connections_dumpit() and the volume-less connection branch
of get_one_status(). Neither op carries GENL_ADMIN_PERM, so any
unprivileged local user could read the CRAM-HMAC secret.

Add a net_conf_to_skb_sanitized() wrapper and route all three callers
through it.

Fixes: 8098eeb693c4 ("drbd: replace genl_magic with explicit netlink serialization")
Reported-by: Vivek Parikh <vivek.parikh@breachx.ai>
Signed-off-by: Christoph Böhmwalder <christoph.boehmwalder@linbit.com>
Link: https://patch.msgid.link/20260814151617.73752-1-christoph.boehmwalder@linbit.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
drivers/block/drbd/drbd_nl.c

index f9ffcd67607b55062bd7630802ff060bf7e119dd..b77f901fc3ef49e11199ad8e68c3ff36cb437754 100644 (file)
@@ -3306,6 +3306,26 @@ nla_put_failure:
        return -EMSGSIZE;
 }
 
+/*
+ * net_conf_to_skb() serializes the shared secret verbatim. Any path that can
+ * answer a request from an unprivileged process must pass exclude_sensitive,
+ * so the secret is blanked in a private copy before it reaches the skb.
+ */
+static int net_conf_to_skb_sanitized(struct sk_buff *skb, struct net_conf *nc,
+                                    bool exclude_sensitive)
+{
+       struct net_conf nc_clean;
+
+       if (!exclude_sensitive)
+               return net_conf_to_skb(skb, nc);
+
+       nc_clean = *nc;
+       memset(nc_clean.shared_secret, 0, sizeof(nc_clean.shared_secret));
+       nc_clean.shared_secret_len = 0;
+
+       return net_conf_to_skb(skb, &nc_clean);
+}
+
 /*
  * The generic netlink dump callbacks are called outside the genl_lock(), so
  * they cannot use the simple attribute parsing code which uses global
@@ -3621,7 +3641,8 @@ put_result:
                        goto out;
                net_conf = rcu_dereference(connection->net_conf);
                if (net_conf) {
-                       err = net_conf_to_skb(skb, net_conf);
+                       err = net_conf_to_skb_sanitized(skb, net_conf,
+                                                       !capable(CAP_SYS_ADMIN));
                        if (err)
                                goto out;
                }
@@ -3842,18 +3863,8 @@ static int nla_put_status_info(struct sk_buff *skb, struct drbd_device *device,
                struct net_conf *nc;
 
                nc = rcu_dereference(first_peer_device(device)->connection->net_conf);
-               if (nc) {
-                       if (exclude_sensitive) {
-                               struct net_conf nc_clean = *nc;
-
-                               memset(nc_clean.shared_secret, 0,
-                                      sizeof(nc_clean.shared_secret));
-                               nc_clean.shared_secret_len = 0;
-                               err = net_conf_to_skb(skb, &nc_clean);
-                       } else {
-                               err = net_conf_to_skb(skb, nc);
-                       }
-               }
+               if (nc)
+                       err = net_conf_to_skb_sanitized(skb, nc, exclude_sensitive);
        }
        rcu_read_unlock();
        if (err)
@@ -4058,7 +4069,7 @@ next_resource:
                                struct net_conf *nc;
 
                                nc = rcu_dereference(connection->net_conf);
-                               if (nc && net_conf_to_skb(skb, nc) != 0)
+                               if (nc && net_conf_to_skb_sanitized(skb, nc, true) != 0)
                                        goto cancel;
                        }
                        goto done;