From: Christoph Böhmwalder Date: Fri, 14 Aug 2026 15:16:17 +0000 (+0200) Subject: drbd: don't leak the shared secret to unprivileged netlink dumps X-Git-Tag: v7.2~8^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c71bf113dfdf426bdaf106636f573ef87b6613a0;p=thirdparty%2Fkernel%2Flinux.git drbd: don't leak the shared secret to unprivileged netlink dumps 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 Signed-off-by: Christoph Böhmwalder Link: https://patch.msgid.link/20260814151617.73752-1-christoph.boehmwalder@linbit.com Signed-off-by: Jens Axboe --- diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index f9ffcd67607b..b77f901fc3ef 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -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;