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/[email protected]
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