1: caec9379055 < -: ----------- oauth: Report cleanup errors as warnings on stderr 2: 7228af114ca < -: ----------- libpq: Add PQgetThreadLock() to mirror PQregisterThreadLock() 3: 751df22f99d ! 1: 90f05c5d963 libpq: Introduce PQAUTHDATA_OAUTH_BEARER_TOKEN_V2 @@ doc/src/sgml/libpq.sgml: typedef struct PGoauthBearerRequest + issuer contains the issuer identifier, as + defined in RFC 9207, + that is in use for the current connection. This identifier is -+ determined by . ++ derived from . + To avoid mix-up attacks, custom flows should ensure that any discovery + metadata provided by the authorization server matches this issuer ID. + @@ src/interfaces/libpq/fe-auth-oauth.c: setup_token_request(PGconn *conn, fe_oauth ## src/test/modules/oauth_validator/oauth_hook_client.c ## -@@ - - #include "getopt_long.h" - #include "libpq-fe.h" -+#include "pqexpbuffer.h" - - static int handle_auth_data(PGauthData type, PGconn *conn, void *data); - static PostgresPollingStatusType async_cb(PGconn *conn, @@ src/test/modules/oauth_validator/oauth_hook_client.c: usage(char *argv[]) printf("recognized flags:\n"); 4: fb9915437da = 2: d8fbfc8f7a0 libpq-oauth: Use the PGoauthBearerRequestV2 API 5: ed6e7268ec2 = 3: 96bd5970668 libpq-oauth: Never link against libpq's encoding functions 6: e4b09853e3a ! 4: 0e7fae1e152 WIP: test out poisoning @@ Metadata ## Commit message ## WIP: test out poisoning - ## src/interfaces/libpq/meson.build ## -@@ src/interfaces/libpq/meson.build: libpq_c_args = ['-DSO_MAJOR_VERSION=5'] - # The OAuth implementation differs depending on the type of library being built. - libpq_so_c_args = ['-DUSE_DYNAMIC_OAUTH'] - -+libpq_link_args = [] -+if host_system == 'darwin' -+ # TODO staticlib too... -+ libpq_link_args += [ -+ '-Wl,-U,___asan_poison_memory_region', -+ '-Wl,-U,___asan_unpoison_memory_region', -+ ] -+endif -+ - # Not using both_libraries() here as - # 1) resource files should only be in the shared library - # 2) we want the .pc file to include a dependency to {pgport,common}_static for -@@ src/interfaces/libpq/meson.build: libpq_so = shared_library('libpq', - darwin_versions: ['5', '5.' + pg_version_major.to_string()], - dependencies: [frontend_shlib_code, libpq_deps], - link_depends: export_file, -- link_args: export_fmt.format(export_file.full_path()), -+ link_args: [ -+ export_fmt.format(export_file.full_path()), -+ libpq_link_args, -+ ], - kwargs: default_lib_args, - ) - libpq_targets += libpq_so - - ## src/interfaces/libpq/Makefile ## -@@ src/interfaces/libpq/Makefile: ifneq ($(PORTNAME), win32) - override CFLAGS += $(PTHREAD_CFLAGS) - endif - -+ifeq ($(PORTNAME),darwin) -+# TODO staticlib too... -+override LDFLAGS += -Wl,-U,___asan_poison_memory_region -+override LDFLAGS += -Wl,-U,___asan_unpoison_memory_region -+endif -+ - OBJS = \ - $(WIN32RES) \ - fe-auth-scram.o \ - ## src/interfaces/libpq/fe-auth-oauth.h ## @@ src/interfaces/libpq/fe-auth-oauth.h: typedef struct PGconn *conn; @@ src/interfaces/libpq/fe-auth-oauth.c: oauth_unsafe_debugging_enabled(void) + * PGoauthBearerRequestV2. (Such clients may crash or worse when speaking to + * libpq 18.) + * -+ * This attempts to use Valgrind and AddressSanitizer hooks, if present, to mark -+ * the extra members as inaccessible. For uninstrumented builds, it also munges -+ * request->issuer to try to crash clients that perform string operations, and -+ * it aborts if request->error is set. ++ * This attempts to use Valgrind hooks, if present, to mark the extra members as ++ * inaccessible. For uninstrumented builds, it also munges request->issuer to ++ * try to crash clients that perform string operations, and it aborts if ++ * request->error is set. + */ + -+#if defined(__has_attribute) && __has_attribute(weak) -+void __asan_poison_memory_region(void const volatile *addr, size_t size) __attribute__((weak)); -+void __asan_unpoison_memory_region(void const volatile *addr, size_t size) __attribute__((weak)); -+#else -+static void (*const __asan_poison_memory_region) (void const volatile *addr, size_t size) = NULL; -+static void (*const __asan_unpoison_memory_region) (void const volatile *addr, size_t size) = NULL; -+#endif -+ +#define MASK_BITS ((uintptr_t) 0x55aa55aa55aa55aa) +#define POISON_MASK(ptr) ((void *) (((uintptr_t) ptr) ^ MASK_BITS)) + @@ src/interfaces/libpq/fe-auth-oauth.c: oauth_unsafe_debugging_enabled(void) + request->issuer = POISON_MASK(request->issuer); + + VALGRIND_MAKE_MEM_NOACCESS(base, len); -+ if (__asan_poison_memory_region) -+ __asan_poison_memory_region(base, len); + } + else + { @@ src/interfaces/libpq/fe-auth-oauth.c: oauth_unsafe_debugging_enabled(void) + * original state of the memory. + */ + VALGRIND_MAKE_MEM_DEFINED(base, len); -+ if (__asan_unpoison_memory_region) -+ __asan_unpoison_memory_region(base, len); + + /* Undo our mask. */ + request->issuer = POISON_MASK(request->issuer); 7: 3d6d0901f7e ! 5: fbb89bcd980 WIP: Introduce third-party OAuth flow plugins? @@ src/test/modules/oauth_validator/meson.build: oauth_hook_client = executable('oa 'name': 'oauth_validator', 'sd': meson.current_source_dir(), @@ src/test/modules/oauth_validator/meson.build: tests += { - 'PYTHON': python.full_path(), 'with_libcurl': oauth_flow_supported ? 'yes' : 'no', 'with_python': 'yes', + 'cert_dir': meson.project_source_root() / 'src/test/ssl/ssl', + 'flow_module_path': oauth_flow.full_path(), }, 'deps': [oauth_hook_client], @@ src/test/modules/oauth_validator/Makefile: top_builddir = ../../../.. export PYTHON export with_libcurl export with_python +-export cert_dir=$(top_srcdir)/src/test/ssl/ssl ++export cert_dir := $(top_srcdir)/src/test/ssl/ssl +export flow_module_path := $(abs_top_builddir)/$(subdir)/oauth_flow$(DLSUFFIX) endif @@ src/test/modules/oauth_validator/oauth_hook_client.c -#include "getopt_long.h" #include "libpq-fe.h" --#include "pqexpbuffer.h" -static int handle_auth_data(PGauthData type, PGconn *conn, void *data); -static PostgresPollingStatusType async_cb(PGconn *conn, @@ src/test/modules/oauth_validator/oauth_test_common.c (new) + +#include "getopt_long.h" +#include "libpq-fe.h" -+#include "pqexpbuffer.h" + +#include "oauth_test_common.h" +