From: Chuck Lever The kernel caps the number of session tags it accepts in a DONE downcall at HANDSHAKE_MAX_SESSIONTAGS. tlshd has no way to learn this cap today: a daemon built against newer UAPI headers than the running kernel silently overruns it, and the kernel truncates the list with one pr_warn_once per boot. Truncation is recoverable but the underlying misconfiguration is easy to miss. Carry the cap on every ACCEPT reply as HANDSHAKE_A_ACCEPT_MAX_TAGS, a u32 attribute populated by the kernel. User space reads the value at ACCEPT time and can gate its DONE-side tag list against it, turning over-cap into a user-space policy choice rather than a silent kernel-side truncation. Putting the cap in the ACCEPT reply keeps a single source of truth and lets the kernel raise it in a later release without bumping the daemon's UAPI header dependency. Signed-off-by: Chuck Lever --- Documentation/netlink/specs/handshake.yaml | 4 ++++ Documentation/networking/tls-handshake.rst | 7 +++++++ include/uapi/linux/handshake.h | 1 + net/handshake/tlshd.c | 5 +++++ 4 files changed, 17 insertions(+) diff --git a/Documentation/netlink/specs/handshake.yaml b/Documentation/netlink/specs/handshake.yaml index df36ff7da18f..614d31bee656 100644 --- a/Documentation/netlink/specs/handshake.yaml +++ b/Documentation/netlink/specs/handshake.yaml @@ -78,6 +78,9 @@ attribute-sets: - name: keyring type: u32 + - + name: max-tags + type: u32 - name: done attributes: @@ -123,6 +126,7 @@ operations: - certificate - peername - keyring + - max-tags - name: done doc: Handler reports handshake completion diff --git a/Documentation/networking/tls-handshake.rst b/Documentation/networking/tls-handshake.rst index 352842a74e6b..ea2e090a1ed8 100644 --- a/Documentation/networking/tls-handshake.rst +++ b/Documentation/networking/tls-handshake.rst @@ -273,4 +273,11 @@ empty. The handshake layer always delivers a finalized tagset to the callback, so consumers may call tagset_is_member() and tagset_intersection() unconditionally without a separate guard. +The tagset delivered to the consumer may contain fewer tags than +the handshake agent assigned. The kernel caps the per-DONE tag +count at HANDSHAKE_MAX_SESSIONTAGS, and individual tags within +the cap may be dropped under memory pressure. The cap rides on +every ACCEPT reply so the agent can size its DONE-side tag list +to it; see Documentation/netlink/specs/handshake.yaml. + See Documentation/core-api/tagset.rst for the complete tagset API. diff --git a/include/uapi/linux/handshake.h b/include/uapi/linux/handshake.h index 1ed309e475b4..1445983e7369 100644 --- a/include/uapi/linux/handshake.h +++ b/include/uapi/linux/handshake.h @@ -49,6 +49,7 @@ enum { HANDSHAKE_A_ACCEPT_CERTIFICATE, HANDSHAKE_A_ACCEPT_PEERNAME, HANDSHAKE_A_ACCEPT_KEYRING, + HANDSHAKE_A_ACCEPT_MAX_TAGS, __HANDSHAKE_A_ACCEPT_MAX, HANDSHAKE_A_ACCEPT_MAX = (__HANDSHAKE_A_ACCEPT_MAX - 1) diff --git a/net/handshake/tlshd.c b/net/handshake/tlshd.c index 9bcaeba74f8c..eae4a4a0a9ef 100644 --- a/net/handshake/tlshd.c +++ b/net/handshake/tlshd.c @@ -238,6 +238,11 @@ static int tls_handshake_accept(struct handshake_req *req, goto out_cancel; } + ret = nla_put_u32(msg, HANDSHAKE_A_ACCEPT_MAX_TAGS, + HANDSHAKE_MAX_SESSIONTAGS); + if (ret < 0) + goto out_cancel; + ret = nla_put_u32(msg, HANDSHAKE_A_ACCEPT_AUTH_MODE, treq->th_auth_mode); if (ret < 0) -- 2.54.0