Coverage Report

Created: 2025-12-07 06:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boringssl/crypto/bio/bio_mem.cc
Line
Count
Source
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
#include <limits.h>
18
#include <string.h>
19
20
#include <openssl/buf.h>
21
#include <openssl/err.h>
22
#include <openssl/mem.h>
23
24
#include "../internal.h"
25
#include "internal.h"
26
27
28
13.7k
BIO *BIO_new_mem_buf(const void *buf, ossl_ssize_t len) {
29
13.7k
  BIO *ret;
30
13.7k
  BUF_MEM *b;
31
13.7k
  const size_t size = len < 0 ? strlen((char *)buf) : (size_t)len;
32
33
13.7k
  if (!buf && len != 0) {
34
0
    OPENSSL_PUT_ERROR(BIO, BIO_R_NULL_PARAMETER);
35
0
    return nullptr;
36
0
  }
37
38
13.7k
  ret = BIO_new(BIO_s_mem());
39
13.7k
  if (ret == nullptr) {
40
0
    return nullptr;
41
0
  }
42
43
13.7k
  b = (BUF_MEM *)ret->ptr;
44
  // BIO_FLAGS_MEM_RDONLY ensures |b->data| is not written to.
45
13.7k
  b->data = reinterpret_cast<char *>(const_cast<void *>(buf));
46
13.7k
  b->length = size;
47
13.7k
  b->max = size;
48
49
13.7k
  ret->flags |= BIO_FLAGS_MEM_RDONLY;
50
51
  // |num| is used to store the value that this BIO will return when it runs
52
  // out of data. If it's negative then the retry flags will also be set. Since
53
  // this is static data, retrying won't help
54
13.7k
  ret->num = 0;
55
56
13.7k
  return ret;
57
13.7k
}
58
59
49.0k
static int mem_new(BIO *bio) {
60
49.0k
  BUF_MEM *b;
61
62
49.0k
  b = BUF_MEM_new();
63
49.0k
  if (b == nullptr) {
64
0
    return 0;
65
0
  }
66
67
  // |shutdown| is used to store the close flag: whether the BIO has ownership
68
  // of the BUF_MEM.
69
49.0k
  bio->shutdown = 1;
70
49.0k
  bio->init = 1;
71
49.0k
  bio->num = -1;
72
49.0k
  bio->ptr = (char *)b;
73
74
49.0k
  return 1;
75
49.0k
}
76
77
49.0k
static int mem_free(BIO *bio) {
78
49.0k
  if (!bio->shutdown || !bio->init || bio->ptr == nullptr) {
79
0
    return 1;
80
0
  }
81
82
49.0k
  BUF_MEM *b = (BUF_MEM *)bio->ptr;
83
49.0k
  if (bio->flags & BIO_FLAGS_MEM_RDONLY) {
84
13.7k
    b->data = nullptr;
85
13.7k
  }
86
49.0k
  BUF_MEM_free(b);
87
49.0k
  bio->ptr = nullptr;
88
49.0k
  return 1;
89
49.0k
}
90
91
300k
static int mem_read(BIO *bio, char *out, int outl) {
92
300k
  BIO_clear_retry_flags(bio);
93
300k
  if (outl <= 0) {
94
25.1k
    return 0;
95
25.1k
  }
96
97
275k
  BUF_MEM *b = reinterpret_cast<BUF_MEM *>(bio->ptr);
98
275k
  int ret = outl;
99
275k
  if ((size_t)ret > b->length) {
100
0
    ret = (int)b->length;
101
0
  }
102
103
275k
  if (ret > 0) {
104
275k
    OPENSSL_memcpy(out, b->data, ret);
105
275k
    b->length -= ret;
106
275k
    if (bio->flags & BIO_FLAGS_MEM_RDONLY) {
107
275k
      b->data += ret;
108
275k
    } else {
109
0
      OPENSSL_memmove(b->data, &b->data[ret], b->length);
110
0
    }
111
275k
  } else if (b->length == 0) {
112
0
    ret = bio->num;
113
0
    if (ret != 0) {
114
0
      BIO_set_retry_read(bio);
115
0
    }
116
0
  }
117
275k
  return ret;
118
300k
}
119
120
1.08M
static int mem_write(BIO *bio, const char *in, int inl) {
121
1.08M
  BIO_clear_retry_flags(bio);
122
1.08M
  if (inl <= 0) {
123
0
    return 0;  // Successfully write zero bytes.
124
0
  }
125
126
1.08M
  if (bio->flags & BIO_FLAGS_MEM_RDONLY) {
127
0
    OPENSSL_PUT_ERROR(BIO, BIO_R_WRITE_TO_READ_ONLY_BIO);
128
0
    return -1;
129
0
  }
130
131
1.08M
  BUF_MEM *b = reinterpret_cast<BUF_MEM *>(bio->ptr);
132
1.08M
  if (!BUF_MEM_append(b, in, inl)) {
133
0
    return -1;
134
0
  }
135
136
1.08M
  return inl;
137
1.08M
}
138
139
300k
static int mem_gets(BIO *bio, char *buf, int size) {
140
300k
  BIO_clear_retry_flags(bio);
141
300k
  if (size <= 0) {
142
0
    return 0;
143
0
  }
144
145
  // The buffer size includes space for the trailing NUL, so we can read at most
146
  // one fewer byte.
147
300k
  BUF_MEM *b = reinterpret_cast<BUF_MEM *>(bio->ptr);
148
300k
  int ret = size - 1;
149
300k
  if ((size_t)ret > b->length) {
150
68.4k
    ret = (int)b->length;
151
68.4k
  }
152
153
  // Stop at the first newline.
154
300k
  const char *newline =
155
300k
      reinterpret_cast<char *>(OPENSSL_memchr(b->data, '\n', ret));
156
300k
  if (newline != nullptr) {
157
135k
    ret = (int)(newline - b->data + 1);
158
135k
  }
159
160
300k
  ret = mem_read(bio, buf, ret);
161
300k
  if (ret >= 0) {
162
300k
    buf[ret] = '\0';
163
300k
  }
164
300k
  return ret;
165
300k
}
166
167
167k
static long mem_ctrl(BIO *bio, int cmd, long num, void *ptr) {
168
167k
  BUF_MEM *b = static_cast<BUF_MEM *>(bio->ptr);
169
167k
  switch (cmd) {
170
0
    case BIO_CTRL_RESET:
171
0
      if (b->data != nullptr) {
172
        // For read only case reset to the start again
173
0
        if (bio->flags & BIO_FLAGS_MEM_RDONLY) {
174
0
          b->data -= b->max - b->length;
175
0
          b->length = b->max;
176
0
        } else {
177
0
          OPENSSL_memset(b->data, 0, b->max);
178
0
          b->length = 0;
179
0
        }
180
0
      }
181
0
      return 1;
182
0
    case BIO_CTRL_EOF:
183
0
      return b->length == 0;
184
0
    case BIO_C_SET_BUF_MEM_EOF_RETURN:
185
0
      bio->num = static_cast<int>(num);
186
0
      return 1;
187
0
    case BIO_CTRL_INFO:
188
0
      if (ptr != nullptr) {
189
0
        char **out = reinterpret_cast<char **>(ptr);
190
0
        *out = b->data;
191
0
      }
192
      // This API can overflow on 64-bit Windows, where |long| is smaller than
193
      // |ptrdiff_t|. |BIO_mem_contents| is the overflow-safe API.
194
0
      return static_cast<long>(b->length);
195
0
    case BIO_C_SET_BUF_MEM:
196
0
      mem_free(bio);
197
0
      bio->shutdown = static_cast<int>(num);
198
0
      bio->ptr = ptr;
199
0
      return 1;
200
0
    case BIO_C_GET_BUF_MEM_PTR:
201
0
      if (ptr != nullptr) {
202
0
        BUF_MEM **out = reinterpret_cast<BUF_MEM **>(ptr);
203
0
        *out = b;
204
0
      }
205
0
      return 1;
206
0
    case BIO_CTRL_GET_CLOSE:
207
0
      return bio->shutdown;
208
0
    case BIO_CTRL_SET_CLOSE:
209
0
      bio->shutdown = static_cast<int>(num);
210
0
      return 1;
211
0
    case BIO_CTRL_WPENDING:
212
0
      return 0;
213
0
    case BIO_CTRL_PENDING:
214
      // TODO(crbug.com/412584975): This can overflow on 64-bit Windows.
215
0
      return static_cast<long>(b->length);
216
147k
    case BIO_CTRL_FLUSH:
217
147k
      return 1;
218
20.1k
    default:
219
20.1k
      return 0;
220
167k
  }
221
167k
}
222
223
static const BIO_METHOD mem_method = {
224
    BIO_TYPE_MEM, "memory buffer", mem_write,
225
    mem_read,     mem_gets,        mem_ctrl,
226
    mem_new,      mem_free,        /*callback_ctrl=*/nullptr,
227
};
228
229
49.0k
const BIO_METHOD *BIO_s_mem(void) { return &mem_method; }
230
231
int BIO_mem_contents(const BIO *bio, const uint8_t **out_contents,
232
0
                     size_t *out_len) {
233
0
  const BUF_MEM *b;
234
0
  if (bio->method != &mem_method) {
235
0
    return 0;
236
0
  }
237
238
0
  b = (BUF_MEM *)bio->ptr;
239
0
  *out_contents = (uint8_t *)b->data;
240
0
  *out_len = b->length;
241
0
  return 1;
242
0
}
243
244
0
long BIO_get_mem_data(BIO *bio, char **contents) {
245
0
  return BIO_ctrl(bio, BIO_CTRL_INFO, 0, contents);
246
0
}
247
248
0
int BIO_get_mem_ptr(BIO *bio, BUF_MEM **out) {
249
0
  return (int)BIO_ctrl(bio, BIO_C_GET_BUF_MEM_PTR, 0, out);
250
0
}
251
252
0
int BIO_set_mem_buf(BIO *bio, BUF_MEM *b, int take_ownership) {
253
0
  return (int)BIO_ctrl(bio, BIO_C_SET_BUF_MEM, take_ownership, b);
254
0
}
255
256
0
int BIO_set_mem_eof_return(BIO *bio, int eof_value) {
257
0
  return (int)BIO_ctrl(bio, BIO_C_SET_BUF_MEM_EOF_RETURN, eof_value, nullptr);
258
0
}