diff --git a/meta/recipes-support/p11-kit/files/CVE-2026-13757.patch b/meta/recipes-support/p11-kit/files/CVE-2026-13757.patch new file mode 100644 index 0000000000..2f9aa080bb --- /dev/null +++ b/meta/recipes-support/p11-kit/files/CVE-2026-13757.patch @@ -0,0 +1,265 @@ +From 0eedd4ddd7c924f9cbb4ac496b3fda699435c3cf Mon Sep 17 00:00:00 2001 +From: Zoltan Fridrich +Date: Thu, 2 Jul 2026 10:54:47 +0200 +Subject: [PATCH] rpc: add recursion depth limit into RPC attribute parsing + (CVE-2026-13757) + +A DoS was possible when client sent request to a server with deeply +nested attributes causing stack exhaustion on the server. +This patch adds a recursion limit on all server entry points to +prevent such attacks. + +Signed-off-by: Zoltan Fridrich + +Upstream-Status: Backport [import from ubuntu p11-kit_0.25.3-4ubuntu2.2.debian.tar.xz +Upstream commit https://github.com/p11-glue/p11-kit/commit/0eedd4ddd7c924f9cbb4ac496b3fda699435c3cf] +CVE: CVE-2026-13757 +Signed-off-by: Vijay Anusuri +--- + p11-kit/rpc-message.c | 39 +++++++++++++++++++++++++++++++++----- + p11-kit/rpc-message.h | 10 +++++++++- + p11-kit/test-rpc-message.c | 39 ++++++++++++++++++++++++++++++++++++-- + p11-kit/test-rpc.c | 27 ++++++++++++++++++++++++++ + 4 files changed, 107 insertions(+), 8 deletions(-) + +diff --git a/p11-kit/rpc-message.c b/p11-kit/rpc-message.c +index 09d7f33..d6f0aad 100644 +--- a/p11-kit/rpc-message.c ++++ b/p11-kit/rpc-message.c +@@ -903,6 +903,15 @@ map_attribute_to_value_type (CK_ATTRIBUTE_TYPE type) + } + } + ++static bool ++p11_rpc_buffer_get_attribute_array_value_wrapper (p11_buffer *buffer, ++ size_t *offset, ++ void *value, ++ CK_ULONG *value_length) ++{ ++ return p11_rpc_buffer_get_attribute_array_value (buffer, offset, value, value_length, 0); ++} ++ + typedef struct { + p11_rpc_value_type type; + p11_rpc_value_encoder encode; +@@ -912,7 +921,7 @@ typedef struct { + static p11_rpc_attribute_serializer p11_rpc_attribute_serializers[] = { + { P11_RPC_VALUE_BYTE, p11_rpc_buffer_add_byte_value, p11_rpc_buffer_get_byte_value }, + { P11_RPC_VALUE_ULONG, p11_rpc_buffer_add_ulong_value, p11_rpc_buffer_get_ulong_value }, +- { P11_RPC_VALUE_ATTRIBUTE_ARRAY, p11_rpc_buffer_add_attribute_array_value, p11_rpc_buffer_get_attribute_array_value }, ++ { P11_RPC_VALUE_ATTRIBUTE_ARRAY, p11_rpc_buffer_add_attribute_array_value, p11_rpc_buffer_get_attribute_array_value_wrapper }, + { P11_RPC_VALUE_MECHANISM_TYPE_ARRAY, p11_rpc_buffer_add_mechanism_type_array_value, p11_rpc_buffer_get_mechanism_type_array_value }, + { P11_RPC_VALUE_DATE, p11_rpc_buffer_add_date_value, p11_rpc_buffer_get_date_value }, + { P11_RPC_VALUE_BYTE_ARRAY, p11_rpc_buffer_add_byte_array_value, p11_rpc_buffer_get_byte_array_value } +@@ -1142,7 +1151,8 @@ bool + p11_rpc_buffer_get_attribute_array_value (p11_buffer *buffer, + size_t *offset, + void *value, +- CK_ULONG *value_length) ++ CK_ULONG *value_length, ++ size_t depth) + { + uint32_t count, i; + CK_ATTRIBUTE *attr, temp; +@@ -1157,7 +1167,7 @@ p11_rpc_buffer_get_attribute_array_value (p11_buffer *buffer, + attr = value; + + for (i = 0; i < count; i++) { +- if (!p11_rpc_buffer_get_attribute (buffer, offset, attr)) ++ if (!p11_rpc_buffer_get_attribute_recursive (buffer, offset, attr, depth)) + return false; + if (value) + attr++; +@@ -1255,12 +1265,26 @@ bool + p11_rpc_buffer_get_attribute (p11_buffer *buffer, + size_t *offset, + CK_ATTRIBUTE *attr) ++{ ++ return p11_rpc_buffer_get_attribute_recursive (buffer, offset, attr, 0); ++} ++ ++bool ++p11_rpc_buffer_get_attribute_recursive (p11_buffer *buffer, ++ size_t *offset, ++ CK_ATTRIBUTE *attr, ++ size_t depth) + { + uint32_t type, length, decode_length; + unsigned char validity; + p11_rpc_attribute_serializer *serializer; + p11_rpc_value_type value_type; + ++ if (depth > P11_RPC_MAX_RECURSION_DEPTH) { ++ p11_debug ("recursion depth limit reached"); ++ return false; ++ } ++ + /* The attribute type */ + if (!p11_rpc_buffer_get_uint32 (buffer, offset, &type)) + return false; +@@ -1284,8 +1308,13 @@ p11_rpc_buffer_get_attribute (p11_buffer *buffer, + assert (value_type < ELEMS (p11_rpc_attribute_serializers)); + serializer = &p11_rpc_attribute_serializers[value_type]; + assert (serializer != NULL); +- if (!serializer->decode (buffer, offset, attr->pValue, &attr->ulValueLen)) +- return false; ++ if (value_type == P11_RPC_VALUE_ATTRIBUTE_ARRAY) { ++ if (!p11_rpc_buffer_get_attribute_array_value (buffer, offset, attr->pValue, &attr->ulValueLen, depth + 1)) ++ return false; ++ } else { ++ if (!serializer->decode (buffer, offset, attr->pValue, &attr->ulValueLen)) ++ return false; ++ } + if (!attr->pValue) { + decode_length = attr->ulValueLen; + attr->ulValueLen = length; +diff --git a/p11-kit/rpc-message.h b/p11-kit/rpc-message.h +index f171fc4..671a60d 100644 +--- a/p11-kit/rpc-message.h ++++ b/p11-kit/rpc-message.h +@@ -44,6 +44,8 @@ + #include "pkcs11.h" + #include "pkcs11x.h" + ++#define P11_RPC_MAX_RECURSION_DEPTH 8 ++ + /* The calls, must be in sync with array below */ + enum { + P11_RPC_CALL_ERROR = 0, +@@ -441,6 +443,11 @@ bool p11_rpc_buffer_get_attribute (p11_buffer *buffer, + size_t *offset, + CK_ATTRIBUTE *attr); + ++bool p11_rpc_buffer_get_attribute_recursive (p11_buffer *buffer, ++ size_t *offset, ++ CK_ATTRIBUTE *attr, ++ size_t depth); ++ + void p11_rpc_buffer_add_byte_value (p11_buffer *buffer, + const void *value, + CK_ULONG value_length); +@@ -468,7 +475,8 @@ bool p11_rpc_buffer_get_attribute_array_value + (p11_buffer *buffer, + size_t *offset, + void *value, +- CK_ULONG *value_length); ++ CK_ULONG *value_length, ++ size_t depth); + + void p11_rpc_buffer_add_mechanism_type_array_value + (p11_buffer *buffer, +diff --git a/p11-kit/test-rpc-message.c b/p11-kit/test-rpc-message.c +index 4c11ea5..f00f2f1 100644 +--- a/p11-kit/test-rpc-message.c ++++ b/p11-kit/test-rpc-message.c +@@ -594,11 +594,11 @@ test_attribute_array_value (void) + assert (!p11_buffer_failed (&buffer)); + + offset2 = offset; +- ret = p11_rpc_buffer_get_attribute_array_value(&buffer, &offset, NULL, &val_size); ++ ret = p11_rpc_buffer_get_attribute_array_value(&buffer, &offset, NULL, &val_size, 0); + assert_num_eq (true, ret); + + offset = offset2; +- ret = p11_rpc_buffer_get_attribute_array_value(&buffer, &offset, val, &val_size); ++ ret = p11_rpc_buffer_get_attribute_array_value(&buffer, &offset, val, &val_size, 0); + assert_num_eq (true, ret); + assert_num_eq (val[0].type, CKA_MODIFIABLE); + assert_num_eq (*(CK_BBOOL *)val[0].pValue, CK_TRUE); +@@ -806,6 +806,40 @@ test_message_write (void) + p11_buffer_uninit (&buffer); + } + ++static void ++test_attribute_recursion_limit (void) ++{ ++ bool ret; ++ p11_buffer buffer; ++ size_t offset = 0; ++ CK_BBOOL truev = CK_TRUE; ++ CK_ATTRIBUTE attrs_out; ++ CK_ATTRIBUTE attrs[P11_RPC_MAX_RECURSION_DEPTH + 2]; ++ for (size_t i = 0; i <= P11_RPC_MAX_RECURSION_DEPTH; i++) { ++ attrs[i].type = CKA_WRAP_TEMPLATE; ++ attrs[i].pValue = &attrs[i + 1]; ++ attrs[i].ulValueLen = sizeof (CK_ATTRIBUTE); ++ } ++ attrs[P11_RPC_MAX_RECURSION_DEPTH + 1].type = CKA_ENCRYPT; ++ attrs[P11_RPC_MAX_RECURSION_DEPTH + 1].pValue = &truev; ++ attrs[P11_RPC_MAX_RECURSION_DEPTH + 1].ulValueLen = sizeof (CK_BBOOL); ++ ++ ret = p11_buffer_init (&buffer, 0); ++ assert_num_eq (true, ret); ++ p11_rpc_buffer_add_attribute_array_value (&buffer, attrs, ELEMS(attrs)); ++ assert_num_eq (true, !p11_buffer_failed (&buffer)); ++ ++ /* Skip the array count */ ++ ret = p11_rpc_buffer_get_uint32(&buffer, &offset, NULL); ++ assert_num_eq (true, ret); ++ ++ /* Hit recursion limit */ ++ ret = p11_rpc_buffer_get_attribute(&buffer, &offset, &attrs_out); ++ assert_num_eq (false, ret); ++ ++ p11_buffer_uninit (&buffer); ++} ++ + #include "test-mock.c" + + static CK_MECHANISM_TYPE mechanisms[] = { +@@ -848,6 +882,7 @@ main (int argc, + p11_test (test_byte_array_value, "/rpc-message/byte-array-value"); + p11_test (test_mechanism_value, "/rpc-message/mechanism-value"); + p11_test (test_message_write, "/rpc-message/message-write"); ++ p11_test (test_attribute_recursion_limit, "/rpc-message/attribute-recursion-limit"); + + test_mock_add_tests ("/rpc-message", NULL); + +diff --git a/p11-kit/test-rpc.c b/p11-kit/test-rpc.c +index f214509..6059b89 100644 +--- a/p11-kit/test-rpc.c ++++ b/p11-kit/test-rpc.c +@@ -700,6 +700,32 @@ test_mechanism_unsupported (void *module) + teardown_mock_module (rpc_module); + } + ++static void ++test_recursion_limit (void *module) ++{ ++ CK_FUNCTION_LIST_PTR rpc_module; ++ CK_SESSION_HANDLE session; ++ CK_RV rv; ++ CK_BBOOL val; ++ CK_ATTRIBUTE attrs[P11_RPC_MAX_RECURSION_DEPTH + 2]; ++ for (size_t i = 0; i <= P11_RPC_MAX_RECURSION_DEPTH; i++) { ++ attrs[i].type = CKA_WRAP_TEMPLATE; ++ attrs[i].pValue = &attrs[i + 1]; ++ attrs[i].ulValueLen = sizeof (CK_ATTRIBUTE); ++ } ++ attrs[P11_RPC_MAX_RECURSION_DEPTH + 1].type = CKA_ENCRYPT; ++ attrs[P11_RPC_MAX_RECURSION_DEPTH + 1].pValue = &val; ++ attrs[P11_RPC_MAX_RECURSION_DEPTH + 1].ulValueLen = sizeof (CK_BBOOL); ++ ++ rpc_module = setup_test_rpc_module (&test_normal_vtable, module, &session); ++ ++ /* Hit recursion limit */ ++ rv = (rpc_module->C_GetAttributeValue) (session, MOCK_PUBLIC_KEY_PREFIX, attrs, 1); ++ assert_num_eq (rv, CKR_DEVICE_ERROR); ++ ++ teardown_mock_module (rpc_module); ++} ++ + #ifdef OS_UNIX + + static void +@@ -805,6 +831,7 @@ main (int argc, + p11_testx (test_get_slot_list_no_device, &mock_module_v3_no_slots, "/rpc3/get-slot-list-no-device"); + p11_testx (test_simultaneous_functions, &mock_module_v3_no_slots, "/rpc3/simultaneous-functions"); + p11_testx (test_mechanism_unsupported, &mock_module_v3, "/rpc3/mechanism-unsupported"); ++ p11_testx (test_recursion_limit, &mock_module_v3, "/rpc3/recursion-limit"); + + #ifdef OS_UNIX + p11_testx (test_fork_and_reinitialize, &mock_module_v3_no_slots, "/rpc3/fork-and-reinitialize"); +-- +2.43.0 + diff --git a/meta/recipes-support/p11-kit/p11-kit_0.25.3.bb b/meta/recipes-support/p11-kit/p11-kit_0.25.3.bb index 5921a46c88..6c5b82e6bc 100644 --- a/meta/recipes-support/p11-kit/p11-kit_0.25.3.bb +++ b/meta/recipes-support/p11-kit/p11-kit_0.25.3.bb @@ -12,6 +12,7 @@ DEPENDS:append = "${@' glib-2.0' if d.getVar('GTKDOC_ENABLED') == 'True' else '' SRC_URI = "gitsm://github.com/p11-glue/p11-kit;branch=master;protocol=https \ file://fix-parallel-build-failures.patch \ + file://CVE-2026-13757.patch \ " SRCREV = "917e02a3211dabbdea4b079cb598581dce84fda1" S = "${WORKDIR}/git"