Implement BIO_meth_get_* I skipped these functions at first because it is not possible to use them in a future-proof way. See the comments added. Sadly PostgreSQL uses them, and the upstream fix will take quite some time to trickle through. If we limit them to BIO_s_socket, I think we'll be free to work around the API issues by returning custom functions as needed. (For now I have just returned the real ones for convenience.) Bug: 412269080 Change-Id: Id64a0462702b456c27c09a50d0da7d0d51eff3b8 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/78831 Auto-Submit: David Benjamin <davidben@google.com> Reviewed-by: Adam Langley <agl@google.com> Commit-Queue: Adam Langley <agl@google.com>
diff --git a/crypto/bio/socket.cc b/crypto/bio/socket.cc index d1066a7..9888fa2 100644 --- a/crypto/bio/socket.cc +++ b/crypto/bio/socket.cc
@@ -132,4 +132,63 @@ return ret; } +// These functions are provided solely for compatibility with older versions of +// PostgreSQL. See bio.h for details. PostgreSQL's use makes several fragile +// assumptions on |BIO_s_socket|: +// +// - We do not store anything in |BIO_set_data|. (Broken in upstream OpenSSL, +// which broke PostgreSQL.) +// - We do not store anything in |BIO_set_app_data|. +// - |BIO_METHOD| never gains another function pointer that is used in concert +// with any of the functions here. +// +// Some other projects doing similar things use |BIO_meth_get_read| and +// |BIO_meth_get_write| and in turn assume that |BIO_s_socket| has not been +// ported to the |size_t|-clean |BIO_read_ex| and |BIO_write_ex|. (Not yet +// implemented in BoringSSL.) +// +// This is hopelessly fragile. PostgreSQL 18 will include a fix to stop using +// these APIs, but older versions remain impact, so we implement these +// functions, but only support |BIO_s_socket|. For now they just return the +// underlying functions, but if we ever need to break the above assumptions, we +// can return an older, frozen version of |BIO_s_socket|. Limiting to exactly +// one allowed |BIO_METHOD| lets us do this. +// +// These functions are also deprecated in upstream OpenSSL. See +// https://github.com/openssl/openssl/issues/26047 +// +// TODO(davidben): Once all versions of PostgreSQL we care about are updated or +// patched, remove these functions. + +int (*BIO_meth_get_gets(const BIO_METHOD *method))(BIO *, char *, int) { + BSSL_CHECK(method == BIO_s_socket()); + return method->bgets; +} + +int (*BIO_meth_get_puts(const BIO_METHOD *method))(BIO *, const char *) { + BSSL_CHECK(method == BIO_s_socket()); + return method->bputs; +} + +long (*BIO_meth_get_ctrl(const BIO_METHOD *method))(BIO *, int, long, void *) { + BSSL_CHECK(method == BIO_s_socket()); + return method->ctrl; +} + +int (*BIO_meth_get_create(const BIO_METHOD *method))(BIO *) { + BSSL_CHECK(method == BIO_s_socket()); + return method->create; +} + +int (*BIO_meth_get_destroy(const BIO_METHOD *method))(BIO *) { + BSSL_CHECK(method == BIO_s_socket()); + return method->destroy; +} + +long (*BIO_meth_get_callback_ctrl(const BIO_METHOD *method))(BIO *, int, + bio_info_cb) { + BSSL_CHECK(method == BIO_s_socket()); + return method->callback_ctrl; +} + #endif // OPENSSL_NO_SOCK
diff --git a/include/openssl/bio.h b/include/openssl/bio.h index bd88c97..ca5ee4e 100644 --- a/include/openssl/bio.h +++ b/include/openssl/bio.h
@@ -796,6 +796,43 @@ OPENSSL_EXPORT int BIO_meth_set_puts(BIO_METHOD *method, int (*puts)(BIO *, const char *)); +#if !defined(OPENSSL_NO_SOCK) +// The following functions return function pointers, possibly NULL, which are +// compatible with the corresponding |BIO_meth_set_*| function. |method| must be +// |BIO_s_socket| or the program will abort. +// +// Using these functions is inherently unsafe and fragile. It is not possible to +// use them in a future-proof way. See +// https://github.com/openssl/openssl/issues/26047 for details. BoringSSL +// implements them solely for compatibility with older versions of PostgreSQL. +// To work around the future-proofing problems, the return values may diverge +// from the true implementation of |BIO_s_socket|. +// +// Caller should not use these functions. They are not necessary to define +// custom |BIO_METHOD|s. Instead, callers should either: +// +// - Define a custom |BIO_METHOD| that owns a socket |BIO| somewhere in the +// custom data. See |BIO_set_data|. +// +// - Define a custom |BIO_METHOD| that wraps a socket |BIO| as a filter. See +// |BIO_push| and |BIO_next|. +// +// - Define a custom |BIO_METHOD| without |BIO_s_socket| at all. If not using +// the built-in read or write functions, |BIO_s_socket| only provides a no-op +// |BIO_CTRL_FLUSH| implementation. This can be implemented by the caller. +OPENSSL_EXPORT int (*BIO_meth_get_gets(const BIO_METHOD *method))(BIO *, char *, + int); +OPENSSL_EXPORT int (*BIO_meth_get_puts(const BIO_METHOD *method))(BIO *, + const char *); +OPENSSL_EXPORT long (*BIO_meth_get_ctrl(const BIO_METHOD *method))(BIO *, int, + long, + void *); +OPENSSL_EXPORT int (*BIO_meth_get_create(const BIO_METHOD *method))(BIO *); +OPENSSL_EXPORT int (*BIO_meth_get_destroy(const BIO_METHOD *method))(BIO *); +OPENSSL_EXPORT long (*BIO_meth_get_callback_ctrl(const BIO_METHOD *method))( + BIO *, int, BIO_info_cb *); +#endif // !OPENSSL_NO_SOCK + // Private functions