Version in base suite: 3.8.9-3 Base version: gnutls28_3.8.9-3 Target version: gnutls28_3.8.9-3+deb13u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/g/gnutls28/gnutls28_3.8.9-3.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/g/gnutls28/gnutls28_3.8.9-3+deb13u1.dsc changelog | 7 patches/48_0001-pkcs11-try-to-initialize-modules-in-thread-safe-mode.patch | 677 ++++++++++ patches/48_0002-pkcs11-avoid-stack-overwrite-when-initializing-a-tok.patch | 261 +++ patches/series | 2 4 files changed, 947 insertions(+) diff -Nru gnutls28-3.8.9/debian/changelog gnutls28-3.8.9/debian/changelog --- gnutls28-3.8.9/debian/changelog 2025-07-09 10:34:38.000000000 +0000 +++ gnutls28-3.8.9/debian/changelog 2025-11-23 13:13:38.000000000 +0000 @@ -1,3 +1,10 @@ +gnutls28 (3.8.9-3+deb13u1) trixie; urgency=medium + + * Add patch for CVE-2025-9820 / GNUTLS-SA-2025-11-18 from 3.8.11. + Closes: #1121146 + + -- Andreas Metzler Sun, 23 Nov 2025 14:13:38 +0100 + gnutls28 (3.8.9-3) unstable; urgency=medium * Cherry-pick fixes from 3.8.10 release: diff -Nru gnutls28-3.8.9/debian/patches/48_0001-pkcs11-try-to-initialize-modules-in-thread-safe-mode.patch gnutls28-3.8.9/debian/patches/48_0001-pkcs11-try-to-initialize-modules-in-thread-safe-mode.patch --- gnutls28-3.8.9/debian/patches/48_0001-pkcs11-try-to-initialize-modules-in-thread-safe-mode.patch 1970-01-01 00:00:00.000000000 +0000 +++ gnutls28-3.8.9/debian/patches/48_0001-pkcs11-try-to-initialize-modules-in-thread-safe-mode.patch 2025-11-23 13:13:38.000000000 +0000 @@ -0,0 +1,677 @@ +From aa5f15a872e62e54abe58624ee393e68d1faf689 Mon Sep 17 00:00:00 2001 +From: Daiki Ueno +Date: Tue, 2 Sep 2025 06:53:34 +0900 +Subject: [PATCH] pkcs11: try to initialize modules in thread-safe mode + +When modules are initialized without CKF_OS_LOCKING_OK nor custom +locking functions, they may skip their internal locking assuming that +the applications will take care of thread-safety, which is costly and +GnuTLS currently doesn't do that. + +To mitigate this, this patch changes the module initialization code to +tell the modules to guarantee thread-safety by themselves. If they are +unable to do that, this falls back to the normal initialization +without C_Initialize parameters. This also omits the custom_init flag, +which indicated whether the module is initialized with +p11_kit_module_initialize or a direct call to C_Initialize, now that +modules are always initialized with C_Initialize. + +Signed-off-by: Daiki Ueno +--- + .gitignore | 2 + + lib/pkcs11.c | 186 ++++++++++++++++++++++++----------- + tests/Makefile.am | 10 +- + tests/pkcs11/os-locking-ok.c | 165 +++++++++++++++++++++++++++++++ + tests/pkcs11/pkcs11-mock4.c | 115 ++++++++++++++++++++++ + 5 files changed, 419 insertions(+), 59 deletions(-) + create mode 100644 tests/pkcs11/os-locking-ok.c + create mode 100644 tests/pkcs11/pkcs11-mock4.c + +--- a/lib/pkcs11.c ++++ b/lib/pkcs11.c +@@ -61,14 +61,14 @@ + GNUTLS_STATIC_MUTEX(pkcs11_mutex); + + struct gnutls_pkcs11_provider_st { + struct ck_function_list *module; + unsigned active; +- unsigned custom_init; + unsigned trusted; /* in the sense of p11-kit trusted: + * it can be used for verification */ + struct ck_info info; ++ struct ck_c_initialize_args init_args; + }; + + struct find_flags_data_st { + struct p11_kit_uri *info; + unsigned int slot_flags; /* Slot Information Flags */ +@@ -244,46 +244,127 @@ static int scan_slots(struct gnutls_pkcs + return pkcs11_rv_to_err(rv); + } + return 0; + } + +-static int pkcs11_add_module(const char *name, struct ck_function_list *module, +- unsigned custom_init, const char *params) ++static const struct ck_c_initialize_args default_init_args = { ++ NULL, ++ NULL, ++ NULL, ++ NULL, ++ CKF_LIBRARY_CANT_CREATE_OS_THREADS | CKF_OS_LOCKING_OK, ++ NULL, ++}; ++ ++static const struct ck_c_initialize_args no_thread_init_args = { ++ NULL, NULL, NULL, NULL, CKF_LIBRARY_CANT_CREATE_OS_THREADS, NULL, ++}; ++ ++static void pkcs11_provider_deinit(struct gnutls_pkcs11_provider_st *provider) ++{ ++ p11_kit_module_finalize(provider->module); ++ p11_kit_module_release(provider->module); ++ gnutls_free(provider->init_args.reserved); ++} ++ ++static int pkcs11_provider_init(struct gnutls_pkcs11_provider_st *provider, ++ struct ck_function_list *module, ++ const void *params) ++{ ++ struct ck_c_initialize_args args; ++ const void *reserved = NULL; ++ ck_rv_t rv; ++ char *name; ++ char *p; ++ ++ name = p11_kit_module_get_name(module); ++ ++ _gnutls_debug_log("p11: Initializing module: %s\n", name); ++ ++ if (params && (p = strstr(params, "p11-kit:")) != 0) { ++ reserved = (char *)(p + sizeof("p11-kit:") - 1); ++ } ++ ++ /* First try with CKF_OS_LOCKING_OK, then fall back without it */ ++ args = default_init_args; ++ args.reserved = (void *)reserved; ++ rv = module->C_Initialize(&args); ++ ++ if (rv == CKR_CANT_LOCK) { ++ args = no_thread_init_args; ++ args.reserved = (void *)reserved; ++ rv = module->C_Initialize(&args); ++ } ++ ++ if (rv != CKR_OK) { ++ int ret; ++ ++ gnutls_assert(); ++ free(name); ++ ret = pkcs11_rv_to_err(rv); ++ assert(ret < 0); ++ return ret; ++ } ++ ++ if (args.flags & CKF_OS_LOCKING_OK) { ++ _gnutls_debug_log( ++ "p11: Module %s is initialized in a thread-safe mode\n", ++ name); ++ } else { ++ _gnutls_debug_log( ++ "p11: Module %s is initialized NOT in a thread-safe mode\n", ++ name); ++ } ++ free(name); ++ ++ if (args.reserved) { ++ args.reserved = gnutls_strdup((const char *)args.reserved); ++ if (!args.reserved) ++ return GNUTLS_E_MEMORY_ERROR; ++ } ++ ++ memset(provider, 0, sizeof(*provider)); ++ provider->module = module; ++ provider->init_args = args; ++ if (p11_kit_module_get_flags(module) & P11_KIT_MODULE_TRUSTED || ++ (params != NULL && strstr(params, "trusted") != 0)) ++ provider->trusted = 1; ++ ++ return 0; ++} ++ ++static int pkcs11_provider_add(const struct gnutls_pkcs11_provider_st *provider) + { + unsigned int i; + struct ck_info info; + + if (active_providers >= MAX_PROVIDERS) { + gnutls_assert(); + return GNUTLS_E_CONSTRAINT_ERROR; + } + + memset(&info, 0, sizeof(info)); +- pkcs11_get_module_info(module, &info); ++ pkcs11_get_module_info(provider->module, &info); + + /* initially check if this module is a duplicate */ + for (i = 0; i < active_providers; i++) { + /* already loaded, skip the rest */ +- if (module == providers[i].module || ++ if (provider->module == providers[i].module || + memcmp(&info, &providers[i].info, sizeof(info)) == 0) { ++ char *name = p11_kit_module_get_name(provider->module); + _gnutls_debug_log("p11: module %s is already loaded.\n", + name); ++ free(name); + return GNUTLS_E_INT_RET_0; + } + } + +- active_providers++; +- providers[active_providers - 1].module = module; +- providers[active_providers - 1].active = 1; +- providers[active_providers - 1].trusted = 0; +- providers[active_providers - 1].custom_init = custom_init; +- +- if (p11_kit_module_get_flags(module) & P11_KIT_MODULE_TRUSTED || +- (params != NULL && strstr(params, "trusted") != 0)) +- providers[active_providers - 1].trusted = 1; ++ memcpy(&providers[active_providers], provider, sizeof(*provider)); ++ memcpy(&providers[active_providers].info, &info, sizeof(info)); ++ providers[active_providers].active = 1; + +- memcpy(&providers[active_providers - 1].info, &info, sizeof(info)); ++ active_providers++; + + return 0; + } + + /* Returns: +@@ -399,55 +480,37 @@ cleanup: + * Since: 2.12.0 + **/ + int gnutls_pkcs11_add_provider(const char *name, const char *params) + { + struct ck_function_list *module; +- unsigned custom_init = 0, flags = 0; +- struct ck_c_initialize_args args; +- const char *p; ++ struct gnutls_pkcs11_provider_st provider; ++ int flags = 0; + int ret; + +- if (params && (p = strstr(params, "p11-kit:")) != 0) { +- memset(&args, 0, sizeof(args)); +- args.reserved = (char *)(p + sizeof("p11-kit:") - 1); +- args.flags = CKF_OS_LOCKING_OK; +- +- custom_init = 1; ++ if (params && strstr(params, "p11-kit:") != NULL) { + flags = P11_KIT_MODULE_UNMANAGED; + } + + module = p11_kit_module_load(name, P11_KIT_MODULE_CRITICAL | flags); + if (module == NULL) { + gnutls_assert(); + _gnutls_debug_log("p11: Cannot load provider %s\n", name); + return GNUTLS_E_PKCS11_LOAD_ERROR; + } + +- _gnutls_debug_log("p11: Initializing module: %s\n", name); +- +- /* check if we have special information for a p11-kit trust module */ +- if (custom_init) { +- ret = module->C_Initialize(&args); +- } else { +- ret = p11_kit_module_initialize(module); +- } +- +- if (ret != CKR_OK) { ++ ret = pkcs11_provider_init(&provider, module, params); ++ if (ret != 0) { + p11_kit_module_release(module); + gnutls_assert(); +- return pkcs11_rv_to_err(ret); ++ return ret; + } + +- ret = pkcs11_add_module(name, module, custom_init, params); ++ ret = pkcs11_provider_add(&provider); + if (ret != 0) { + if (ret == GNUTLS_E_INT_RET_0) + ret = 0; +- if (!custom_init) +- p11_kit_module_finalize(module); +- else +- module->C_Finalize(NULL); +- p11_kit_module_release(module); ++ pkcs11_provider_deinit(&provider); + gnutls_assert(); + } + + return ret; + } +@@ -936,32 +999,44 @@ static void compat_load(const char *conf + + static int auto_load(unsigned trusted) + { + struct ck_function_list **modules; + int i, ret; +- char *name; + +- modules = p11_kit_modules_load_and_initialize( +- trusted ? P11_KIT_MODULE_TRUSTED : 0); ++ modules = p11_kit_modules_load(NULL, ++ trusted ? P11_KIT_MODULE_TRUSTED : 0); + if (modules == NULL) { + gnutls_assert(); +- _gnutls_debug_log("Cannot initialize registered modules: %s\n", ++ _gnutls_debug_log("Cannot load registered modules: %s\n", + p11_kit_message()); + return GNUTLS_E_PKCS11_LOAD_ERROR; + } + + for (i = 0; modules[i] != NULL; i++) { +- name = p11_kit_module_get_name(modules[i]); +- _gnutls_debug_log("p11: Initializing module: %s\n", name); ++ struct gnutls_pkcs11_provider_st provider; + +- ret = pkcs11_add_module(name, modules[i], 0, NULL); ++ ret = pkcs11_provider_init(&provider, modules[i], NULL); + if (ret < 0) { + gnutls_assert(); +- _gnutls_debug_log("Cannot load PKCS #11 module: %s\n", ++ char *name = p11_kit_module_get_name(modules[i]); ++ _gnutls_debug_log( ++ "Cannot initialize PKCS #11 module: %s\n", ++ name); ++ free(name); ++ continue; ++ } ++ ++ ret = pkcs11_provider_add(&provider); ++ if (ret < 0) { ++ gnutls_assert(); ++ char *name = p11_kit_module_get_name(provider.module); ++ _gnutls_debug_log("Cannot add PKCS #11 module: %s\n", + name); ++ free(name); ++ pkcs11_provider_deinit(&provider); ++ continue; + } +- free(name); + } + + /* Shallow free */ + free(modules); + return 0; +@@ -1033,11 +1108,12 @@ static int _gnutls_pkcs11_reinit(void) + unsigned i; + ck_rv_t rv; + + for (i = 0; i < active_providers; i++) { + if (providers[i].module != NULL) { +- rv = p11_kit_module_initialize(providers[i].module); ++ rv = providers[i].module->C_Initialize( ++ &providers[i].init_args); + if (rv == CKR_OK || + rv == CKR_CRYPTOKI_ALREADY_INITIALIZED) { + providers[i].active = 1; + } else { + providers[i].active = 0; +@@ -1102,17 +1178,11 @@ void gnutls_pkcs11_deinit(void) + init--; + if (init > 0) + return; + + for (i = 0; i < active_providers; i++) { +- if (providers[i].active) { +- if (!providers[i].custom_init) +- p11_kit_module_finalize(providers[i].module); +- else +- providers[i].module->C_Finalize(NULL); +- } +- p11_kit_module_release(providers[i].module); ++ pkcs11_provider_deinit(&providers[i]); + } + active_providers = 0; + providers_initialized = PROV_UNINITIALIZED; + + gnutls_pkcs11_set_pin_function(NULL, NULL); +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -356,10 +356,15 @@ libpkcs11mock2_la_LIBADD = ../gl/libgnu + noinst_LTLIBRARIES += libpkcs11mock3.la + libpkcs11mock3_la_SOURCES = pkcs11/pkcs11-mock3.c + libpkcs11mock3_la_LDFLAGS = -shared -rpath $(pkglibdir) -module -no-undefined -avoid-version + libpkcs11mock3_la_LIBADD = ../gl/libgnu.la + ++noinst_LTLIBRARIES += libpkcs11mock4.la ++libpkcs11mock4_la_SOURCES = pkcs11/pkcs11-mock4.c ++libpkcs11mock4_la_LDFLAGS = -shared -rpath $(pkglibdir) -module -no-undefined -avoid-version ++libpkcs11mock4_la_LIBADD = ../gl/libgnu.la ++ + pkcs11_cert_import_url_exts_SOURCES = pkcs11/pkcs11-cert-import-url-exts.c + pkcs11_cert_import_url_exts_DEPENDENCIES = libpkcs11mock1.la libutils.la + + pkcs11_cert_import_url4_exts_SOURCES = pkcs11/pkcs11-cert-import-url4-exts.c + pkcs11_cert_import_url4_exts_DEPENDENCIES = libpkcs11mock1.la libutils.la +@@ -501,17 +506,19 @@ pathbuf_CPPFLAGS = $(AM_CPPFLAGS) \ + -I$(top_builddir)/gl + + if ENABLE_PKCS11 + if !WINDOWS + ctests += tls13/post-handshake-with-cert-pkcs11 pkcs11/tls-neg-pkcs11-no-key \ +- global-init-override pkcs11/distrust-after ++ global-init-override pkcs11/distrust-after pkcs11/os-locking-ok + tls13_post_handshake_with_cert_pkcs11_DEPENDENCIES = libpkcs11mock2.la libutils.la + tls13_post_handshake_with_cert_pkcs11_LDADD = $(LDADD) $(LIBDL) + pkcs11_tls_neg_pkcs11_no_key_DEPENDENCIES = libpkcs11mock2.la libutils.la + pkcs11_tls_neg_pkcs11_no_key_LDADD = $(LDADD) $(LIBDL) + pkcs11_distrust_after_DEPENDENCIES = libpkcs11mock3.la libutils.la + pkcs11_distrust_after_LDADD = $(LDADD) $(LIBDL) ++pkcs11_os_locking_ok_DEPENDENCIES = libpkcs11mock4.la libutils.la ++pkcs11_os_locking_ok_LDADD = $(LDADD) $(LIBDL) + endif + endif + + dist_check_SCRIPTS = rfc2253-escape-test.sh rsa-md5-collision/rsa-md5-collision.sh systemkey.sh + +@@ -630,10 +637,11 @@ TESTS_ENVIRONMENT += \ + LSAN_OPTIONS=suppressions=$(srcdir)/gnutls-asan.supp \ + CAFILE=$(srcdir)/cert-tests/data/ca-certs.pem \ + P11MOCKLIB1=$(abs_builddir)/.libs/libpkcs11mock1.so \ + P11MOCKLIB2=$(abs_builddir)/.libs/libpkcs11mock2.so \ + P11MOCKLIB3=$(abs_builddir)/.libs/libpkcs11mock3.so \ ++ P11MOCKLIB4=$(abs_builddir)/.libs/libpkcs11mock4.so \ + PKCS12_MANY_CERTS_FILE=$(srcdir)/cert-tests/data/pkcs12_5certs.p12 \ + PKCS12FILE=$(srcdir)/cert-tests/data/client.p12 \ + PKCS12PASSWORD=foobar \ + PKCS12FILE_2=$(srcdir)/cert-tests/data/pkcs12_2certs.p12 \ + PKCS12PASSWORD_2="" \ +--- /dev/null ++++ b/tests/pkcs11/os-locking-ok.c +@@ -0,0 +1,165 @@ ++/* ++ * Copyright (C) 2025 Red Hat, Inc. ++ * ++ * Author: Daiki Ueno ++ * ++ * This file is part of GnuTLS. ++ * ++ * GnuTLS is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GnuTLS is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with this program. If not, see ++ */ ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif ++ ++#include ++#include ++#include ++ ++#if defined(_WIN32) ++ ++int main(void) ++{ ++ exit(77); ++} ++ ++#else ++ ++#include ++#include ++#include ++ ++#include "cert-common.h" ++#include "pkcs11/softhsm.h" ++#include "utils.h" ++ ++/* This program tests that a module can be initialized with ++ * CKF_OS_LOCKING_OK, even if it's not supported by the module. ++ */ ++ ++static void tls_log_func(int level, const char *str) ++{ ++ fprintf(stderr, "server|<%d>| %s", level, str); ++} ++ ++#define PIN "1234" ++ ++#define CONFIG_NAME "softhsm-os-locking-ok" ++#define CONFIG CONFIG_NAME ".config" ++ ++static int pin_func(void *userdata, int attempt, const char *url, ++ const char *label, unsigned flags, char *pin, ++ size_t pin_max) ++{ ++ if (attempt == 0) { ++ strcpy(pin, PIN); ++ return 0; ++ } ++ return -1; ++} ++ ++static void test(const char *provider) ++{ ++ int ret; ++ gnutls_x509_trust_list_t tl; ++ ++ gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL); ++ ++ success("test with %s\n", provider); ++ ++ if (debug) { ++ gnutls_global_set_log_function(tls_log_func); ++ gnutls_global_set_log_level(4711); ++ } ++ ++ /* point to SoftHSM token that libpkcs11mock4.so internally uses */ ++ setenv(SOFTHSM_ENV, CONFIG, 1); ++ ++ gnutls_pkcs11_set_pin_function(pin_func, NULL); ++ ++ ret = gnutls_pkcs11_add_provider(provider, "trusted"); ++ if (ret != 0) { ++ fail("gnutls_pkcs11_add_provider: %s\n", gnutls_strerror(ret)); ++ } ++ ++ /* initialize softhsm token */ ++ ret = gnutls_pkcs11_token_init(SOFTHSM_URL, PIN, "test"); ++ if (ret < 0) { ++ fail("gnutls_pkcs11_token_init: %s\n", gnutls_strerror(ret)); ++ } ++ ++ ret = gnutls_pkcs11_token_set_pin(SOFTHSM_URL, NULL, PIN, ++ GNUTLS_PIN_USER); ++ if (ret < 0) { ++ fail("gnutls_pkcs11_token_set_pin: %s\n", gnutls_strerror(ret)); ++ } ++ ++ gnutls_x509_trust_list_init(&tl, 0); ++ ++ ret = gnutls_x509_trust_list_add_trust_file(tl, SOFTHSM_URL, NULL, 0, 0, ++ 0); ++ if (ret < 0) { ++ fail("gnutls_x509_trust_list_add_trust_file\n"); ++ } ++ ++ gnutls_x509_trust_list_deinit(tl, 0); ++ ++ gnutls_pkcs11_deinit(); ++} ++ ++void doit(void) ++{ ++ const char *bin; ++ const char *lib; ++ char buf[128]; ++ ++ if (gnutls_fips140_mode_enabled()) ++ exit(77); ++ ++ /* this must be called once in the program */ ++ global_init(); ++ ++ /* we call gnutls_pkcs11_init manually */ ++ gnutls_pkcs11_deinit(); ++ ++ /* check if softhsm module is loadable */ ++ lib = softhsm_lib(); ++ ++ /* initialize SoftHSM token that libpkcs11mock4.so internally uses */ ++ bin = softhsm_bin(); ++ ++ set_softhsm_conf(CONFIG); ++ snprintf(buf, sizeof(buf), ++ "%s --init-token --slot 0 --label test --so-pin " PIN ++ " --pin " PIN, ++ bin); ++ system(buf); ++ ++ test(lib); ++ ++ lib = getenv("P11MOCKLIB4"); ++ if (lib == NULL) { ++ fail("P11MOCKLIB4 is not set\n"); ++ } ++ ++ set_softhsm_conf(CONFIG); ++ snprintf(buf, sizeof(buf), ++ "%s --init-token --slot 0 --label test --so-pin " PIN ++ " --pin " PIN, ++ bin); ++ system(buf); ++ ++ test(lib); ++} ++#endif /* _WIN32 */ +--- /dev/null ++++ b/tests/pkcs11/pkcs11-mock4.c +@@ -0,0 +1,115 @@ ++/* ++ * Copyright (C) 2025 Red Hat, Inc. ++ * ++ * Author: Daiki Ueno ++ * ++ * This file is part of GnuTLS. ++ * ++ * GnuTLS is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GnuTLS is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with this program. If not, see ++ */ ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "softhsm.h" ++ ++/* This provides a mock PKCS #11 module that delegates all the ++ * operations to SoftHSM except that it returns CKR_CANT_LOCK upon ++ * C_Initialize if CKF_OS_LOCKING_OK is set. ++ */ ++ ++static void *dl; ++static CK_C_Initialize base_C_Initialize; ++static CK_FUNCTION_LIST override_funcs; ++ ++#ifdef __sun ++#pragma fini(mock_deinit) ++#pragma init(mock_init) ++#define _CONSTRUCTOR ++#define _DESTRUCTOR ++#else ++#define _CONSTRUCTOR __attribute__((constructor)) ++#define _DESTRUCTOR __attribute__((destructor)) ++#endif ++ ++static CK_RV override_C_Initialize(void *args) ++{ ++ CK_C_INITIALIZE_ARGS *init_args = args; ++ static bool first = true; ++ ++ assert(init_args); ++ ++ if (first) { ++ assert(init_args->flags & CKF_OS_LOCKING_OK); ++ first = false; ++ return CKR_CANT_LOCK; ++ } else { ++ assert(!(init_args->flags & CKF_OS_LOCKING_OK)); ++ } ++ ++ return base_C_Initialize(args); ++} ++ ++CK_RV C_GetFunctionList(CK_FUNCTION_LIST **function_list) ++{ ++ CK_C_GetFunctionList func; ++ CK_FUNCTION_LIST *funcs; ++ ++ assert(dl); ++ ++ func = dlsym(dl, "C_GetFunctionList"); ++ if (func == NULL) { ++ return CKR_GENERAL_ERROR; ++ } ++ ++ func(&funcs); ++ ++ base_C_Initialize = funcs->C_Initialize; ++ ++ memcpy(&override_funcs, funcs, sizeof(CK_FUNCTION_LIST)); ++ override_funcs.C_Initialize = override_C_Initialize; ++ *function_list = &override_funcs; ++ ++ return CKR_OK; ++} ++ ++static _CONSTRUCTOR void mock_init(void) ++{ ++ const char *lib; ++ ++ /* suppress compiler warning */ ++ (void)set_softhsm_conf; ++ ++ lib = softhsm_lib(); ++ ++ dl = dlopen(lib, RTLD_NOW); ++ if (dl == NULL) ++ exit(77); ++} ++ ++static _DESTRUCTOR void mock_deinit(void) ++{ ++ dlclose(dl); ++} diff -Nru gnutls28-3.8.9/debian/patches/48_0002-pkcs11-avoid-stack-overwrite-when-initializing-a-tok.patch gnutls28-3.8.9/debian/patches/48_0002-pkcs11-avoid-stack-overwrite-when-initializing-a-tok.patch --- gnutls28-3.8.9/debian/patches/48_0002-pkcs11-avoid-stack-overwrite-when-initializing-a-tok.patch 1970-01-01 00:00:00.000000000 +0000 +++ gnutls28-3.8.9/debian/patches/48_0002-pkcs11-avoid-stack-overwrite-when-initializing-a-tok.patch 2025-11-23 13:13:38.000000000 +0000 @@ -0,0 +1,261 @@ +From 1d56f96f6ab5034d677136b9d50b5a75dff0faf5 Mon Sep 17 00:00:00 2001 +From: Daiki Ueno +Date: Tue, 18 Nov 2025 13:17:55 +0900 +Subject: [PATCH] pkcs11: avoid stack overwrite when initializing a token + +If gnutls_pkcs11_token_init is called with label longer than 32 +characters, the internal storage used to blank-fill it would +overflow. This adds a guard to prevent that. + +Signed-off-by: Daiki Ueno +--- + .gitignore | 2 + + NEWS | 4 + + lib/pkcs11_write.c | 5 +- + tests/Makefile.am | 2 +- + tests/pkcs11/long-label.c | 164 ++++++++++++++++++++++++++++++++++++++ + 5 files changed, 174 insertions(+), 3 deletions(-) + create mode 100644 tests/pkcs11/long-label.c + +--- a/NEWS ++++ b/NEWS +@@ -3,10 +3,16 @@ Bug numbers referenced in this log corre + available at https://gitlab.com/gnutls/gnutls/issues + Copyright (C) 2000-2016 Free Software Foundation, Inc. + Copyright (C) 2013-2019 Nikos Mavrogiannopoulos + See the end for copying conditions. + ++* Version 3.8.11 ++ ++** libgnutls: Fix stack overwrite in gnutls_pkcs11_token_init ++ Reported by Luigino Camastra from Aisle Research. [GNUTLS-SA-2025-11-18, ++ CVSS: low] [CVE-2025-9820] ++ + * Version 3.8.10 + + ** libgnutls: Fix NULL pointer dereference when 2nd Client Hello omits PSK + Reported by Stefan Bühler. [GNUTLS-SA-2025-07-07-4, CVSS: medium] + [CVE-2025-6395] +--- a/lib/pkcs11_write.c ++++ b/lib/pkcs11_write.c +@@ -26,10 +26,11 @@ + #include "datum.h" + #include "pkcs11_int.h" + #include "pkcs11x.h" + #include "x509/common.h" + #include "pk.h" ++#include "minmax.h" + + static const ck_bool_t tval = 1; + static const ck_bool_t fval = 0; + + #define MAX_ASIZE 24 +@@ -1170,11 +1171,11 @@ int gnutls_pkcs11_delete_url(const char + + /** + * gnutls_pkcs11_token_init: + * @token_url: A PKCS #11 URL specifying a token + * @so_pin: Security Officer's PIN +- * @label: A name to be used for the token ++ * @label: A name to be used for the token, at most 32 characters + * + * This function will initialize (format) a token. If the token is + * at a factory defaults state the security officer's PIN given will be + * set to be the default. Otherwise it should match the officer's PIN. + * +@@ -1208,11 +1209,11 @@ int gnutls_pkcs11_token_init(const char + } + + /* so it seems memset has other uses than zeroing! */ + memset(flabel, ' ', sizeof(flabel)); + if (label != NULL) +- memcpy(flabel, label, strlen(label)); ++ memcpy(flabel, label, MIN(sizeof(flabel), strlen(label))); + + rv = pkcs11_init_token(module, slot, (uint8_t *)so_pin, strlen(so_pin), + (uint8_t *)flabel); + if (rv != CKR_OK) { + gnutls_assert(); +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -506,11 +506,12 @@ pathbuf_CPPFLAGS = $(AM_CPPFLAGS) \ + -I$(top_builddir)/gl + + if ENABLE_PKCS11 + if !WINDOWS + ctests += tls13/post-handshake-with-cert-pkcs11 pkcs11/tls-neg-pkcs11-no-key \ +- global-init-override pkcs11/distrust-after pkcs11/os-locking-ok ++ global-init-override pkcs11/distrust-after pkcs11/os-locking-ok \ ++ pkcs11/long-label + tls13_post_handshake_with_cert_pkcs11_DEPENDENCIES = libpkcs11mock2.la libutils.la + tls13_post_handshake_with_cert_pkcs11_LDADD = $(LDADD) $(LIBDL) + pkcs11_tls_neg_pkcs11_no_key_DEPENDENCIES = libpkcs11mock2.la libutils.la + pkcs11_tls_neg_pkcs11_no_key_LDADD = $(LDADD) $(LIBDL) + pkcs11_distrust_after_DEPENDENCIES = libpkcs11mock3.la libutils.la +--- /dev/null ++++ b/tests/pkcs11/long-label.c +@@ -0,0 +1,164 @@ ++/* ++ * Copyright (C) 2025 Red Hat, Inc. ++ * ++ * Author: Daiki Ueno ++ * ++ * This file is part of GnuTLS. ++ * ++ * GnuTLS is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GnuTLS is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with this program. If not, see ++ */ ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif ++ ++#include ++#include ++#include ++ ++#if defined(_WIN32) ++ ++int main(void) ++{ ++ exit(77); ++} ++ ++#else ++ ++#include ++#include ++#include ++ ++#include "cert-common.h" ++#include "pkcs11/softhsm.h" ++#include "utils.h" ++ ++/* This program tests that a token can be initialized with ++ * a label longer than 32 characters. ++ */ ++ ++static void tls_log_func(int level, const char *str) ++{ ++ fprintf(stderr, "server|<%d>| %s", level, str); ++} ++ ++#define PIN "1234" ++ ++#define CONFIG_NAME "softhsm-long-label" ++#define CONFIG CONFIG_NAME ".config" ++ ++static int pin_func(void *userdata, int attempt, const char *url, ++ const char *label, unsigned flags, char *pin, ++ size_t pin_max) ++{ ++ if (attempt == 0) { ++ strcpy(pin, PIN); ++ return 0; ++ } ++ return -1; ++} ++ ++static void test(const char *provider) ++{ ++ int ret; ++ size_t i; ++ ++ gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL); ++ ++ success("test with %s\n", provider); ++ ++ if (debug) { ++ gnutls_global_set_log_function(tls_log_func); ++ gnutls_global_set_log_level(4711); ++ } ++ ++ /* point to SoftHSM token that libpkcs11mock4.so internally uses */ ++ setenv(SOFTHSM_ENV, CONFIG, 1); ++ ++ gnutls_pkcs11_set_pin_function(pin_func, NULL); ++ ++ ret = gnutls_pkcs11_add_provider(provider, "trusted"); ++ if (ret != 0) { ++ fail("gnutls_pkcs11_add_provider: %s\n", gnutls_strerror(ret)); ++ } ++ ++ /* initialize softhsm token */ ++ ret = gnutls_pkcs11_token_init( ++ SOFTHSM_URL, PIN, ++ "this is a very long label whose length exceeds 32"); ++ if (ret < 0) { ++ fail("gnutls_pkcs11_token_init: %s\n", gnutls_strerror(ret)); ++ } ++ ++ for (i = 0;; i++) { ++ char *url = NULL; ++ ++ ret = gnutls_pkcs11_token_get_url(i, 0, &url); ++ if (ret < 0) ++ break; ++ if (strstr(url, ++ "token=this%20is%20a%20very%20long%20label%20whose")) ++ break; ++ } ++ if (ret < 0) ++ fail("gnutls_pkcs11_token_get_url: %s\n", gnutls_strerror(ret)); ++ ++ gnutls_pkcs11_deinit(); ++} ++ ++void doit(void) ++{ ++ const char *bin; ++ const char *lib; ++ char buf[128]; ++ ++ if (gnutls_fips140_mode_enabled()) ++ exit(77); ++ ++ /* this must be called once in the program */ ++ global_init(); ++ ++ /* we call gnutls_pkcs11_init manually */ ++ gnutls_pkcs11_deinit(); ++ ++ /* check if softhsm module is loadable */ ++ lib = softhsm_lib(); ++ ++ /* initialize SoftHSM token that libpkcs11mock4.so internally uses */ ++ bin = softhsm_bin(); ++ ++ set_softhsm_conf(CONFIG); ++ snprintf(buf, sizeof(buf), ++ "%s --init-token --slot 0 --label test --so-pin " PIN ++ " --pin " PIN, ++ bin); ++ system(buf); ++ ++ test(lib); ++ ++ lib = getenv("P11MOCKLIB4"); ++ if (lib == NULL) { ++ fail("P11MOCKLIB4 is not set\n"); ++ } ++ ++ set_softhsm_conf(CONFIG); ++ snprintf(buf, sizeof(buf), ++ "%s --init-token --slot 0 --label test --so-pin " PIN ++ " --pin " PIN, ++ bin); ++ system(buf); ++ ++ test(lib); ++} ++#endif /* _WIN32 */ diff -Nru gnutls28-3.8.9/debian/patches/series gnutls28-3.8.9/debian/patches/series --- gnutls28-3.8.9/debian/patches/series 2025-07-09 09:40:47.000000000 +0000 +++ gnutls28-3.8.9/debian/patches/series 2025-11-23 13:13:38.000000000 +0000 @@ -9,3 +9,5 @@ 47_0004-x509-avoid-double-free-when-exporting-othernames-in-.patch 47_0005-certtool-avoid-1-byte-write-buffer-overrun-when-pars.patch 47_0006-handshake-clear-HSK_PSK_SELECTED-is-when-resetting-b.patch +48_0001-pkcs11-try-to-initialize-modules-in-thread-safe-mode.patch +48_0002-pkcs11-avoid-stack-overwrite-when-initializing-a-tok.patch