From 605f2aeb97bd7dabb60172e0f57e074e91ebde6c Mon Sep 17 00:00:00 2001 From: Zhijin Zeng Date: Tue, 11 Aug 2026 14:35:55 +0800 Subject: [PATCH] [WRAPPER] Fix UAF for gpgme_data_new_from_cbs reported in #4214 `gpgme_data_release` is invoked without explicitly passing `cbs`. As `cbs` reside inside a union, fetching the `cbs` is a bit complicated, so no cleanup helper is provided. In practice, there are probably few cbs instances, analogous to `cbs->release` that only has five available slots. `gpgme_data_new_from_cbs` in: https://github.com/gpg/gpgme/blob/master/src/data-user.c#L99 --- src/wrapped/wrappedlibgpgme.c | 55 ++++++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 8 deletions(-) diff --git a/src/wrapped/wrappedlibgpgme.c b/src/wrapped/wrappedlibgpgme.c index 0e08e0395b..a8f2149d26 100644 --- a/src/wrapped/wrappedlibgpgme.c +++ b/src/wrapped/wrappedlibgpgme.c @@ -132,16 +132,55 @@ static void* find_release_Fct(void* fct) #undef SUPER -EXPORT uint32_t my_gpgme_data_new_from_cbs(x64emu_t* emu, void* data, my_gpgme_data_cbs_t* cbs, void* stream) +// gpgme_data_cbs_t +#define SUPER() \ +GO(0) \ +GO(1) \ +GO(2) \ +GO(3) \ +GO(4) + +#define GO(A) \ +static my_gpgme_data_cbs_t* my_gpgme_data_cbs_ref_##A = NULL; \ +static my_gpgme_data_cbs_t my_gpgme_data_cbs_struct_##A = {0}; +SUPER() +#undef GO + +static void wrap_gpgme_data_cbs(my_gpgme_data_cbs_t* dst, my_gpgme_data_cbs_t* src) { - my_gpgme_data_cbs_t cbs_ = {0}; - if(cbs) { - cbs_.read = find_read_Fct(cbs->read); - cbs_.write = find_write_Fct(cbs->write); - cbs_.seek = find_seek_Fct(cbs->seek); - cbs_.release = find_release_Fct(cbs->release); + #define GO(A) dst->A = find_##A##_Fct(src->A) + GO(read); + GO(write); + GO(seek); + GO(release); + #undef GO +} + +static my_gpgme_data_cbs_t* find_gpgme_data_cbs_Struct(my_gpgme_data_cbs_t* cbs) +{ + if(!cbs) return NULL; + #define GO(A) if(my_gpgme_data_cbs_ref_##A == cbs) { \ + return &my_gpgme_data_cbs_struct_##A; \ } - return my->gpgme_data_new_from_cbs(data, cbs?&cbs_:NULL, stream); + SUPER() + #undef GO + #define GO(A) if(!my_gpgme_data_cbs_ref_##A) { \ + wrap_gpgme_data_cbs(&my_gpgme_data_cbs_struct_##A, cbs); \ + my_gpgme_data_cbs_ref_##A = cbs; \ + return &my_gpgme_data_cbs_struct_##A; \ + } + SUPER() + #undef GO + printf_log(LOG_NONE, "Warning, no more slot for gpgme_data_cbs\n"); + return NULL; +} + +#undef SUPER + + +EXPORT uint32_t my_gpgme_data_new_from_cbs(x64emu_t* emu, void* data, my_gpgme_data_cbs_t* cbs, void* stream) +{ + return my->gpgme_data_new_from_cbs(data, find_gpgme_data_cbs_Struct(cbs), stream); } #include "wrappedlib_init.h"