1 // Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <openssl/bio.h>
16 
17 #if !defined(OPENSSL_NO_SOCK)
18 
19 #include <fcntl.h>
20 #include <string.h>
21 
22 #if !defined(OPENSSL_WINDOWS)
23 #include <unistd.h>
24 #else
25 #include <winsock2.h>
26 OPENSSL_MSVC_PRAGMA(comment(lib, "Ws2_32.lib"))
27 #endif
28 
29 #include "internal.h"
30 
31 
32 #if !defined(OPENSSL_WINDOWS)
closesocket(int sock)33 static int closesocket(int sock) {
34   return close(sock);
35 }
36 #endif
37 
sock_free(BIO * bio)38 static int sock_free(BIO *bio) {
39   if (bio->shutdown) {
40     if (bio->init) {
41       closesocket(bio->num);
42     }
43     bio->init = 0;
44     bio->flags = 0;
45   }
46   return 1;
47 }
48 
sock_read(BIO * b,char * out,int outl)49 static int sock_read(BIO *b, char *out, int outl) {
50   if (out == NULL) {
51     return 0;
52   }
53 
54   bio_clear_socket_error();
55 #if defined(OPENSSL_WINDOWS)
56   int ret = recv(b->num, out, outl, 0);
57 #else
58   int ret = (int)read(b->num, out, outl);
59 #endif
60   BIO_clear_retry_flags(b);
61   if (ret <= 0) {
62     if (bio_socket_should_retry(ret)) {
63       BIO_set_retry_read(b);
64     }
65   }
66   return ret;
67 }
68 
sock_write(BIO * b,const char * in,int inl)69 static int sock_write(BIO *b, const char *in, int inl) {
70   bio_clear_socket_error();
71 #if defined(OPENSSL_WINDOWS)
72   int ret = send(b->num, in, inl, 0);
73 #else
74   int ret = (int)write(b->num, in, inl);
75 #endif
76   BIO_clear_retry_flags(b);
77   if (ret <= 0) {
78     if (bio_socket_should_retry(ret)) {
79       BIO_set_retry_write(b);
80     }
81   }
82   return ret;
83 }
84 
sock_ctrl(BIO * b,int cmd,long num,void * ptr)85 static long sock_ctrl(BIO *b, int cmd, long num, void *ptr) {
86   switch (cmd) {
87     case BIO_C_SET_FD:
88       sock_free(b);
89       b->num = *static_cast<int *>(ptr);
90       b->shutdown = static_cast<int>(num);
91       b->init = 1;
92       return 1;
93     case BIO_C_GET_FD:
94       if (b->init) {
95         int *out = static_cast<int*>(ptr);
96         if (out != nullptr) {
97           *out = b->num;
98         }
99         return b->num;
100       }
101       return -1;
102     case BIO_CTRL_GET_CLOSE:
103       return b->shutdown;
104     case BIO_CTRL_SET_CLOSE:
105       b->shutdown = static_cast<int>(num);
106       return 1;
107     case BIO_CTRL_FLUSH:
108       return 1;
109     default:
110       return 0;
111   }
112 }
113 
114 static const BIO_METHOD methods_sockp = {
115     BIO_TYPE_SOCKET,
116     "socket",
117     sock_write,
118     sock_read,
119     nullptr /* gets, */,
120     sock_ctrl,
121     nullptr /* create */,
122     sock_free,
123     nullptr /* callback_ctrl */,
124 };
125 
BIO_s_socket(void)126 const BIO_METHOD *BIO_s_socket(void) { return &methods_sockp; }
127 
BIO_new_socket(int fd,int close_flag)128 BIO *BIO_new_socket(int fd, int close_flag) {
129   BIO *ret;
130 
131   ret = BIO_new(BIO_s_socket());
132   if (ret == NULL) {
133     return NULL;
134   }
135   BIO_set_fd(ret, fd, close_flag);
136   return ret;
137 }
138 
139 // These functions are provided solely for compatibility with software that
140 // tries to copy and then modify |BIO_s_socket|. See bio.h for details.
141 // PostgreSQL's use makes several fragile assumptions on |BIO_s_socket|:
142 //
143 // - We do not store anything in |BIO_set_data|. (Broken in upstream OpenSSL,
144 //   which broke PostgreSQL.)
145 // - We do not store anything in |BIO_set_app_data|.
146 // - |BIO_s_socket| is implemented internally using the non-|size_t|-clean
147 //   I/O functions rather than the |size_t|-clean ones.
148 // - |BIO_METHOD| never gains another function pointer that is used in concert
149 //   with any of the functions here.
150 //
151 // Some other projects doing similar things use |BIO_meth_get_read| and
152 // |BIO_meth_get_write| and in turn assume that |BIO_s_socket| has not been
153 // ported to the |size_t|-clean |BIO_read_ex| and |BIO_write_ex|. (Not yet
154 // implemented in BoringSSL.)
155 //
156 // This is hopelessly fragile. PostgreSQL 18 will include a fix to stop using
157 // these APIs, but older versions and other software remain impacted, so we
158 // implement these functions, but only support |BIO_s_socket|. For now they just
159 // return the underlying functions, but if we ever need to break the above
160 // assumptions, we can return an older, frozen version of |BIO_s_socket|.
161 // Limiting to exactly one allowed |BIO_METHOD| lets us do this.
162 //
163 // These functions are also deprecated in upstream OpenSSL. See
164 // https://github.com/openssl/openssl/issues/26047
165 //
166 // TODO(davidben): Once Folly and all versions of PostgreSQL we care about are
167 // updated or patched, remove these functions.
168 
BIO_meth_get_write(const BIO_METHOD * method)169 int (*BIO_meth_get_write(const BIO_METHOD *method))(BIO *, const char *, int) {
170   BSSL_CHECK(method == BIO_s_socket());
171   return method->bwrite;
172 }
173 
BIO_meth_get_read(const BIO_METHOD * method)174 int (*BIO_meth_get_read(const BIO_METHOD *method))(BIO *, char *, int) {
175   BSSL_CHECK(method == BIO_s_socket());
176   return method->bread;
177 }
178 
BIO_meth_get_gets(const BIO_METHOD * method)179 int (*BIO_meth_get_gets(const BIO_METHOD *method))(BIO *, char *, int) {
180   BSSL_CHECK(method == BIO_s_socket());
181   return method->bgets;
182 }
183 
BIO_meth_get_puts(const BIO_METHOD * method)184 int (*BIO_meth_get_puts(const BIO_METHOD *method))(BIO *, const char *) {
185   BSSL_CHECK(method == BIO_s_socket());
186   return nullptr;
187 }
188 
BIO_meth_get_ctrl(const BIO_METHOD * method)189 long (*BIO_meth_get_ctrl(const BIO_METHOD *method))(BIO *, int, long, void *) {
190   BSSL_CHECK(method == BIO_s_socket());
191   return method->ctrl;
192 }
193 
BIO_meth_get_create(const BIO_METHOD * method)194 int (*BIO_meth_get_create(const BIO_METHOD *method))(BIO *) {
195   BSSL_CHECK(method == BIO_s_socket());
196   return method->create;
197 }
198 
BIO_meth_get_destroy(const BIO_METHOD * method)199 int (*BIO_meth_get_destroy(const BIO_METHOD *method))(BIO *) {
200   BSSL_CHECK(method == BIO_s_socket());
201   return method->destroy;
202 }
203 
BIO_meth_get_callback_ctrl(const BIO_METHOD * method)204 long (*BIO_meth_get_callback_ctrl(const BIO_METHOD *method))(BIO *, int,
205                                                              bio_info_cb) {
206   BSSL_CHECK(method == BIO_s_socket());
207   return method->callback_ctrl;
208 }
209 
210 #endif  // OPENSSL_NO_SOCK
211