Coverage Report

Created: 2025-06-24 07:00

/src/boringssl/crypto/bio/socket.cc
Line
Count
Source (jump to first uncovered line)
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)
33
0
static int closesocket(int sock) {
34
0
  return close(sock);
35
0
}
36
#endif
37
38
0
static int sock_free(BIO *bio) {
39
0
  if (bio->shutdown) {
40
0
    if (bio->init) {
41
0
      closesocket(bio->num);
42
0
    }
43
0
    bio->init = 0;
44
0
    bio->flags = 0;
45
0
  }
46
0
  return 1;
47
0
}
48
49
0
static int sock_read(BIO *b, char *out, int outl) {
50
0
  if (out == NULL) {
51
0
    return 0;
52
0
  }
53
54
0
  bio_clear_socket_error();
55
#if defined(OPENSSL_WINDOWS)
56
  int ret = recv(b->num, out, outl, 0);
57
#else
58
0
  int ret = (int)read(b->num, out, outl);
59
0
#endif
60
0
  BIO_clear_retry_flags(b);
61
0
  if (ret <= 0) {
62
0
    if (bio_socket_should_retry(ret)) {
63
0
      BIO_set_retry_read(b);
64
0
    }
65
0
  }
66
0
  return ret;
67
0
}
68
69
0
static int sock_write(BIO *b, const char *in, int inl) {
70
0
  bio_clear_socket_error();
71
#if defined(OPENSSL_WINDOWS)
72
  int ret = send(b->num, in, inl, 0);
73
#else
74
0
  int ret = (int)write(b->num, in, inl);
75
0
#endif
76
0
  BIO_clear_retry_flags(b);
77
0
  if (ret <= 0) {
78
0
    if (bio_socket_should_retry(ret)) {
79
0
      BIO_set_retry_write(b);
80
0
    }
81
0
  }
82
0
  return ret;
83
0
}
84
85
0
static long sock_ctrl(BIO *b, int cmd, long num, void *ptr) {
86
0
  switch (cmd) {
87
0
    case BIO_C_SET_FD:
88
0
      sock_free(b);
89
0
      b->num = *static_cast<int *>(ptr);
90
0
      b->shutdown = static_cast<int>(num);
91
0
      b->init = 1;
92
0
      return 1;
93
0
    case BIO_C_GET_FD:
94
0
      if (b->init) {
95
0
        int *out = static_cast<int*>(ptr);
96
0
        if (out != nullptr) {
97
0
          *out = b->num;
98
0
        }
99
0
        return b->num;
100
0
      }
101
0
      return -1;
102
0
    case BIO_CTRL_GET_CLOSE:
103
0
      return b->shutdown;
104
0
    case BIO_CTRL_SET_CLOSE:
105
0
      b->shutdown = static_cast<int>(num);
106
0
      return 1;
107
0
    case BIO_CTRL_FLUSH:
108
0
      return 1;
109
0
    default:
110
0
      return 0;
111
0
  }
112
0
}
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
126
0
const BIO_METHOD *BIO_s_socket(void) { return &methods_sockp; }
127
128
0
BIO *BIO_new_socket(int fd, int close_flag) {
129
0
  BIO *ret;
130
131
0
  ret = BIO_new(BIO_s_socket());
132
0
  if (ret == NULL) {
133
0
    return NULL;
134
0
  }
135
0
  BIO_set_fd(ret, fd, close_flag);
136
0
  return ret;
137
0
}
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
169
0
int (*BIO_meth_get_write(const BIO_METHOD *method))(BIO *, const char *, int) {
170
0
  BSSL_CHECK(method == BIO_s_socket());
171
0
  return method->bwrite;
172
0
}
173
174
0
int (*BIO_meth_get_read(const BIO_METHOD *method))(BIO *, char *, int) {
175
0
  BSSL_CHECK(method == BIO_s_socket());
176
0
  return method->bread;
177
0
}
178
179
0
int (*BIO_meth_get_gets(const BIO_METHOD *method))(BIO *, char *, int) {
180
0
  BSSL_CHECK(method == BIO_s_socket());
181
0
  return method->bgets;
182
0
}
183
184
0
int (*BIO_meth_get_puts(const BIO_METHOD *method))(BIO *, const char *) {
185
0
  BSSL_CHECK(method == BIO_s_socket());
186
0
  return nullptr;
187
0
}
188
189
0
long (*BIO_meth_get_ctrl(const BIO_METHOD *method))(BIO *, int, long, void *) {
190
0
  BSSL_CHECK(method == BIO_s_socket());
191
0
  return method->ctrl;
192
0
}
193
194
0
int (*BIO_meth_get_create(const BIO_METHOD *method))(BIO *) {
195
0
  BSSL_CHECK(method == BIO_s_socket());
196
0
  return method->create;
197
0
}
198
199
0
int (*BIO_meth_get_destroy(const BIO_METHOD *method))(BIO *) {
200
0
  BSSL_CHECK(method == BIO_s_socket());
201
0
  return method->destroy;
202
0
}
203
204
long (*BIO_meth_get_callback_ctrl(const BIO_METHOD *method))(BIO *, int,
205
0
                                                             bio_info_cb) {
206
0
  BSSL_CHECK(method == BIO_s_socket());
207
0
  return method->callback_ctrl;
208
0
}
209
210
#endif  // OPENSSL_NO_SOCK