From: Michael Bommarito <michael.bommarito@gmail.com>
To: Alexander Aring <alex.aring@gmail.com>,
Stefan Schmidt <stefan@datenfreihafen.org>,
Miquel Raynal <miquel.raynal@bootlin.com>
Cc: "David S . Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
Simon Horman <horms@kernel.org>,
Phoebe Buckheister <phoebe.buckheister@itwm.fraunhofer.de>,
linux-wpan@vger.kernel.org, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: [PATCH net 0/2] ieee802154: admin-gate legacy LLSEC dumps + un-deaden ADD/DEL
Date: Wed, 20 May 2026 10:16:38 -0400 [thread overview]
Message-ID: <20260520141640.1149513-1-michael.bommarito@gmail.com> (raw)
The legacy IEEE802154_NL family (net/ieee802154/netlink.c) builds its
ops table from two macros in net/ieee802154/ieee802154.h. IEEE802154_OP()
sets .flags = GENL_ADMIN_PERM; IEEE802154_DUMP() sets no flags. Among
the IEEE802154_DUMP() consumers are four LLSEC dump ops (LIST_KEY,
LIST_DEV, LIST_DEVKEY, LIST_SECLEVEL), and the LLSEC_LIST_KEY dump
handler at net/ieee802154/nl-mac.c emits the raw 16-byte AES-128
keytable bytes (IEEE802154_ATTR_LLSEC_KEY_BYTES, .len = 16, copied
verbatim from struct ieee802154_llsec_key.key) into the reply skb.
The modern nl802154 family admin-gates the equivalent reads
(NL802154_CMD_GET_SEC_KEY at net/ieee802154/nl802154.c:2978 with
.flags = GENL_ADMIN_PERM) so the legacy interface is the open side.
Any local uid with no capabilities can dump the AES-128 LLSEC keytable
of any wpan netdev that has an administrator-installed key. 802.15.4
LLSEC uses CCM*, so the same key authenticates and encrypts frames at
the chosen security level. One key leak compromises confidentiality
and authenticity at the link layer.
Patches:
1/2 ieee802154: admin-gate legacy LLSEC dump operations
Introduce IEEE802154_DUMP_PRIV() mirroring IEEE802154_DUMP() but
with .flags = GENL_ADMIN_PERM. Switch the four LLSEC dump ops to
it. LIST_PHY and LIST_IFACE keep IEEE802154_DUMP() because the
modern nl802154 family exposes their equivalents to unprivileged
readers by design.
2/2 ieee802154: allow legacy LLSEC ADD/DEL ops to pass strict validation
While reproducing the dump leak the LLSEC ADD/DEL doit handlers
turned out to have been silently dead since strict netlink
validation became the default: IEEE802154_ATTR_LLSEC_KEY_BYTES
and _KEY_USAGE_COMMANDS are declared as NLA_UNSPEC in
nl_policy.c, which validate_nla() rejects under
NL_VALIDATE_STRICT. Add IEEE802154_OP_RELAXED() with
.validate = GENL_DONT_VALIDATE_STRICT and switch the eight LLSEC
mutate ops to it. The dump ops keep strict validation; their
gate from patch 1/2 stands.
This would be a good time to revisit this thread from Alexander Aring:
https://lore.kernel.org/r/20160725121450.4093-4-aar@pengutronix.de
Ten years later the legacy interface is still in mainline and
(per patch 2/2) silently dead on the doit side anyway. Maintainers
who prefer to revive that deletion series should NACK patch 2/2 and
pick patch 1/2 alone; patch 1/2 plugs the key leak whether the
legacy doit path is ever brought back to life or removed entirely.
Reproduction
============
Tree: mainline 7.1-rc2 (22be7671cc3497f68d14555285c0ac221597c8eb),
x86 UML, KASAN off. Conditions: CONFIG_IEEE802154=y, CONFIG_MAC802154=y,
CONFIG_IEEE802154_HWSIM=y; one wpan netdev exists; an administrator
has installed an LLSEC key on it.
Harness: a userspace C program opens AF_NETLINK / NETLINK_GENERIC,
resolves the "802.15.4 MAC" family, and issues a CTRL_CMD_GETFAMILY
followed by a IEEE802154_LLSEC_LIST_KEY dump on wpan0. The dump
response is parsed for IEEE802154_ATTR_LLSEC_KEY_BYTES nested
attributes and the 16-byte payload is hex-printed. The runner drops
privileges to uid=1000 via setpriv with --bounding-set=-all and
--inh-caps=-all before invoking the dump.
For patch 2/2, the same harness shape sends a IEEE802154_LLSEC_ADD_KEY
request with policy-conformant attributes (frame counter, key ID
mode, key bytes, usage frame types) as root. The harness measures
whether the doit handler is reached (ieee802154_llsec_add_key()
return code visible via the netlink ack) or the dispatcher rejects
the request at the validate phase.
Stock vs patched outcomes (per patch):
1/2: stock dump returns the installed AES-128 key bytes
byte-identical to the unprivileged dumper; patched returns
-EPERM at the generic-netlink dispatch.
2/2: stock LLSEC_ADD_KEY as root returns "Unsupported attribute"
from __nla_validate_parse(); patched reaches
ieee802154_llsec_add_key() and installs the key.
Regression-adjacent runs (per patch):
1/2: LIST_PHY and LIST_IFACE dumps continue to succeed from an
unprivileged uid post-patch, mirroring the modern
NL802154_CMD_GET_WPAN_PHY and NL802154_CMD_GET_INTERFACE
behavior.
2/2: modern nl802154 NL802154_CMD_NEW_SEC_KEY (which is admin-
gated and uses NLA_NESTED policy entries, not NLA_UNSPEC)
continues to install keys unchanged.
Mitigations: a system administrator unwilling to ship patch 1/2
can mitigate the leak by building the kernel without
CONFIG_IEEE802154 or by ensuring no LLSEC key is installed on
any wpan netdev. There is no per-process mitigation.
Selftest gate: tools/testing/selftests/ has no matching binary
for the legacy IEEE802154_NL interface.
The trigger harness sources are available off-list on request.
Scope notes:
- The dump handler reuses the same struct ieee802154_llsec_key
storage as the modern nl802154 NEW_SEC_KEY path. Both interfaces
expose the same backing keytable; gating only the legacy dump is
the minimal fix.
- The two new macros sit alongside the existing two; no existing
callers change beyond the four LIST_LLSEC* lines (patch 1/2)
and the eight LLSEC ADD/DEL lines (patch 2/2).
Michael Bommarito (2):
ieee802154: admin-gate legacy LLSEC dump operations
ieee802154: allow legacy LLSEC ADD/DEL ops to pass strict validation
net/ieee802154/ieee802154.h | 17 +++++++++++++++++
net/ieee802154/netlink.c | 36 ++++++++++++++++++------------------
2 files changed, 35 insertions(+), 18 deletions(-)
base-commit: 22be7671cc3497f68d14555285c0ac221597c8eb
--
2.53.0
next reply other threads:[~2026-05-20 14:16 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-20 14:16 Michael Bommarito [this message]
2026-05-20 14:16 ` [PATCH net 1/2] ieee802154: admin-gate legacy LLSEC dump operations Michael Bommarito
2026-05-20 14:16 ` [PATCH net 2/2] ieee802154: allow legacy LLSEC ADD/DEL ops to pass strict validation Michael Bommarito
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=20260520141640.1149513-1-michael.bommarito@gmail.com \
--to=michael.bommarito@gmail.com \
--cc=alex.aring@gmail.com \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=horms@kernel.org \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-wpan@vger.kernel.org \
--cc=miquel.raynal@bootlin.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=phoebe.buckheister@itwm.fraunhofer.de \
--cc=stefan@datenfreihafen.org \
/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