From daa52e37851a5a1b5890e7a250a27e94a8b9f273 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 12 Jul 2026 15:31:22 -0400 Subject: [PATCH] xdrgen: Fix opaque and string encoders for unbounded members The variable-length opaque and string encoder templates emit an unconditional bound check, "if (value->NAME.len > MAXSIZE) return false". XDR represents an unbounded specifier (opaque foo<>, string foo<>) as a maxsize of 0, so for an unbounded member the check degenerates to "len > 0" and the generated encoder refuses every non-empty value. The decoder does not share this defect. It delegates to xdrgen_decode_opaque() and xdrgen_decode_string(), which treat a maxlen of 0 as unbounded and skip the length check. The sibling variable-length array templates already guard their bound check with maxsize != "0". Guard the bound check the same way in each affected template -- the struct and pointer forms of both the opaque and string encoders -- so an unbounded member encodes a payload of any length while a bounded member keeps its limit. An explicit zero-length bound (foo<0>) parses to the same maxsize of 0 and so also skips the check; xdrgen does not distinguish it from the unbounded form, matching the decoder and the array encoders. Fixes: 4b132aacb076 ("tools: Add xdrgen") Link: https://patch.msgid.link/20260712193122.116845-6-cel@kernel.org Signed-off-by: Chuck Lever --- tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/string.j2 | 2 ++ .../templates/C/pointer/encoder/variable_length_opaque.j2 | 2 ++ tools/net/sunrpc/xdrgen/templates/C/struct/encoder/string.j2 | 2 ++ .../xdrgen/templates/C/struct/encoder/variable_length_opaque.j2 | 2 ++ 4 files changed, 8 insertions(+) diff --git a/tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/string.j2 b/tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/string.j2 index cf65b71eaef3..7ddc2bf3edac 100644 --- a/tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/string.j2 +++ b/tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/string.j2 @@ -2,7 +2,9 @@ {% if annotate %} /* member {{ name }} (variable-length string) */ {% endif %} +{% if maxsize != "0" %} if (value->{{ name }}.len > {{ maxsize }}) return false; +{% endif %} if (xdr_stream_encode_opaque(xdr, value->{{ name }}.data, value->{{ name }}.len) < 0) return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/variable_length_opaque.j2 b/tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/variable_length_opaque.j2 index 1d477c2d197a..5bf00070ae95 100644 --- a/tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/variable_length_opaque.j2 +++ b/tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/variable_length_opaque.j2 @@ -2,7 +2,9 @@ {% if annotate %} /* member {{ name }} (variable-length opaque) */ {% endif %} +{% if maxsize != "0" %} if (value->{{ name }}.len > {{ maxsize }}) return false; +{% endif %} if (xdr_stream_encode_opaque(xdr, value->{{ name }}.data, value->{{ name }}.len) < 0) return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/string.j2 b/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/string.j2 index cf65b71eaef3..7ddc2bf3edac 100644 --- a/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/string.j2 +++ b/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/string.j2 @@ -2,7 +2,9 @@ {% if annotate %} /* member {{ name }} (variable-length string) */ {% endif %} +{% if maxsize != "0" %} if (value->{{ name }}.len > {{ maxsize }}) return false; +{% endif %} if (xdr_stream_encode_opaque(xdr, value->{{ name }}.data, value->{{ name }}.len) < 0) return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/variable_length_opaque.j2 b/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/variable_length_opaque.j2 index 1d477c2d197a..5bf00070ae95 100644 --- a/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/variable_length_opaque.j2 +++ b/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/variable_length_opaque.j2 @@ -2,7 +2,9 @@ {% if annotate %} /* member {{ name }} (variable-length opaque) */ {% endif %} +{% if maxsize != "0" %} if (value->{{ name }}.len > {{ maxsize }}) return false; +{% endif %} if (xdr_stream_encode_opaque(xdr, value->{{ name }}.data, value->{{ name }}.len) < 0) return false;