1 | /*
|
---|
2 | * Copyright 2022-2023 The OpenSSL Project Authors. All Rights Reserved.
|
---|
3 | *
|
---|
4 | * Licensed under the Apache License 2.0 (the "License"). You may not use
|
---|
5 | * this file except in compliance with the License. You can obtain a copy
|
---|
6 | * in the file LICENSE in the source distribution or at
|
---|
7 | * https://www.openssl.org/source/license.html
|
---|
8 | */
|
---|
9 |
|
---|
10 | #include <stdio.h>
|
---|
11 | #include <errno.h>
|
---|
12 | #include "bio_local.h"
|
---|
13 | #include "internal/cryptlib.h"
|
---|
14 | #include "internal/safe_math.h"
|
---|
15 |
|
---|
16 | #if !defined(OPENSSL_NO_DGRAM) && !defined(OPENSSL_NO_SOCK)
|
---|
17 |
|
---|
18 | OSSL_SAFE_MATH_UNSIGNED(size_t, size_t)
|
---|
19 |
|
---|
20 | /* ===========================================================================
|
---|
21 | * Byte-wise ring buffer which supports pushing and popping blocks of multiple
|
---|
22 | * bytes at a time.
|
---|
23 | */
|
---|
24 | struct ring_buf {
|
---|
25 | unsigned char *start; /* start of buffer */
|
---|
26 | size_t len; /* size of buffer allocation in bytes */
|
---|
27 | size_t count; /* number of bytes currently pushed */
|
---|
28 | /*
|
---|
29 | * These index into start. Where idx[0] == idx[1], the buffer is full
|
---|
30 | * (if count is nonzero) and empty otherwise.
|
---|
31 | */
|
---|
32 | size_t idx[2]; /* 0: head, 1: tail */
|
---|
33 | };
|
---|
34 |
|
---|
35 | static int ring_buf_init(struct ring_buf *r, size_t nbytes)
|
---|
36 | {
|
---|
37 | r->start = OPENSSL_malloc(nbytes);
|
---|
38 | if (r->start == NULL)
|
---|
39 | return 0;
|
---|
40 |
|
---|
41 | r->len = nbytes;
|
---|
42 | r->idx[0] = r->idx[1] = r->count = 0;
|
---|
43 | return 1;
|
---|
44 | }
|
---|
45 |
|
---|
46 | static void ring_buf_destroy(struct ring_buf *r)
|
---|
47 | {
|
---|
48 | OPENSSL_free(r->start);
|
---|
49 | r->start = NULL;
|
---|
50 | r->len = 0;
|
---|
51 | r->count = 0;
|
---|
52 | }
|
---|
53 |
|
---|
54 | /*
|
---|
55 | * Get a pointer to the next place to write data to be pushed to the ring buffer
|
---|
56 | * (idx=0), or the next data to be popped from the ring buffer (idx=1). The
|
---|
57 | * pointer is written to *buf and the maximum number of bytes which can be
|
---|
58 | * read/written are written to *len. After writing data to the buffer, call
|
---|
59 | * ring_buf_push/pop() with the number of bytes actually read/written, which
|
---|
60 | * must not exceed the returned length.
|
---|
61 | */
|
---|
62 | static void ring_buf_head_tail(struct ring_buf *r, int idx, uint8_t **buf, size_t *len)
|
---|
63 | {
|
---|
64 | size_t max_len = r->len - r->idx[idx];
|
---|
65 |
|
---|
66 | if (idx == 0 && max_len > r->len - r->count)
|
---|
67 | max_len = r->len - r->count;
|
---|
68 | if (idx == 1 && max_len > r->count)
|
---|
69 | max_len = r->count;
|
---|
70 |
|
---|
71 | *buf = (uint8_t *)r->start + r->idx[idx];
|
---|
72 | *len = max_len;
|
---|
73 | }
|
---|
74 |
|
---|
75 | #define ring_buf_head(r, buf, len) ring_buf_head_tail((r), 0, (buf), (len))
|
---|
76 | #define ring_buf_tail(r, buf, len) ring_buf_head_tail((r), 1, (buf), (len))
|
---|
77 |
|
---|
78 | /*
|
---|
79 | * Commit bytes to the ring buffer previously filled after a call to
|
---|
80 | * ring_buf_head().
|
---|
81 | */
|
---|
82 | static void ring_buf_push_pop(struct ring_buf *r, int idx, size_t num_bytes)
|
---|
83 | {
|
---|
84 | size_t new_idx;
|
---|
85 |
|
---|
86 | /* A single push/pop op cannot wrap around, though it can reach the end.
|
---|
87 | * If the caller adheres to the convention of using the length returned
|
---|
88 | * by ring_buf_head/tail(), this cannot happen.
|
---|
89 | */
|
---|
90 | if (!ossl_assert(num_bytes <= r->len - r->idx[idx]))
|
---|
91 | return;
|
---|
92 |
|
---|
93 | /*
|
---|
94 | * Must not overfill the buffer, or pop more than is in the buffer either.
|
---|
95 | */
|
---|
96 | if (!ossl_assert(idx != 0 ? num_bytes <= r->count
|
---|
97 | : num_bytes + r->count <= r->len))
|
---|
98 | return;
|
---|
99 |
|
---|
100 | /* Update the index. */
|
---|
101 | new_idx = r->idx[idx] + num_bytes;
|
---|
102 | if (new_idx == r->len)
|
---|
103 | new_idx = 0;
|
---|
104 |
|
---|
105 | r->idx[idx] = new_idx;
|
---|
106 | if (idx != 0)
|
---|
107 | r->count -= num_bytes;
|
---|
108 | else
|
---|
109 | r->count += num_bytes;
|
---|
110 | }
|
---|
111 |
|
---|
112 | #define ring_buf_push(r, num_bytes) ring_buf_push_pop((r), 0, (num_bytes))
|
---|
113 | #define ring_buf_pop(r, num_bytes) ring_buf_push_pop((r), 1, (num_bytes))
|
---|
114 |
|
---|
115 | static void ring_buf_clear(struct ring_buf *r)
|
---|
116 | {
|
---|
117 | r->idx[0] = r->idx[1] = r->count = 0;
|
---|
118 | }
|
---|
119 |
|
---|
120 | static int ring_buf_resize(struct ring_buf *r, size_t nbytes)
|
---|
121 | {
|
---|
122 | unsigned char *new_start;
|
---|
123 |
|
---|
124 | if (r->start == NULL)
|
---|
125 | return ring_buf_init(r, nbytes);
|
---|
126 |
|
---|
127 | if (nbytes == r->len)
|
---|
128 | return 1;
|
---|
129 |
|
---|
130 | if (r->count > 0 && nbytes < r->len)
|
---|
131 | /* fail shrinking the ring buffer when there is any data in it */
|
---|
132 | return 0;
|
---|
133 |
|
---|
134 | new_start = OPENSSL_realloc(r->start, nbytes);
|
---|
135 | if (new_start == NULL)
|
---|
136 | return 0;
|
---|
137 |
|
---|
138 | /* Moving tail if it is after (or equal to) head */
|
---|
139 | if (r->count > 0) {
|
---|
140 | if (r->idx[0] <= r->idx[1]) {
|
---|
141 | size_t offset = nbytes - r->len;
|
---|
142 |
|
---|
143 | memmove(new_start + r->idx[1] + offset, new_start + r->idx[1],
|
---|
144 | r->len - r->idx[1]);
|
---|
145 | r->idx[1] += offset;
|
---|
146 | }
|
---|
147 | } else {
|
---|
148 | /* just reset the head/tail because it might be pointing outside */
|
---|
149 | r->idx[0] = r->idx[1] = 0;
|
---|
150 | }
|
---|
151 |
|
---|
152 | r->start = new_start;
|
---|
153 | r->len = nbytes;
|
---|
154 |
|
---|
155 | return 1;
|
---|
156 | }
|
---|
157 |
|
---|
158 | /* ===========================================================================
|
---|
159 | * BIO_s_dgram_pair is documented in BIO_s_dgram_pair(3).
|
---|
160 | *
|
---|
161 | * INTERNAL DATA STRUCTURE
|
---|
162 | *
|
---|
163 | * This is managed internally by using a bytewise ring buffer which supports
|
---|
164 | * pushing and popping spans of multiple bytes at once. The ring buffer stores
|
---|
165 | * internal packets which look like this:
|
---|
166 | *
|
---|
167 | * struct dgram_hdr hdr;
|
---|
168 | * uint8_t data[];
|
---|
169 | *
|
---|
170 | * The header contains the length of the data and metadata such as
|
---|
171 | * source/destination addresses.
|
---|
172 | *
|
---|
173 | * The datagram pair BIO is designed to support both traditional
|
---|
174 | * BIO_read/BIO_write (likely to be used by applications) as well as
|
---|
175 | * BIO_recvmmsg/BIO_sendmmsg.
|
---|
176 | */
|
---|
177 | struct bio_dgram_pair_st;
|
---|
178 | static int dgram_pair_write(BIO *bio, const char *buf, int sz_);
|
---|
179 | static int dgram_pair_read(BIO *bio, char *buf, int sz_);
|
---|
180 | static int dgram_mem_read(BIO *bio, char *buf, int sz_);
|
---|
181 | static long dgram_pair_ctrl(BIO *bio, int cmd, long num, void *ptr);
|
---|
182 | static long dgram_mem_ctrl(BIO *bio, int cmd, long num, void *ptr);
|
---|
183 | static int dgram_pair_init(BIO *bio);
|
---|
184 | static int dgram_mem_init(BIO *bio);
|
---|
185 | static int dgram_pair_free(BIO *bio);
|
---|
186 | static int dgram_pair_sendmmsg(BIO *b, BIO_MSG *msg, size_t stride,
|
---|
187 | size_t num_msg, uint64_t flags,
|
---|
188 | size_t *num_processed);
|
---|
189 | static int dgram_pair_recvmmsg(BIO *b, BIO_MSG *msg, size_t stride,
|
---|
190 | size_t num_msg, uint64_t flags,
|
---|
191 | size_t *num_processed);
|
---|
192 |
|
---|
193 | static int dgram_pair_ctrl_destroy_bio_pair(BIO *bio1);
|
---|
194 | static size_t dgram_pair_read_inner(struct bio_dgram_pair_st *b, uint8_t *buf,
|
---|
195 | size_t sz);
|
---|
196 |
|
---|
197 | #define BIO_MSG_N(array, n) (*(BIO_MSG *)((char *)(array) + (n)*stride))
|
---|
198 |
|
---|
199 | static const BIO_METHOD dgram_pair_method = {
|
---|
200 | BIO_TYPE_DGRAM_PAIR,
|
---|
201 | "BIO dgram pair",
|
---|
202 | bwrite_conv,
|
---|
203 | dgram_pair_write,
|
---|
204 | bread_conv,
|
---|
205 | dgram_pair_read,
|
---|
206 | NULL, /* dgram_pair_puts */
|
---|
207 | NULL, /* dgram_pair_gets */
|
---|
208 | dgram_pair_ctrl,
|
---|
209 | dgram_pair_init,
|
---|
210 | dgram_pair_free,
|
---|
211 | NULL, /* dgram_pair_callback_ctrl */
|
---|
212 | dgram_pair_sendmmsg,
|
---|
213 | dgram_pair_recvmmsg,
|
---|
214 | };
|
---|
215 |
|
---|
216 | static const BIO_METHOD dgram_mem_method = {
|
---|
217 | BIO_TYPE_DGRAM_MEM,
|
---|
218 | "BIO dgram mem",
|
---|
219 | bwrite_conv,
|
---|
220 | dgram_pair_write,
|
---|
221 | bread_conv,
|
---|
222 | dgram_mem_read,
|
---|
223 | NULL, /* dgram_pair_puts */
|
---|
224 | NULL, /* dgram_pair_gets */
|
---|
225 | dgram_mem_ctrl,
|
---|
226 | dgram_mem_init,
|
---|
227 | dgram_pair_free,
|
---|
228 | NULL, /* dgram_pair_callback_ctrl */
|
---|
229 | dgram_pair_sendmmsg,
|
---|
230 | dgram_pair_recvmmsg,
|
---|
231 | };
|
---|
232 |
|
---|
233 | const BIO_METHOD *BIO_s_dgram_pair(void)
|
---|
234 | {
|
---|
235 | return &dgram_pair_method;
|
---|
236 | }
|
---|
237 |
|
---|
238 | const BIO_METHOD *BIO_s_dgram_mem(void)
|
---|
239 | {
|
---|
240 | return &dgram_mem_method;
|
---|
241 | }
|
---|
242 |
|
---|
243 | struct dgram_hdr {
|
---|
244 | size_t len; /* payload length in bytes, not including this struct */
|
---|
245 | BIO_ADDR src_addr, dst_addr; /* family == 0: not present */
|
---|
246 | };
|
---|
247 |
|
---|
248 | struct bio_dgram_pair_st {
|
---|
249 | /* The other half of the BIO pair. NULL for dgram_mem. */
|
---|
250 | BIO *peer;
|
---|
251 | /* Writes are directed to our own ringbuf and reads to our peer. */
|
---|
252 | struct ring_buf rbuf;
|
---|
253 | /* Requested size of rbuf buffer in bytes once we initialize. */
|
---|
254 | size_t req_buf_len;
|
---|
255 | /* Largest possible datagram size */
|
---|
256 | size_t mtu;
|
---|
257 | /* Capability flags. */
|
---|
258 | uint32_t cap;
|
---|
259 | /*
|
---|
260 | * This lock protects updates to our rbuf. Since writes are directed to our
|
---|
261 | * own rbuf, this means we use this lock for writes and our peer's lock for
|
---|
262 | * reads.
|
---|
263 | */
|
---|
264 | CRYPTO_RWLOCK *lock;
|
---|
265 | unsigned int no_trunc : 1; /* Reads fail if they would truncate */
|
---|
266 | unsigned int local_addr_enable : 1; /* Can use BIO_MSG->local? */
|
---|
267 | unsigned int role : 1; /* Determines lock order */
|
---|
268 | unsigned int grows_on_write : 1; /* Set for BIO_s_dgram_mem only */
|
---|
269 | };
|
---|
270 |
|
---|
271 | #define MIN_BUF_LEN (1024)
|
---|
272 |
|
---|
273 | #define is_dgram_pair(b) (b->peer != NULL)
|
---|
274 |
|
---|
275 | static int dgram_pair_init(BIO *bio)
|
---|
276 | {
|
---|
277 | struct bio_dgram_pair_st *b = OPENSSL_zalloc(sizeof(*b));
|
---|
278 |
|
---|
279 | if (b == NULL)
|
---|
280 | return 0;
|
---|
281 |
|
---|
282 | b->mtu = 1472; /* conservative default MTU */
|
---|
283 | /* default buffer size */
|
---|
284 | b->req_buf_len = 9 * (sizeof(struct dgram_hdr) + b->mtu);
|
---|
285 |
|
---|
286 | b->lock = CRYPTO_THREAD_lock_new();
|
---|
287 | if (b->lock == NULL) {
|
---|
288 | OPENSSL_free(b);
|
---|
289 | return 0;
|
---|
290 | }
|
---|
291 |
|
---|
292 | bio->ptr = b;
|
---|
293 | return 1;
|
---|
294 | }
|
---|
295 |
|
---|
296 | static int dgram_mem_init(BIO *bio)
|
---|
297 | {
|
---|
298 | struct bio_dgram_pair_st *b;
|
---|
299 |
|
---|
300 | if (!dgram_pair_init(bio))
|
---|
301 | return 0;
|
---|
302 |
|
---|
303 | b = bio->ptr;
|
---|
304 |
|
---|
305 | if (ring_buf_init(&b->rbuf, b->req_buf_len) == 0) {
|
---|
306 | ERR_raise(ERR_LIB_BIO, ERR_R_BIO_LIB);
|
---|
307 | return 0;
|
---|
308 | }
|
---|
309 |
|
---|
310 | b->grows_on_write = 1;
|
---|
311 |
|
---|
312 | bio->init = 1;
|
---|
313 | return 1;
|
---|
314 | }
|
---|
315 |
|
---|
316 | static int dgram_pair_free(BIO *bio)
|
---|
317 | {
|
---|
318 | struct bio_dgram_pair_st *b;
|
---|
319 |
|
---|
320 | if (bio == NULL)
|
---|
321 | return 0;
|
---|
322 |
|
---|
323 | b = bio->ptr;
|
---|
324 | if (!ossl_assert(b != NULL))
|
---|
325 | return 0;
|
---|
326 |
|
---|
327 | /* We are being freed. Disconnect any peer and destroy buffers. */
|
---|
328 | dgram_pair_ctrl_destroy_bio_pair(bio);
|
---|
329 |
|
---|
330 | CRYPTO_THREAD_lock_free(b->lock);
|
---|
331 | OPENSSL_free(b);
|
---|
332 | return 1;
|
---|
333 | }
|
---|
334 |
|
---|
335 | /* BIO_make_bio_pair (BIO_C_MAKE_BIO_PAIR) */
|
---|
336 | static int dgram_pair_ctrl_make_bio_pair(BIO *bio1, BIO *bio2)
|
---|
337 | {
|
---|
338 | struct bio_dgram_pair_st *b1, *b2;
|
---|
339 |
|
---|
340 | /* peer must be non-NULL. */
|
---|
341 | if (bio1 == NULL || bio2 == NULL) {
|
---|
342 | ERR_raise(ERR_LIB_BIO, BIO_R_INVALID_ARGUMENT);
|
---|
343 | return 0;
|
---|
344 | }
|
---|
345 |
|
---|
346 | /* Ensure the BIO we have been passed is actually a dgram pair BIO. */
|
---|
347 | if (bio1->method != &dgram_pair_method || bio2->method != &dgram_pair_method) {
|
---|
348 | ERR_raise_data(ERR_LIB_BIO, BIO_R_INVALID_ARGUMENT,
|
---|
349 | "both BIOs must be BIO_dgram_pair");
|
---|
350 | return 0;
|
---|
351 | }
|
---|
352 |
|
---|
353 | b1 = bio1->ptr;
|
---|
354 | b2 = bio2->ptr;
|
---|
355 |
|
---|
356 | if (!ossl_assert(b1 != NULL && b2 != NULL)) {
|
---|
357 | ERR_raise(ERR_LIB_BIO, BIO_R_UNINITIALIZED);
|
---|
358 | return 0;
|
---|
359 | }
|
---|
360 |
|
---|
361 | /*
|
---|
362 | * This ctrl cannot be used to associate a BIO pair half which is already
|
---|
363 | * associated.
|
---|
364 | */
|
---|
365 | if (b1->peer != NULL || b2->peer != NULL) {
|
---|
366 | ERR_raise_data(ERR_LIB_BIO, BIO_R_IN_USE,
|
---|
367 | "cannot associate a BIO_dgram_pair which is already in use");
|
---|
368 | return 0;
|
---|
369 | }
|
---|
370 |
|
---|
371 | if (!ossl_assert(b1->req_buf_len >= MIN_BUF_LEN
|
---|
372 | && b2->req_buf_len >= MIN_BUF_LEN)) {
|
---|
373 | ERR_raise(ERR_LIB_BIO, BIO_R_UNINITIALIZED);
|
---|
374 | return 0;
|
---|
375 | }
|
---|
376 |
|
---|
377 | if (b1->rbuf.len != b1->req_buf_len)
|
---|
378 | if (ring_buf_init(&b1->rbuf, b1->req_buf_len) == 0) {
|
---|
379 | ERR_raise(ERR_LIB_BIO, ERR_R_BIO_LIB);
|
---|
380 | return 0;
|
---|
381 | }
|
---|
382 |
|
---|
383 | if (b2->rbuf.len != b2->req_buf_len)
|
---|
384 | if (ring_buf_init(&b2->rbuf, b2->req_buf_len) == 0) {
|
---|
385 | ERR_raise(ERR_LIB_BIO, ERR_R_BIO_LIB);
|
---|
386 | ring_buf_destroy(&b1->rbuf);
|
---|
387 | return 0;
|
---|
388 | }
|
---|
389 |
|
---|
390 | b1->peer = bio2;
|
---|
391 | b2->peer = bio1;
|
---|
392 | b1->role = 0;
|
---|
393 | b2->role = 1;
|
---|
394 | bio1->init = 1;
|
---|
395 | bio2->init = 1;
|
---|
396 | return 1;
|
---|
397 | }
|
---|
398 |
|
---|
399 | /* BIO_destroy_bio_pair (BIO_C_DESTROY_BIO_PAIR) */
|
---|
400 | static int dgram_pair_ctrl_destroy_bio_pair(BIO *bio1)
|
---|
401 | {
|
---|
402 | BIO *bio2;
|
---|
403 | struct bio_dgram_pair_st *b1 = bio1->ptr, *b2;
|
---|
404 |
|
---|
405 | ring_buf_destroy(&b1->rbuf);
|
---|
406 | bio1->init = 0;
|
---|
407 |
|
---|
408 | /* Early return if we don't have a peer. */
|
---|
409 | if (b1->peer == NULL)
|
---|
410 | return 1;
|
---|
411 |
|
---|
412 | bio2 = b1->peer;
|
---|
413 | b2 = bio2->ptr;
|
---|
414 |
|
---|
415 | /* Invariant. */
|
---|
416 | if (!ossl_assert(b2->peer == bio1))
|
---|
417 | return 0;
|
---|
418 |
|
---|
419 | /* Free buffers. */
|
---|
420 | ring_buf_destroy(&b2->rbuf);
|
---|
421 |
|
---|
422 | bio2->init = 0;
|
---|
423 | b1->peer = NULL;
|
---|
424 | b2->peer = NULL;
|
---|
425 | return 1;
|
---|
426 | }
|
---|
427 |
|
---|
428 | /* BIO_eof (BIO_CTRL_EOF) */
|
---|
429 | static int dgram_pair_ctrl_eof(BIO *bio)
|
---|
430 | {
|
---|
431 | struct bio_dgram_pair_st *b = bio->ptr, *peerb;
|
---|
432 |
|
---|
433 | if (!ossl_assert(b != NULL))
|
---|
434 | return -1;
|
---|
435 |
|
---|
436 | /* If we aren't initialized, we can never read anything */
|
---|
437 | if (!bio->init)
|
---|
438 | return 1;
|
---|
439 | if (!is_dgram_pair(b))
|
---|
440 | return 0;
|
---|
441 |
|
---|
442 |
|
---|
443 | peerb = b->peer->ptr;
|
---|
444 | if (!ossl_assert(peerb != NULL))
|
---|
445 | return -1;
|
---|
446 |
|
---|
447 | /*
|
---|
448 | * Since we are emulating datagram semantics, never indicate EOF so long as
|
---|
449 | * we have a peer.
|
---|
450 | */
|
---|
451 | return 0;
|
---|
452 | }
|
---|
453 |
|
---|
454 | /* BIO_set_write_buf_size (BIO_C_SET_WRITE_BUF_SIZE) */
|
---|
455 | static int dgram_pair_ctrl_set_write_buf_size(BIO *bio, size_t len)
|
---|
456 | {
|
---|
457 | struct bio_dgram_pair_st *b = bio->ptr;
|
---|
458 |
|
---|
459 | /* Changing buffer sizes is not permitted while a peer is connected. */
|
---|
460 | if (b->peer != NULL) {
|
---|
461 | ERR_raise(ERR_LIB_BIO, BIO_R_IN_USE);
|
---|
462 | return 0;
|
---|
463 | }
|
---|
464 |
|
---|
465 | /* Enforce minimum size. */
|
---|
466 | if (len < MIN_BUF_LEN)
|
---|
467 | len = MIN_BUF_LEN;
|
---|
468 |
|
---|
469 | if (b->rbuf.start != NULL) {
|
---|
470 | if (!ring_buf_resize(&b->rbuf, len))
|
---|
471 | return 0;
|
---|
472 | }
|
---|
473 |
|
---|
474 | b->req_buf_len = len;
|
---|
475 | b->grows_on_write = 0;
|
---|
476 | return 1;
|
---|
477 | }
|
---|
478 |
|
---|
479 | /* BIO_reset (BIO_CTRL_RESET) */
|
---|
480 | static int dgram_pair_ctrl_reset(BIO *bio)
|
---|
481 | {
|
---|
482 | struct bio_dgram_pair_st *b = bio->ptr;
|
---|
483 |
|
---|
484 | ring_buf_clear(&b->rbuf);
|
---|
485 | return 1;
|
---|
486 | }
|
---|
487 |
|
---|
488 | /* BIO_pending (BIO_CTRL_PENDING) (Threadsafe) */
|
---|
489 | static size_t dgram_pair_ctrl_pending(BIO *bio)
|
---|
490 | {
|
---|
491 | size_t saved_idx, saved_count;
|
---|
492 | struct bio_dgram_pair_st *b = bio->ptr, *readb;
|
---|
493 | struct dgram_hdr hdr;
|
---|
494 | size_t l;
|
---|
495 |
|
---|
496 | /* Safe to check; init may not change during this call */
|
---|
497 | if (!bio->init)
|
---|
498 | return 0;
|
---|
499 | if (is_dgram_pair(b))
|
---|
500 | readb = b->peer->ptr;
|
---|
501 | else
|
---|
502 | readb = b;
|
---|
503 |
|
---|
504 | if (CRYPTO_THREAD_write_lock(readb->lock) == 0)
|
---|
505 | return 0;
|
---|
506 |
|
---|
507 | saved_idx = readb->rbuf.idx[1];
|
---|
508 | saved_count = readb->rbuf.count;
|
---|
509 |
|
---|
510 | l = dgram_pair_read_inner(readb, (uint8_t *)&hdr, sizeof(hdr));
|
---|
511 |
|
---|
512 | readb->rbuf.idx[1] = saved_idx;
|
---|
513 | readb->rbuf.count = saved_count;
|
---|
514 |
|
---|
515 | CRYPTO_THREAD_unlock(readb->lock);
|
---|
516 |
|
---|
517 | if (!ossl_assert(l == 0 || l == sizeof(hdr)))
|
---|
518 | return 0;
|
---|
519 |
|
---|
520 | return l > 0 ? hdr.len : 0;
|
---|
521 | }
|
---|
522 |
|
---|
523 | /* BIO_get_write_guarantee (BIO_C_GET_WRITE_GUARANTEE) (Threadsafe) */
|
---|
524 | static size_t dgram_pair_ctrl_get_write_guarantee(BIO *bio)
|
---|
525 | {
|
---|
526 | size_t l;
|
---|
527 | struct bio_dgram_pair_st *b = bio->ptr;
|
---|
528 |
|
---|
529 | if (CRYPTO_THREAD_read_lock(b->lock) == 0)
|
---|
530 | return 0;
|
---|
531 |
|
---|
532 | l = b->rbuf.len - b->rbuf.count;
|
---|
533 | if (l >= sizeof(struct dgram_hdr))
|
---|
534 | l -= sizeof(struct dgram_hdr);
|
---|
535 |
|
---|
536 | /*
|
---|
537 | * If the amount of buffer space would not be enough to accommodate the
|
---|
538 | * worst-case size of a datagram, report no space available.
|
---|
539 | */
|
---|
540 | if (l < b->mtu)
|
---|
541 | l = 0;
|
---|
542 |
|
---|
543 | CRYPTO_THREAD_unlock(b->lock);
|
---|
544 | return l;
|
---|
545 | }
|
---|
546 |
|
---|
547 | /* BIO_dgram_get_local_addr_cap (BIO_CTRL_DGRAM_GET_LOCAL_ADDR_CAP) */
|
---|
548 | static int dgram_pair_ctrl_get_local_addr_cap(BIO *bio)
|
---|
549 | {
|
---|
550 | struct bio_dgram_pair_st *b = bio->ptr, *readb;
|
---|
551 |
|
---|
552 | if (!bio->init)
|
---|
553 | return 0;
|
---|
554 |
|
---|
555 | if (is_dgram_pair(b))
|
---|
556 | readb = b->peer->ptr;
|
---|
557 | else
|
---|
558 | readb = b;
|
---|
559 |
|
---|
560 | return (~readb->cap & (BIO_DGRAM_CAP_HANDLES_SRC_ADDR
|
---|
561 | | BIO_DGRAM_CAP_PROVIDES_DST_ADDR)) == 0;
|
---|
562 | }
|
---|
563 |
|
---|
564 | /* BIO_dgram_get_effective_caps (BIO_CTRL_DGRAM_GET_EFFECTIVE_CAPS) */
|
---|
565 | static int dgram_pair_ctrl_get_effective_caps(BIO *bio)
|
---|
566 | {
|
---|
567 | struct bio_dgram_pair_st *b = bio->ptr, *peerb;
|
---|
568 |
|
---|
569 | if (b->peer == NULL)
|
---|
570 | return 0;
|
---|
571 |
|
---|
572 | peerb = b->peer->ptr;
|
---|
573 |
|
---|
574 | return peerb->cap;
|
---|
575 | }
|
---|
576 |
|
---|
577 | /* BIO_dgram_get_caps (BIO_CTRL_DGRAM_GET_CAPS) */
|
---|
578 | static uint32_t dgram_pair_ctrl_get_caps(BIO *bio)
|
---|
579 | {
|
---|
580 | struct bio_dgram_pair_st *b = bio->ptr;
|
---|
581 |
|
---|
582 | return b->cap;
|
---|
583 | }
|
---|
584 |
|
---|
585 | /* BIO_dgram_set_caps (BIO_CTRL_DGRAM_SET_CAPS) */
|
---|
586 | static int dgram_pair_ctrl_set_caps(BIO *bio, uint32_t caps)
|
---|
587 | {
|
---|
588 | struct bio_dgram_pair_st *b = bio->ptr;
|
---|
589 |
|
---|
590 | b->cap = caps;
|
---|
591 | return 1;
|
---|
592 | }
|
---|
593 |
|
---|
594 | /* BIO_dgram_get_local_addr_enable (BIO_CTRL_DGRAM_GET_LOCAL_ADDR_ENABLE) */
|
---|
595 | static int dgram_pair_ctrl_get_local_addr_enable(BIO *bio)
|
---|
596 | {
|
---|
597 | struct bio_dgram_pair_st *b = bio->ptr;
|
---|
598 |
|
---|
599 | return b->local_addr_enable;
|
---|
600 | }
|
---|
601 |
|
---|
602 | /* BIO_dgram_set_local_addr_enable (BIO_CTRL_DGRAM_SET_LOCAL_ADDR_ENABLE) */
|
---|
603 | static int dgram_pair_ctrl_set_local_addr_enable(BIO *bio, int enable)
|
---|
604 | {
|
---|
605 | struct bio_dgram_pair_st *b = bio->ptr;
|
---|
606 |
|
---|
607 | if (dgram_pair_ctrl_get_local_addr_cap(bio) == 0)
|
---|
608 | return 0;
|
---|
609 |
|
---|
610 | b->local_addr_enable = (enable != 0 ? 1 : 0);
|
---|
611 | return 1;
|
---|
612 | }
|
---|
613 |
|
---|
614 | /* BIO_dgram_get_mtu (BIO_CTRL_DGRAM_GET_MTU) */
|
---|
615 | static int dgram_pair_ctrl_get_mtu(BIO *bio)
|
---|
616 | {
|
---|
617 | struct bio_dgram_pair_st *b = bio->ptr;
|
---|
618 |
|
---|
619 | return b->mtu;
|
---|
620 | }
|
---|
621 |
|
---|
622 | /* BIO_dgram_set_mtu (BIO_CTRL_DGRAM_SET_MTU) */
|
---|
623 | static int dgram_pair_ctrl_set_mtu(BIO *bio, size_t mtu)
|
---|
624 | {
|
---|
625 | struct bio_dgram_pair_st *b = bio->ptr, *peerb;
|
---|
626 |
|
---|
627 | b->mtu = mtu;
|
---|
628 |
|
---|
629 | if (b->peer != NULL) {
|
---|
630 | peerb = b->peer->ptr;
|
---|
631 | peerb->mtu = mtu;
|
---|
632 | }
|
---|
633 |
|
---|
634 | return 1;
|
---|
635 | }
|
---|
636 |
|
---|
637 | /* Partially threadsafe (some commands) */
|
---|
638 | static long dgram_mem_ctrl(BIO *bio, int cmd, long num, void *ptr)
|
---|
639 | {
|
---|
640 | long ret = 1;
|
---|
641 | struct bio_dgram_pair_st *b = bio->ptr;
|
---|
642 |
|
---|
643 | if (!ossl_assert(b != NULL))
|
---|
644 | return 0;
|
---|
645 |
|
---|
646 | switch (cmd) {
|
---|
647 | /*
|
---|
648 | * BIO_set_write_buf_size: Set the size of the ring buffer used for storing
|
---|
649 | * datagrams. No more writes can be performed once the buffer is filled up,
|
---|
650 | * until reads are performed. This cannot be used after a peer is connected.
|
---|
651 | */
|
---|
652 | case BIO_C_SET_WRITE_BUF_SIZE: /* Non-threadsafe */
|
---|
653 | ret = (long)dgram_pair_ctrl_set_write_buf_size(bio, (size_t)num);
|
---|
654 | break;
|
---|
655 |
|
---|
656 | /*
|
---|
657 | * BIO_get_write_buf_size: Get ring buffer size.
|
---|
658 | */
|
---|
659 | case BIO_C_GET_WRITE_BUF_SIZE: /* Non-threadsafe */
|
---|
660 | ret = (long)b->req_buf_len;
|
---|
661 | break;
|
---|
662 |
|
---|
663 | /*
|
---|
664 | * BIO_reset: Clear all data which was written to this side of the pair.
|
---|
665 | */
|
---|
666 | case BIO_CTRL_RESET: /* Non-threadsafe */
|
---|
667 | dgram_pair_ctrl_reset(bio);
|
---|
668 | break;
|
---|
669 |
|
---|
670 | /*
|
---|
671 | * BIO_get_write_guarantee: Any BIO_write providing a buffer less than or
|
---|
672 | * equal to this value is guaranteed to succeed.
|
---|
673 | */
|
---|
674 | case BIO_C_GET_WRITE_GUARANTEE: /* Threadsafe */
|
---|
675 | ret = (long)dgram_pair_ctrl_get_write_guarantee(bio);
|
---|
676 | break;
|
---|
677 |
|
---|
678 | /* BIO_pending: Bytes available to read. */
|
---|
679 | case BIO_CTRL_PENDING: /* Threadsafe */
|
---|
680 | ret = (long)dgram_pair_ctrl_pending(bio);
|
---|
681 | break;
|
---|
682 |
|
---|
683 | /* BIO_flush: No-op. */
|
---|
684 | case BIO_CTRL_FLUSH: /* Threadsafe */
|
---|
685 | break;
|
---|
686 |
|
---|
687 | /* BIO_dgram_get_no_trunc */
|
---|
688 | case BIO_CTRL_DGRAM_GET_NO_TRUNC: /* Non-threadsafe */
|
---|
689 | ret = (long)b->no_trunc;
|
---|
690 | break;
|
---|
691 |
|
---|
692 | /* BIO_dgram_set_no_trunc */
|
---|
693 | case BIO_CTRL_DGRAM_SET_NO_TRUNC: /* Non-threadsafe */
|
---|
694 | b->no_trunc = (num > 0);
|
---|
695 | break;
|
---|
696 |
|
---|
697 | /* BIO_dgram_get_local_addr_enable */
|
---|
698 | case BIO_CTRL_DGRAM_GET_LOCAL_ADDR_ENABLE: /* Non-threadsafe */
|
---|
699 | *(int *)ptr = (int)dgram_pair_ctrl_get_local_addr_enable(bio);
|
---|
700 | break;
|
---|
701 |
|
---|
702 | /* BIO_dgram_set_local_addr_enable */
|
---|
703 | case BIO_CTRL_DGRAM_SET_LOCAL_ADDR_ENABLE: /* Non-threadsafe */
|
---|
704 | ret = (long)dgram_pair_ctrl_set_local_addr_enable(bio, num);
|
---|
705 | break;
|
---|
706 |
|
---|
707 | /* BIO_dgram_get_local_addr_cap: Can local addresses be supported? */
|
---|
708 | case BIO_CTRL_DGRAM_GET_LOCAL_ADDR_CAP: /* Non-threadsafe */
|
---|
709 | ret = (long)dgram_pair_ctrl_get_local_addr_cap(bio);
|
---|
710 | break;
|
---|
711 |
|
---|
712 | /* BIO_dgram_get_effective_caps */
|
---|
713 | case BIO_CTRL_DGRAM_GET_EFFECTIVE_CAPS: /* Non-threadsafe */
|
---|
714 | /* BIO_dgram_get_caps */
|
---|
715 | case BIO_CTRL_DGRAM_GET_CAPS: /* Non-threadsafe */
|
---|
716 | ret = (long)dgram_pair_ctrl_get_caps(bio);
|
---|
717 | break;
|
---|
718 |
|
---|
719 | /* BIO_dgram_set_caps */
|
---|
720 | case BIO_CTRL_DGRAM_SET_CAPS: /* Non-threadsafe */
|
---|
721 | ret = (long)dgram_pair_ctrl_set_caps(bio, (uint32_t)num);
|
---|
722 | break;
|
---|
723 |
|
---|
724 | /* BIO_dgram_get_mtu */
|
---|
725 | case BIO_CTRL_DGRAM_GET_MTU: /* Non-threadsafe */
|
---|
726 | ret = (long)dgram_pair_ctrl_get_mtu(bio);
|
---|
727 | break;
|
---|
728 |
|
---|
729 | /* BIO_dgram_set_mtu */
|
---|
730 | case BIO_CTRL_DGRAM_SET_MTU: /* Non-threadsafe */
|
---|
731 | ret = (long)dgram_pair_ctrl_set_mtu(bio, (uint32_t)num);
|
---|
732 | break;
|
---|
733 |
|
---|
734 | /*
|
---|
735 | * BIO_eof: Returns whether this half of the BIO pair is empty of data to
|
---|
736 | * read.
|
---|
737 | */
|
---|
738 | case BIO_CTRL_EOF: /* Non-threadsafe */
|
---|
739 | ret = (long)dgram_pair_ctrl_eof(bio);
|
---|
740 | break;
|
---|
741 |
|
---|
742 | default:
|
---|
743 | ret = 0;
|
---|
744 | break;
|
---|
745 | }
|
---|
746 |
|
---|
747 | return ret;
|
---|
748 | }
|
---|
749 |
|
---|
750 | static long dgram_pair_ctrl(BIO *bio, int cmd, long num, void *ptr)
|
---|
751 | {
|
---|
752 | long ret = 1;
|
---|
753 |
|
---|
754 | switch (cmd) {
|
---|
755 | /*
|
---|
756 | * BIO_make_bio_pair: this is usually used by BIO_new_dgram_pair, though it
|
---|
757 | * may be used manually after manually creating each half of a BIO pair
|
---|
758 | * using BIO_new. This only needs to be called on one of the BIOs.
|
---|
759 | */
|
---|
760 | case BIO_C_MAKE_BIO_PAIR: /* Non-threadsafe */
|
---|
761 | ret = (long)dgram_pair_ctrl_make_bio_pair(bio, (BIO *)ptr);
|
---|
762 | break;
|
---|
763 |
|
---|
764 | /*
|
---|
765 | * BIO_destroy_bio_pair: Manually disconnect two halves of a BIO pair so
|
---|
766 | * that they are no longer peers.
|
---|
767 | */
|
---|
768 | case BIO_C_DESTROY_BIO_PAIR: /* Non-threadsafe */
|
---|
769 | dgram_pair_ctrl_destroy_bio_pair(bio);
|
---|
770 | break;
|
---|
771 |
|
---|
772 | /* BIO_dgram_get_effective_caps */
|
---|
773 | case BIO_CTRL_DGRAM_GET_EFFECTIVE_CAPS: /* Non-threadsafe */
|
---|
774 | ret = (long)dgram_pair_ctrl_get_effective_caps(bio);
|
---|
775 | break;
|
---|
776 |
|
---|
777 | default:
|
---|
778 | ret = dgram_mem_ctrl(bio, cmd, num, ptr);
|
---|
779 | break;
|
---|
780 | }
|
---|
781 |
|
---|
782 | return ret;
|
---|
783 | }
|
---|
784 |
|
---|
785 | int BIO_new_bio_dgram_pair(BIO **pbio1, size_t writebuf1,
|
---|
786 | BIO **pbio2, size_t writebuf2)
|
---|
787 | {
|
---|
788 | int ret = 0;
|
---|
789 | long r;
|
---|
790 | BIO *bio1 = NULL, *bio2 = NULL;
|
---|
791 |
|
---|
792 | bio1 = BIO_new(BIO_s_dgram_pair());
|
---|
793 | if (bio1 == NULL)
|
---|
794 | goto err;
|
---|
795 |
|
---|
796 | bio2 = BIO_new(BIO_s_dgram_pair());
|
---|
797 | if (bio2 == NULL)
|
---|
798 | goto err;
|
---|
799 |
|
---|
800 | if (writebuf1 > 0) {
|
---|
801 | r = BIO_set_write_buf_size(bio1, writebuf1);
|
---|
802 | if (r == 0)
|
---|
803 | goto err;
|
---|
804 | }
|
---|
805 |
|
---|
806 | if (writebuf2 > 0) {
|
---|
807 | r = BIO_set_write_buf_size(bio2, writebuf2);
|
---|
808 | if (r == 0)
|
---|
809 | goto err;
|
---|
810 | }
|
---|
811 |
|
---|
812 | r = BIO_make_bio_pair(bio1, bio2);
|
---|
813 | if (r == 0)
|
---|
814 | goto err;
|
---|
815 |
|
---|
816 | ret = 1;
|
---|
817 | err:
|
---|
818 | if (ret == 0) {
|
---|
819 | BIO_free(bio1);
|
---|
820 | bio1 = NULL;
|
---|
821 | BIO_free(bio2);
|
---|
822 | bio2 = NULL;
|
---|
823 | }
|
---|
824 |
|
---|
825 | *pbio1 = bio1;
|
---|
826 | *pbio2 = bio2;
|
---|
827 | return ret;
|
---|
828 | }
|
---|
829 |
|
---|
830 | /* Must hold peer write lock */
|
---|
831 | static size_t dgram_pair_read_inner(struct bio_dgram_pair_st *b, uint8_t *buf, size_t sz)
|
---|
832 | {
|
---|
833 | size_t total_read = 0;
|
---|
834 |
|
---|
835 | /*
|
---|
836 | * We repeat pops from the ring buffer for as long as we have more
|
---|
837 | * application *buffer to fill until we fail. We may not be able to pop
|
---|
838 | * enough data to fill the buffer in one operation if the ring buffer wraps
|
---|
839 | * around, but there may still be more data available.
|
---|
840 | */
|
---|
841 | while (sz > 0) {
|
---|
842 | uint8_t *src_buf = NULL;
|
---|
843 | size_t src_len = 0;
|
---|
844 |
|
---|
845 | /*
|
---|
846 | * There are two BIO instances, each with a ringbuf. We read from the
|
---|
847 | * peer ringbuf and write to our own ringbuf.
|
---|
848 | */
|
---|
849 | ring_buf_tail(&b->rbuf, &src_buf, &src_len);
|
---|
850 | if (src_len == 0)
|
---|
851 | break;
|
---|
852 |
|
---|
853 | if (src_len > sz)
|
---|
854 | src_len = sz;
|
---|
855 |
|
---|
856 | if (buf != NULL)
|
---|
857 | memcpy(buf, src_buf, src_len);
|
---|
858 |
|
---|
859 | ring_buf_pop(&b->rbuf, src_len);
|
---|
860 |
|
---|
861 | if (buf != NULL)
|
---|
862 | buf += src_len;
|
---|
863 | total_read += src_len;
|
---|
864 | sz -= src_len;
|
---|
865 | }
|
---|
866 |
|
---|
867 | return total_read;
|
---|
868 | }
|
---|
869 |
|
---|
870 | /*
|
---|
871 | * Must hold peer write lock. Returns number of bytes processed or negated BIO
|
---|
872 | * response code.
|
---|
873 | */
|
---|
874 | static ossl_ssize_t dgram_pair_read_actual(BIO *bio, char *buf, size_t sz,
|
---|
875 | BIO_ADDR *local, BIO_ADDR *peer,
|
---|
876 | int is_multi)
|
---|
877 | {
|
---|
878 | size_t l, trunc = 0, saved_idx, saved_count;
|
---|
879 | struct bio_dgram_pair_st *b = bio->ptr, *readb;
|
---|
880 | struct dgram_hdr hdr;
|
---|
881 |
|
---|
882 | if (!is_multi)
|
---|
883 | BIO_clear_retry_flags(bio);
|
---|
884 |
|
---|
885 | if (!bio->init)
|
---|
886 | return -BIO_R_UNINITIALIZED;
|
---|
887 |
|
---|
888 | if (!ossl_assert(b != NULL))
|
---|
889 | return -BIO_R_TRANSFER_ERROR;
|
---|
890 |
|
---|
891 | if (is_dgram_pair(b))
|
---|
892 | readb = b->peer->ptr;
|
---|
893 | else
|
---|
894 | readb = b;
|
---|
895 | if (!ossl_assert(readb != NULL && readb->rbuf.start != NULL))
|
---|
896 | return -BIO_R_TRANSFER_ERROR;
|
---|
897 |
|
---|
898 | if (sz > 0 && buf == NULL)
|
---|
899 | return -BIO_R_INVALID_ARGUMENT;
|
---|
900 |
|
---|
901 | /* If the caller wants to know the local address, it must be enabled */
|
---|
902 | if (local != NULL && b->local_addr_enable == 0)
|
---|
903 | return -BIO_R_LOCAL_ADDR_NOT_AVAILABLE;
|
---|
904 |
|
---|
905 | /* Read the header. */
|
---|
906 | saved_idx = readb->rbuf.idx[1];
|
---|
907 | saved_count = readb->rbuf.count;
|
---|
908 | l = dgram_pair_read_inner(readb, (uint8_t *)&hdr, sizeof(hdr));
|
---|
909 | if (l == 0) {
|
---|
910 | /* Buffer was empty. */
|
---|
911 | if (!is_multi)
|
---|
912 | BIO_set_retry_read(bio);
|
---|
913 | return -BIO_R_NON_FATAL;
|
---|
914 | }
|
---|
915 |
|
---|
916 | if (!ossl_assert(l == sizeof(hdr)))
|
---|
917 | /*
|
---|
918 | * This should not be possible as headers (and their following payloads)
|
---|
919 | * should always be written atomically.
|
---|
920 | */
|
---|
921 | return -BIO_R_BROKEN_PIPE;
|
---|
922 |
|
---|
923 | if (sz > hdr.len) {
|
---|
924 | sz = hdr.len;
|
---|
925 | } else if (sz < hdr.len) {
|
---|
926 | /* Truncation is occurring. */
|
---|
927 | trunc = hdr.len - sz;
|
---|
928 | if (b->no_trunc) {
|
---|
929 | /* Restore original state. */
|
---|
930 | readb->rbuf.idx[1] = saved_idx;
|
---|
931 | readb->rbuf.count = saved_count;
|
---|
932 | return -BIO_R_NON_FATAL;
|
---|
933 | }
|
---|
934 | }
|
---|
935 |
|
---|
936 | l = dgram_pair_read_inner(readb, (uint8_t *)buf, sz);
|
---|
937 | if (!ossl_assert(l == sz))
|
---|
938 | /* We were somehow not able to read the entire datagram. */
|
---|
939 | return -BIO_R_TRANSFER_ERROR;
|
---|
940 |
|
---|
941 | /*
|
---|
942 | * If the datagram was truncated due to an inadequate buffer, discard the
|
---|
943 | * remainder.
|
---|
944 | */
|
---|
945 | if (trunc > 0 && !ossl_assert(dgram_pair_read_inner(readb, NULL, trunc) == trunc))
|
---|
946 | /* We were somehow not able to read/skip the entire datagram. */
|
---|
947 | return -BIO_R_TRANSFER_ERROR;
|
---|
948 |
|
---|
949 | if (local != NULL)
|
---|
950 | *local = hdr.dst_addr;
|
---|
951 | if (peer != NULL)
|
---|
952 | *peer = hdr.src_addr;
|
---|
953 |
|
---|
954 | return (ossl_ssize_t)l;
|
---|
955 | }
|
---|
956 |
|
---|
957 | /* Threadsafe */
|
---|
958 | static int dgram_pair_lock_both_write(struct bio_dgram_pair_st *a,
|
---|
959 | struct bio_dgram_pair_st *b)
|
---|
960 | {
|
---|
961 | struct bio_dgram_pair_st *x, *y;
|
---|
962 |
|
---|
963 | x = (a->role == 1) ? a : b;
|
---|
964 | y = (a->role == 1) ? b : a;
|
---|
965 |
|
---|
966 | if (!ossl_assert(a->role != b->role))
|
---|
967 | return 0;
|
---|
968 |
|
---|
969 | if (!ossl_assert(a != b && x != y))
|
---|
970 | return 0;
|
---|
971 |
|
---|
972 | if (CRYPTO_THREAD_write_lock(x->lock) == 0)
|
---|
973 | return 0;
|
---|
974 |
|
---|
975 | if (CRYPTO_THREAD_write_lock(y->lock) == 0) {
|
---|
976 | CRYPTO_THREAD_unlock(x->lock);
|
---|
977 | return 0;
|
---|
978 | }
|
---|
979 |
|
---|
980 | return 1;
|
---|
981 | }
|
---|
982 |
|
---|
983 | static void dgram_pair_unlock_both(struct bio_dgram_pair_st *a,
|
---|
984 | struct bio_dgram_pair_st *b)
|
---|
985 | {
|
---|
986 | CRYPTO_THREAD_unlock(a->lock);
|
---|
987 | CRYPTO_THREAD_unlock(b->lock);
|
---|
988 | }
|
---|
989 |
|
---|
990 | /* Threadsafe */
|
---|
991 | static int dgram_pair_read(BIO *bio, char *buf, int sz_)
|
---|
992 | {
|
---|
993 | int ret;
|
---|
994 | ossl_ssize_t l;
|
---|
995 | struct bio_dgram_pair_st *b = bio->ptr, *peerb;
|
---|
996 |
|
---|
997 | if (sz_ < 0) {
|
---|
998 | ERR_raise(ERR_LIB_BIO, BIO_R_INVALID_ARGUMENT);
|
---|
999 | return -1;
|
---|
1000 | }
|
---|
1001 |
|
---|
1002 | if (b->peer == NULL) {
|
---|
1003 | ERR_raise(ERR_LIB_BIO, BIO_R_BROKEN_PIPE);
|
---|
1004 | return -1;
|
---|
1005 | }
|
---|
1006 |
|
---|
1007 | peerb = b->peer->ptr;
|
---|
1008 |
|
---|
1009 | /*
|
---|
1010 | * For BIO_read we have to acquire both locks because we touch the retry
|
---|
1011 | * flags on the local bio. (This is avoided in the recvmmsg case as it does
|
---|
1012 | * not touch the retry flags.)
|
---|
1013 | */
|
---|
1014 | if (dgram_pair_lock_both_write(peerb, b) == 0) {
|
---|
1015 | ERR_raise(ERR_LIB_BIO, ERR_R_UNABLE_TO_GET_WRITE_LOCK);
|
---|
1016 | return -1;
|
---|
1017 | }
|
---|
1018 |
|
---|
1019 | l = dgram_pair_read_actual(bio, buf, (size_t)sz_, NULL, NULL, 0);
|
---|
1020 | if (l < 0) {
|
---|
1021 | if (l != -BIO_R_NON_FATAL)
|
---|
1022 | ERR_raise(ERR_LIB_BIO, -l);
|
---|
1023 | ret = -1;
|
---|
1024 | } else {
|
---|
1025 | ret = (int)l;
|
---|
1026 | }
|
---|
1027 |
|
---|
1028 | dgram_pair_unlock_both(peerb, b);
|
---|
1029 | return ret;
|
---|
1030 | }
|
---|
1031 |
|
---|
1032 | /* Threadsafe */
|
---|
1033 | static int dgram_pair_recvmmsg(BIO *bio, BIO_MSG *msg,
|
---|
1034 | size_t stride, size_t num_msg,
|
---|
1035 | uint64_t flags,
|
---|
1036 | size_t *num_processed)
|
---|
1037 | {
|
---|
1038 | int ret;
|
---|
1039 | ossl_ssize_t l;
|
---|
1040 | BIO_MSG *m;
|
---|
1041 | size_t i;
|
---|
1042 | struct bio_dgram_pair_st *b = bio->ptr, *readb;
|
---|
1043 |
|
---|
1044 | if (num_msg == 0) {
|
---|
1045 | *num_processed = 0;
|
---|
1046 | return 1;
|
---|
1047 | }
|
---|
1048 |
|
---|
1049 | if (!bio->init) {
|
---|
1050 | ERR_raise(ERR_LIB_BIO, BIO_R_BROKEN_PIPE);
|
---|
1051 | *num_processed = 0;
|
---|
1052 | return 0;
|
---|
1053 | }
|
---|
1054 |
|
---|
1055 | if (is_dgram_pair(b))
|
---|
1056 | readb = b->peer->ptr;
|
---|
1057 | else
|
---|
1058 | readb = b;
|
---|
1059 |
|
---|
1060 | if (CRYPTO_THREAD_write_lock(readb->lock) == 0) {
|
---|
1061 | ERR_raise(ERR_LIB_BIO, ERR_R_UNABLE_TO_GET_WRITE_LOCK);
|
---|
1062 | *num_processed = 0;
|
---|
1063 | return 0;
|
---|
1064 | }
|
---|
1065 |
|
---|
1066 | for (i = 0; i < num_msg; ++i) {
|
---|
1067 | m = &BIO_MSG_N(msg, i);
|
---|
1068 | l = dgram_pair_read_actual(bio, m->data, m->data_len,
|
---|
1069 | m->local, m->peer, 1);
|
---|
1070 | if (l < 0) {
|
---|
1071 | *num_processed = i;
|
---|
1072 | if (i > 0) {
|
---|
1073 | ret = 1;
|
---|
1074 | } else {
|
---|
1075 | ERR_raise(ERR_LIB_BIO, -l);
|
---|
1076 | ret = 0;
|
---|
1077 | }
|
---|
1078 | goto out;
|
---|
1079 | }
|
---|
1080 |
|
---|
1081 | m->data_len = l;
|
---|
1082 | m->flags = 0;
|
---|
1083 | }
|
---|
1084 |
|
---|
1085 | *num_processed = i;
|
---|
1086 | ret = 1;
|
---|
1087 | out:
|
---|
1088 | CRYPTO_THREAD_unlock(readb->lock);
|
---|
1089 | return ret;
|
---|
1090 | }
|
---|
1091 |
|
---|
1092 | /* Threadsafe */
|
---|
1093 | static int dgram_mem_read(BIO *bio, char *buf, int sz_)
|
---|
1094 | {
|
---|
1095 | int ret;
|
---|
1096 | ossl_ssize_t l;
|
---|
1097 | struct bio_dgram_pair_st *b = bio->ptr;
|
---|
1098 |
|
---|
1099 | if (sz_ < 0) {
|
---|
1100 | ERR_raise(ERR_LIB_BIO, BIO_R_INVALID_ARGUMENT);
|
---|
1101 | return -1;
|
---|
1102 | }
|
---|
1103 |
|
---|
1104 | if (CRYPTO_THREAD_write_lock(b->lock) == 0) {
|
---|
1105 | ERR_raise(ERR_LIB_BIO, ERR_R_UNABLE_TO_GET_WRITE_LOCK);
|
---|
1106 | return -1;
|
---|
1107 | }
|
---|
1108 |
|
---|
1109 | l = dgram_pair_read_actual(bio, buf, (size_t)sz_, NULL, NULL, 0);
|
---|
1110 | if (l < 0) {
|
---|
1111 | if (l != -BIO_R_NON_FATAL)
|
---|
1112 | ERR_raise(ERR_LIB_BIO, -l);
|
---|
1113 | ret = -1;
|
---|
1114 | } else {
|
---|
1115 | ret = (int)l;
|
---|
1116 | }
|
---|
1117 |
|
---|
1118 | CRYPTO_THREAD_unlock(b->lock);
|
---|
1119 | return ret;
|
---|
1120 | }
|
---|
1121 |
|
---|
1122 | /*
|
---|
1123 | * Calculate the array growth based on the target size.
|
---|
1124 | *
|
---|
1125 | * The growth factor is a rational number and is defined by a numerator
|
---|
1126 | * and a denominator. According to Andrew Koenig in his paper "Why Are
|
---|
1127 | * Vectors Efficient?" from JOOP 11(5) 1998, this factor should be less
|
---|
1128 | * than the golden ratio (1.618...).
|
---|
1129 | *
|
---|
1130 | * We use an expansion factor of 8 / 5 = 1.6
|
---|
1131 | */
|
---|
1132 | static const size_t max_rbuf_size = SIZE_MAX / 2; /* unlimited in practice */
|
---|
1133 | static ossl_inline size_t compute_rbuf_growth(size_t target, size_t current)
|
---|
1134 | {
|
---|
1135 | int err = 0;
|
---|
1136 |
|
---|
1137 | while (current < target) {
|
---|
1138 | if (current >= max_rbuf_size)
|
---|
1139 | return 0;
|
---|
1140 |
|
---|
1141 | current = safe_muldiv_size_t(current, 8, 5, &err);
|
---|
1142 | if (err)
|
---|
1143 | return 0;
|
---|
1144 | if (current >= max_rbuf_size)
|
---|
1145 | current = max_rbuf_size;
|
---|
1146 | }
|
---|
1147 | return current;
|
---|
1148 | }
|
---|
1149 |
|
---|
1150 | /* Must hold local write lock */
|
---|
1151 | static size_t dgram_pair_write_inner(struct bio_dgram_pair_st *b,
|
---|
1152 | const uint8_t *buf, size_t sz)
|
---|
1153 | {
|
---|
1154 | size_t total_written = 0;
|
---|
1155 |
|
---|
1156 | /*
|
---|
1157 | * We repeat pushes to the ring buffer for as long as we have data until we
|
---|
1158 | * fail. We may not be able to push in one operation if the ring buffer
|
---|
1159 | * wraps around, but there may still be more room for data.
|
---|
1160 | */
|
---|
1161 | while (sz > 0) {
|
---|
1162 | size_t dst_len;
|
---|
1163 | uint8_t *dst_buf;
|
---|
1164 |
|
---|
1165 | /*
|
---|
1166 | * There are two BIO instances, each with a ringbuf. We write to our own
|
---|
1167 | * ringbuf and read from the peer ringbuf.
|
---|
1168 | */
|
---|
1169 | ring_buf_head(&b->rbuf, &dst_buf, &dst_len);
|
---|
1170 | if (dst_len == 0) {
|
---|
1171 | size_t new_len;
|
---|
1172 |
|
---|
1173 | if (!b->grows_on_write) /* resize only if size not set explicitly */
|
---|
1174 | break;
|
---|
1175 | /* increase the size */
|
---|
1176 | new_len = compute_rbuf_growth(b->req_buf_len + sz, b->req_buf_len);
|
---|
1177 | if (new_len == 0 || !ring_buf_resize(&b->rbuf, new_len))
|
---|
1178 | break;
|
---|
1179 | b->req_buf_len = new_len;
|
---|
1180 | }
|
---|
1181 |
|
---|
1182 | if (dst_len > sz)
|
---|
1183 | dst_len = sz;
|
---|
1184 |
|
---|
1185 | memcpy(dst_buf, buf, dst_len);
|
---|
1186 | ring_buf_push(&b->rbuf, dst_len);
|
---|
1187 |
|
---|
1188 | buf += dst_len;
|
---|
1189 | sz -= dst_len;
|
---|
1190 | total_written += dst_len;
|
---|
1191 | }
|
---|
1192 |
|
---|
1193 | return total_written;
|
---|
1194 | }
|
---|
1195 |
|
---|
1196 | /*
|
---|
1197 | * Must hold local write lock. Returns number of bytes processed or negated BIO
|
---|
1198 | * response code.
|
---|
1199 | */
|
---|
1200 | static ossl_ssize_t dgram_pair_write_actual(BIO *bio, const char *buf, size_t sz,
|
---|
1201 | const BIO_ADDR *local, const BIO_ADDR *peer,
|
---|
1202 | int is_multi)
|
---|
1203 | {
|
---|
1204 | static const BIO_ADDR zero_addr;
|
---|
1205 | size_t saved_idx, saved_count;
|
---|
1206 | struct bio_dgram_pair_st *b = bio->ptr, *readb;
|
---|
1207 | struct dgram_hdr hdr = {0};
|
---|
1208 |
|
---|
1209 | if (!is_multi)
|
---|
1210 | BIO_clear_retry_flags(bio);
|
---|
1211 |
|
---|
1212 | if (!bio->init)
|
---|
1213 | return -BIO_R_UNINITIALIZED;
|
---|
1214 |
|
---|
1215 | if (!ossl_assert(b != NULL && b->rbuf.start != NULL))
|
---|
1216 | return -BIO_R_TRANSFER_ERROR;
|
---|
1217 |
|
---|
1218 | if (sz > 0 && buf == NULL)
|
---|
1219 | return -BIO_R_INVALID_ARGUMENT;
|
---|
1220 |
|
---|
1221 | if (local != NULL && b->local_addr_enable == 0)
|
---|
1222 | return -BIO_R_LOCAL_ADDR_NOT_AVAILABLE;
|
---|
1223 |
|
---|
1224 | if (is_dgram_pair(b))
|
---|
1225 | readb = b->peer->ptr;
|
---|
1226 | else
|
---|
1227 | readb = b;
|
---|
1228 | if (peer != NULL && (readb->cap & BIO_DGRAM_CAP_HANDLES_DST_ADDR) == 0)
|
---|
1229 | return -BIO_R_PEER_ADDR_NOT_AVAILABLE;
|
---|
1230 |
|
---|
1231 | hdr.len = sz;
|
---|
1232 | hdr.dst_addr = (peer != NULL ? *peer : zero_addr);
|
---|
1233 | hdr.src_addr = (local != NULL ? *local : zero_addr);
|
---|
1234 |
|
---|
1235 | saved_idx = b->rbuf.idx[0];
|
---|
1236 | saved_count = b->rbuf.count;
|
---|
1237 | if (dgram_pair_write_inner(b, (const uint8_t *)&hdr, sizeof(hdr)) != sizeof(hdr)
|
---|
1238 | || dgram_pair_write_inner(b, (const uint8_t *)buf, sz) != sz) {
|
---|
1239 | /*
|
---|
1240 | * We were not able to push the header and the entirety of the payload
|
---|
1241 | * onto the ring buffer, so abort and roll back the ring buffer state.
|
---|
1242 | */
|
---|
1243 | b->rbuf.idx[0] = saved_idx;
|
---|
1244 | b->rbuf.count = saved_count;
|
---|
1245 | if (!is_multi)
|
---|
1246 | BIO_set_retry_write(bio);
|
---|
1247 | return -BIO_R_NON_FATAL;
|
---|
1248 | }
|
---|
1249 |
|
---|
1250 | return sz;
|
---|
1251 | }
|
---|
1252 |
|
---|
1253 | /* Threadsafe */
|
---|
1254 | static int dgram_pair_write(BIO *bio, const char *buf, int sz_)
|
---|
1255 | {
|
---|
1256 | int ret;
|
---|
1257 | ossl_ssize_t l;
|
---|
1258 | struct bio_dgram_pair_st *b = bio->ptr;
|
---|
1259 |
|
---|
1260 | if (sz_ < 0) {
|
---|
1261 | ERR_raise(ERR_LIB_BIO, BIO_R_INVALID_ARGUMENT);
|
---|
1262 | return -1;
|
---|
1263 | }
|
---|
1264 |
|
---|
1265 | if (CRYPTO_THREAD_write_lock(b->lock) == 0) {
|
---|
1266 | ERR_raise(ERR_LIB_BIO, ERR_R_UNABLE_TO_GET_WRITE_LOCK);
|
---|
1267 | return -1;
|
---|
1268 | }
|
---|
1269 |
|
---|
1270 | l = dgram_pair_write_actual(bio, buf, (size_t)sz_, NULL, NULL, 0);
|
---|
1271 | if (l < 0) {
|
---|
1272 | ERR_raise(ERR_LIB_BIO, -l);
|
---|
1273 | ret = -1;
|
---|
1274 | } else {
|
---|
1275 | ret = (int)l;
|
---|
1276 | }
|
---|
1277 |
|
---|
1278 | CRYPTO_THREAD_unlock(b->lock);
|
---|
1279 | return ret;
|
---|
1280 | }
|
---|
1281 |
|
---|
1282 | /* Threadsafe */
|
---|
1283 | static int dgram_pair_sendmmsg(BIO *bio, BIO_MSG *msg,
|
---|
1284 | size_t stride, size_t num_msg,
|
---|
1285 | uint64_t flags, size_t *num_processed)
|
---|
1286 | {
|
---|
1287 | ossl_ssize_t ret, l;
|
---|
1288 | BIO_MSG *m;
|
---|
1289 | size_t i;
|
---|
1290 | struct bio_dgram_pair_st *b = bio->ptr;
|
---|
1291 |
|
---|
1292 | if (num_msg == 0) {
|
---|
1293 | *num_processed = 0;
|
---|
1294 | return 1;
|
---|
1295 | }
|
---|
1296 |
|
---|
1297 | if (CRYPTO_THREAD_write_lock(b->lock) == 0) {
|
---|
1298 | ERR_raise(ERR_LIB_BIO, ERR_R_UNABLE_TO_GET_WRITE_LOCK);
|
---|
1299 | *num_processed = 0;
|
---|
1300 | return 0;
|
---|
1301 | }
|
---|
1302 |
|
---|
1303 | for (i = 0; i < num_msg; ++i) {
|
---|
1304 | m = &BIO_MSG_N(msg, i);
|
---|
1305 | l = dgram_pair_write_actual(bio, m->data, m->data_len,
|
---|
1306 | m->local, m->peer, 1);
|
---|
1307 | if (l < 0) {
|
---|
1308 | *num_processed = i;
|
---|
1309 | if (i > 0) {
|
---|
1310 | ret = 1;
|
---|
1311 | } else {
|
---|
1312 | ERR_raise(ERR_LIB_BIO, -l);
|
---|
1313 | ret = 0;
|
---|
1314 | }
|
---|
1315 | goto out;
|
---|
1316 | }
|
---|
1317 |
|
---|
1318 | m->flags = 0;
|
---|
1319 | }
|
---|
1320 |
|
---|
1321 | *num_processed = i;
|
---|
1322 | ret = 1;
|
---|
1323 | out:
|
---|
1324 | CRYPTO_THREAD_unlock(b->lock);
|
---|
1325 | return ret;
|
---|
1326 | }
|
---|
1327 |
|
---|
1328 | #endif
|
---|