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