Coverage Report

Created: 2026-10-16 07:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openssl/ssl/dgram_demux.c
Line
Count
Source
1
/*
2
 * Copyright 2026 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 "internal/e_os.h"
11
#include "internal/dgram_demux.h"
12
#include "internal/thread_arch.h"
13
#include "internal/common.h"
14
#include <openssl/err.h>
15
#include <string.h>
16
17
#if !defined(OPENSSL_NO_QUIC) || !defined(OPENSSL_NO_DTLS)
18
19
/* URXE_DEMUX_STATE_* are defined in dgram_demux.h */
20
21
0
#define DEMUX_DEFAULT_MTU 1500
22
0
#define DEMUX_MIN_INITIAL_DGRAM_LEN 1200
23
24
struct dgram_demux_st {
25
    /* The underlying transport BIO with datagram semantics. */
26
    BIO *net_bio;
27
28
    /*
29
     * Our current understanding of the upper bound on an incoming datagram size
30
     * in bytes.
31
     */
32
    size_t mtu;
33
34
    /* The datagram_id to use for the next datagram we receive. */
35
    uint64_t next_datagram_id;
36
37
    /* Time retrieval callback. */
38
    OSSL_TIME (*now)(void *arg);
39
    void *now_arg;
40
41
    /* The default packet handler, if any. */
42
    ossl_dgram_demux_cb_fn *default_cb;
43
    void *default_cb_arg;
44
45
    /*
46
     * List of URXEs which are not currently in use (i.e., not filled with
47
     * unconsumed data). These are moved to the pending list as they are filled.
48
     */
49
    DGRAM_URXE_LIST urx_free;
50
51
    /*
52
     * List of URXEs which are filled with received encrypted data. These are
53
     * removed from this list as we invoke the callbacks for each of them. They
54
     * are then not on any list managed by us; we forget about them until our
55
     * user calls ossl_dgram_demux_release_urxe to return the URXE to us, at
56
     * which point we add it to the free list.
57
     */
58
    DGRAM_URXE_LIST urx_pending;
59
60
    /* Whether to use local address support. */
61
    char use_local_addr;
62
63
    /* Whether internal locking is required */
64
    char require_mutex;
65
66
    /* Maximum URXEs cached on urx_free; 0 means unbounded. */
67
    size_t max_free_urxe;
68
69
    /*
70
     * Mutex protecting the URXE lists (urx_free and urx_pending).
71
     */
72
    CRYPTO_MUTEX *mutex;
73
};
74
75
/* List management helpers */
76
void ossl_dgram_urxe_remove(DGRAM_URXE_LIST *l, DGRAM_URXE *e)
77
0
{
78
0
    ossl_list_urxe_remove(l, e);
79
0
}
80
81
void ossl_dgram_urxe_insert_head(DGRAM_URXE_LIST *l, DGRAM_URXE *e)
82
0
{
83
0
    ossl_list_urxe_insert_head(l, e);
84
0
}
85
86
void ossl_dgram_urxe_insert_tail(DGRAM_URXE_LIST *l, DGRAM_URXE *e)
87
0
{
88
0
    ossl_list_urxe_insert_tail(l, e);
89
0
}
90
91
DGRAM_DEMUX *ossl_dgram_demux_new(BIO *net_bio,
92
    int threadsafe,
93
    OSSL_TIME (*now)(void *arg),
94
    void *now_arg)
95
0
{
96
0
    DGRAM_DEMUX *demux;
97
98
0
    demux = OPENSSL_zalloc(sizeof(DGRAM_DEMUX));
99
0
    if (demux == NULL)
100
0
        return NULL;
101
102
0
    if (threadsafe) {
103
0
        demux->require_mutex = 1;
104
0
        demux->mutex = ossl_crypto_mutex_new();
105
0
#ifdef OPENSSL_THREADS
106
0
        if (demux->mutex == NULL) {
107
0
            ERR_raise(ERR_LIB_SSL, ERR_R_CRYPTO_LIB);
108
0
            OPENSSL_free(demux);
109
0
            return NULL;
110
0
        }
111
0
#endif
112
0
    }
113
114
    /* We update this if possible when we get a BIO. */
115
0
    demux->mtu = DEMUX_DEFAULT_MTU;
116
0
    demux->now = now;
117
0
    demux->now_arg = now_arg;
118
119
0
    ossl_dgram_demux_set_bio(demux, net_bio);
120
121
0
    return demux;
122
0
}
123
124
static void dgram_demux_free_urxl(DGRAM_URXE_LIST *l)
125
0
{
126
0
    DGRAM_URXE *e, *enext;
127
128
0
    for (e = ossl_list_urxe_head(l); e != NULL; e = enext) {
129
0
        enext = ossl_list_urxe_next(e);
130
0
        ossl_list_urxe_remove(l, e);
131
0
        OPENSSL_free(e);
132
0
    }
133
0
}
134
135
void ossl_dgram_demux_free(DGRAM_DEMUX *demux)
136
0
{
137
0
    if (demux == NULL)
138
0
        return;
139
140
    /* Free all URXEs we are holding. */
141
0
    dgram_demux_free_urxl(&demux->urx_free);
142
0
    dgram_demux_free_urxl(&demux->urx_pending);
143
144
0
    if (demux->require_mutex)
145
0
        ossl_crypto_mutex_free(&demux->mutex);
146
147
0
    OPENSSL_free(demux);
148
0
}
149
150
void ossl_dgram_demux_set_bio(DGRAM_DEMUX *demux, BIO *net_bio)
151
0
{
152
0
    unsigned int mtu;
153
154
0
    demux->net_bio = net_bio;
155
156
0
    if (net_bio != NULL) {
157
        /*
158
         * Try to determine our MTU if possible. The BIO is not required to
159
         * support this, in which case we remain at the last known MTU, or our
160
         * initial default.
161
         */
162
0
        mtu = BIO_dgram_get_mtu(net_bio);
163
0
        if (mtu >= DEMUX_MIN_INITIAL_DGRAM_LEN)
164
0
            ossl_dgram_demux_set_mtu(demux, mtu);
165
166
0
        if (BIO_dgram_get_local_addr_cap(net_bio)
167
0
            && BIO_dgram_set_local_addr_enable(net_bio, 1))
168
0
            demux->use_local_addr = 1;
169
0
    }
170
0
}
171
172
int ossl_dgram_demux_set_mtu(DGRAM_DEMUX *demux, unsigned int mtu)
173
0
{
174
0
    if (mtu < DEMUX_MIN_INITIAL_DGRAM_LEN)
175
0
        return 0;
176
177
    /*
178
     * mtu is read under demux->mutex by the receive path
179
     * so take the lock here.
180
     */
181
0
    if (demux->require_mutex)
182
0
        ossl_crypto_mutex_lock(demux->mutex);
183
0
    demux->mtu = mtu;
184
0
    if (demux->require_mutex)
185
0
        ossl_crypto_mutex_unlock(demux->mutex);
186
0
    return 1;
187
0
}
188
189
void ossl_dgram_demux_set_max_free_urxe(DGRAM_DEMUX *demux, size_t max_free)
190
0
{
191
0
    if (demux->require_mutex)
192
0
        ossl_crypto_mutex_lock(demux->mutex);
193
0
    demux->max_free_urxe = max_free;
194
0
    if (demux->require_mutex)
195
0
        ossl_crypto_mutex_unlock(demux->mutex);
196
0
}
197
198
size_t ossl_dgram_demux_get_free_list_len(DGRAM_DEMUX *demux)
199
0
{
200
0
    size_t n;
201
202
0
    if (demux->require_mutex)
203
0
        ossl_crypto_mutex_lock(demux->mutex);
204
0
    n = ossl_list_urxe_num(&demux->urx_free);
205
0
    if (demux->require_mutex)
206
0
        ossl_crypto_mutex_unlock(demux->mutex);
207
0
    return n;
208
0
}
209
210
void ossl_dgram_demux_set_default_handler(DGRAM_DEMUX *demux,
211
    ossl_dgram_demux_cb_fn *cb,
212
    void *cb_arg)
213
0
{
214
0
    demux->default_cb = cb;
215
0
    demux->default_cb_arg = cb_arg;
216
0
}
217
218
static DGRAM_URXE *dgram_demux_alloc_urxe(size_t alloc_len)
219
0
{
220
0
    DGRAM_URXE *e;
221
222
0
    if (alloc_len >= SIZE_MAX - sizeof(DGRAM_URXE))
223
0
        return NULL;
224
225
0
    e = OPENSSL_zalloc(sizeof(DGRAM_URXE) + alloc_len);
226
0
    if (e == NULL)
227
0
        return NULL;
228
229
0
    ossl_list_urxe_init_elem(e);
230
0
    e->alloc_len = alloc_len;
231
0
    e->data_len = 0;
232
0
    return e;
233
0
}
234
235
static DGRAM_URXE *dgram_demux_resize_urxe(DGRAM_DEMUX *demux, DGRAM_URXE *e,
236
    size_t new_alloc_len)
237
0
{
238
0
    DGRAM_URXE *e2, *prev;
239
240
0
    if (!ossl_assert(e->demux_state == URXE_DEMUX_STATE_FREE))
241
        /* Never attempt to resize a URXE which is not on the free list. */
242
0
        return NULL;
243
244
0
    prev = ossl_list_urxe_prev(e);
245
0
    ossl_list_urxe_remove(&demux->urx_free, e);
246
247
0
    if (new_alloc_len >= SIZE_MAX - sizeof(DGRAM_URXE))
248
0
        goto rollback;
249
250
0
    e2 = OPENSSL_realloc(e, sizeof(DGRAM_URXE) + new_alloc_len);
251
252
    /* Failed to resize, abort. */
253
0
    if (e2 == NULL)
254
0
        goto rollback;
255
256
0
    if (prev == NULL)
257
0
        ossl_list_urxe_insert_head(&demux->urx_free, e2);
258
0
    else
259
0
        ossl_list_urxe_insert_after(&demux->urx_free, prev, e2);
260
261
0
    e2->alloc_len = new_alloc_len;
262
0
    return e2;
263
264
0
rollback:
265
    /* Reinsert e back into the list on failures */
266
0
    if (prev == NULL)
267
0
        ossl_list_urxe_insert_head(&demux->urx_free, e);
268
0
    else
269
0
        ossl_list_urxe_insert_after(&demux->urx_free, prev, e);
270
271
0
    return NULL;
272
0
}
273
274
static DGRAM_URXE *dgram_demux_reserve_urxe(DGRAM_DEMUX *demux, DGRAM_URXE *e,
275
    size_t alloc_len)
276
0
{
277
0
    return e->alloc_len < alloc_len
278
0
        ? dgram_demux_resize_urxe(demux, e, alloc_len)
279
0
        : e;
280
0
}
281
282
static int dgram_demux_ensure_free_urxe(DGRAM_DEMUX *demux, size_t min_num_free)
283
0
{
284
0
    DGRAM_URXE *e;
285
286
    /* Caller must hold the lock */
287
0
    while (ossl_list_urxe_num(&demux->urx_free) < min_num_free) {
288
0
        e = dgram_demux_alloc_urxe(demux->mtu);
289
0
        if (e == NULL)
290
0
            return 0;
291
292
0
        ossl_list_urxe_insert_tail(&demux->urx_free, e);
293
0
        e->demux_state = URXE_DEMUX_STATE_FREE;
294
0
    }
295
296
0
    return 1;
297
0
}
298
299
/*
300
 * Receive datagrams from network, placing them into URXEs.
301
 *
302
 * Returns DGRAM_DEMUX_PUMP_RES_* value.
303
 *
304
 * Precondition: at least one URXE is free
305
 * Precondition: there are no pending URXEs
306
 * Precondition: Caller holds the demux lock
307
 */
308
static int dgram_demux_recv(DGRAM_DEMUX *demux)
309
0
{
310
0
    BIO_MSG msg[DEMUX_MAX_MSGS_PER_CALL];
311
0
    size_t rd, i;
312
0
    DGRAM_URXE *urxe = ossl_list_urxe_head(&demux->urx_free), *unext;
313
0
    OSSL_TIME now;
314
315
    /* This should never be called when we have any pending URXE. */
316
0
    assert(ossl_list_urxe_head(&demux->urx_pending) == NULL);
317
0
    assert(urxe->demux_state == URXE_DEMUX_STATE_FREE);
318
319
0
    if (demux->net_bio == NULL)
320
        /*
321
         * If no BIO is plugged in, treat this as no datagram being available.
322
         */
323
0
        return DGRAM_DEMUX_PUMP_RES_TRANSIENT_FAIL;
324
325
    /*
326
     * Opportunistically receive as many messages as possible in a single
327
     * syscall, determined by how many free URXEs are available.
328
     */
329
0
    for (i = 0; i < (ossl_ssize_t)OSSL_NELEM(msg);
330
0
        ++i, urxe = ossl_list_urxe_next(urxe)) {
331
0
        if (urxe == NULL) {
332
            /* We need at least one URXE to receive into. */
333
0
            if (!ossl_assert(i > 0))
334
0
                return DGRAM_DEMUX_PUMP_RES_PERMANENT_FAIL;
335
336
0
            break;
337
0
        }
338
339
        /* Ensure the URXE is big enough. */
340
0
        urxe = dgram_demux_reserve_urxe(demux, urxe, demux->mtu);
341
0
        if (urxe == NULL)
342
            /* Allocation error, fail. */
343
0
            return DGRAM_DEMUX_PUMP_RES_PERMANENT_FAIL;
344
345
        /* Ensure we zero any fields added to BIO_MSG at a later date. */
346
0
        memset(&msg[i], 0, sizeof(BIO_MSG));
347
0
        msg[i].data = ossl_dgram_urxe_data(urxe);
348
0
        msg[i].data_len = urxe->alloc_len;
349
0
        msg[i].peer = &urxe->peer;
350
0
        BIO_ADDR_clear(&urxe->peer);
351
0
        if (demux->use_local_addr)
352
0
            msg[i].local = &urxe->local;
353
0
        else
354
0
            BIO_ADDR_clear(&urxe->local);
355
0
    }
356
357
0
    ERR_set_mark();
358
0
    if (!BIO_recvmmsg(demux->net_bio, msg, sizeof(BIO_MSG), i, 0, &rd)) {
359
0
        if (BIO_err_is_non_fatal(ERR_peek_last_error())) {
360
            /* Transient error, clear the error and stop. */
361
0
            ERR_pop_to_mark();
362
0
            return DGRAM_DEMUX_PUMP_RES_TRANSIENT_FAIL;
363
0
        } else {
364
            /* Non-transient error, do not clear the error. */
365
0
            ERR_clear_last_mark();
366
0
            return DGRAM_DEMUX_PUMP_RES_PERMANENT_FAIL;
367
0
        }
368
0
    }
369
370
0
    ERR_clear_last_mark();
371
0
    now = demux->now != NULL ? demux->now(demux->now_arg) : ossl_time_zero();
372
373
0
    urxe = ossl_list_urxe_head(&demux->urx_free);
374
0
    for (i = 0; i < rd; ++i, urxe = unext) {
375
0
        unext = ossl_list_urxe_next(urxe);
376
        /* Set URXE with actual length of received datagram. */
377
0
        urxe->data_len = msg[i].data_len;
378
        /* Time we received datagram. */
379
0
        urxe->time = now;
380
0
        urxe->datagram_id = demux->next_datagram_id++;
381
        /* Move from free list to pending list. */
382
0
        ossl_list_urxe_remove(&demux->urx_free, urxe);
383
0
        ossl_list_urxe_insert_tail(&demux->urx_pending, urxe);
384
0
        urxe->demux_state = URXE_DEMUX_STATE_PENDING;
385
0
    }
386
387
0
    return DGRAM_DEMUX_PUMP_RES_OK;
388
0
}
389
390
/*
391
 * Process a single pending URXE.
392
 * Returning 1 on success, 0 on failure.
393
 *
394
 * Precondition: Caller holds the demux lock
395
 * Note: Lock is released before callback and reacquired after.
396
 */
397
static int dgram_demux_process_pending_urxe(DGRAM_DEMUX *demux, DGRAM_URXE *e)
398
0
{
399
    /* The next URXE we process should be at the head of the pending list. */
400
0
    if (!ossl_assert(e == ossl_list_urxe_head(&demux->urx_pending)))
401
0
        return 0;
402
403
0
    assert(e->demux_state == URXE_DEMUX_STATE_PENDING);
404
405
0
    ossl_list_urxe_remove(&demux->urx_pending, e);
406
0
    if (demux->default_cb != NULL) {
407
        /*
408
         * Pass to handler for routing. The URXE now belongs to the callback.
409
         * Release lock before callback to avoid deadlock if callback calls
410
         * release_urxe or reinject_urxe.
411
         */
412
0
        e->demux_state = URXE_DEMUX_STATE_ISSUED;
413
0
        if (demux->require_mutex)
414
0
            ossl_crypto_mutex_unlock(demux->mutex);
415
0
        demux->default_cb(e, demux->default_cb_arg);
416
0
        if (demux->require_mutex)
417
0
            ossl_crypto_mutex_lock(demux->mutex);
418
0
    } else {
419
        /* No handler, discard. */
420
0
        ossl_list_urxe_insert_tail(&demux->urx_free, e);
421
0
        e->demux_state = URXE_DEMUX_STATE_FREE;
422
0
    }
423
424
0
    return 1; /* keep processing pending URXEs */
425
0
}
426
427
/*
428
 * Process pending URXEs to generate callbacks.
429
 * Precondition: Caller holds the demux lock
430
 */
431
static int dgram_demux_process_pending_urxl(DGRAM_DEMUX *demux)
432
0
{
433
0
    DGRAM_URXE *e;
434
0
    int ret;
435
436
0
    while ((e = ossl_list_urxe_head(&demux->urx_pending)) != NULL)
437
0
        if ((ret = dgram_demux_process_pending_urxe(demux, e)) <= 0)
438
0
            return ret;
439
440
0
    return 1;
441
0
}
442
443
/*
444
 * Drain the pending URXE list, processing any pending URXEs by making their
445
 * callbacks. If no URXEs are pending, a network read is attempted first.
446
 */
447
int ossl_dgram_demux_pump(DGRAM_DEMUX *demux)
448
0
{
449
0
    int ret;
450
451
0
    if (demux->require_mutex)
452
0
        ossl_crypto_mutex_lock(demux->mutex);
453
454
0
    if (ossl_list_urxe_head(&demux->urx_pending) == NULL) {
455
0
        if (!dgram_demux_ensure_free_urxe(demux, DEMUX_MAX_MSGS_PER_CALL)) {
456
0
            ret = DGRAM_DEMUX_PUMP_RES_PERMANENT_FAIL;
457
0
            goto end;
458
0
        }
459
460
0
        ret = dgram_demux_recv(demux);
461
0
        if (ret != DGRAM_DEMUX_PUMP_RES_OK)
462
0
            goto end;
463
464
        /*
465
         * If dgram_demux_recv returned successfully, we should always have
466
         * something.
467
         */
468
0
        assert(ossl_list_urxe_head(&demux->urx_pending) != NULL);
469
0
    }
470
471
0
    if (dgram_demux_process_pending_urxl(demux) <= 0) {
472
0
        ret = DGRAM_DEMUX_PUMP_RES_PERMANENT_FAIL;
473
0
        goto end;
474
0
    }
475
476
0
    ret = DGRAM_DEMUX_PUMP_RES_OK;
477
478
0
end:
479
0
    if (demux->require_mutex)
480
0
        ossl_crypto_mutex_unlock(demux->mutex);
481
0
    return ret;
482
0
}
483
484
/* Artificially inject a packet into the demuxer for testing purposes. */
485
int ossl_dgram_demux_inject(DGRAM_DEMUX *demux,
486
    const unsigned char *buf,
487
    size_t buf_len,
488
    const BIO_ADDR *peer,
489
    const BIO_ADDR *local)
490
0
{
491
0
    int ret = 0;
492
0
    DGRAM_URXE *urxe;
493
494
0
    if (demux->require_mutex)
495
0
        ossl_crypto_mutex_lock(demux->mutex);
496
497
0
    if (!dgram_demux_ensure_free_urxe(demux, 1))
498
0
        goto end;
499
500
0
    urxe = ossl_list_urxe_head(&demux->urx_free);
501
502
0
    assert(urxe->demux_state == URXE_DEMUX_STATE_FREE);
503
504
0
    urxe = dgram_demux_reserve_urxe(demux, urxe, buf_len);
505
0
    if (urxe == NULL)
506
0
        goto end;
507
508
0
    memcpy(ossl_dgram_urxe_data(urxe), buf, buf_len);
509
0
    urxe->data_len = buf_len;
510
511
0
    if (peer != NULL)
512
0
        BIO_ADDR_copy(&urxe->peer, peer);
513
0
    else
514
0
        BIO_ADDR_clear(&urxe->peer);
515
516
0
    if (local != NULL)
517
0
        BIO_ADDR_copy(&urxe->local, local);
518
0
    else
519
0
        BIO_ADDR_clear(&urxe->local);
520
521
0
    urxe->time
522
0
        = demux->now != NULL ? demux->now(demux->now_arg) : ossl_time_zero();
523
524
    /* Move from free list to pending list. */
525
0
    ossl_list_urxe_remove(&demux->urx_free, urxe);
526
0
    urxe->datagram_id = demux->next_datagram_id++;
527
0
    ossl_list_urxe_insert_tail(&demux->urx_pending, urxe);
528
0
    urxe->demux_state = URXE_DEMUX_STATE_PENDING;
529
530
0
    ret = dgram_demux_process_pending_urxl(demux) > 0;
531
532
0
end:
533
0
    if (demux->require_mutex)
534
0
        ossl_crypto_mutex_unlock(demux->mutex);
535
0
    return ret;
536
0
}
537
538
/*
539
 * Called by our user to return a URXE to the free list. If the free list
540
 * is already at its limit the URXE is freed instead of being cached;
541
 * callers must not reference a URXE after releasing it, so freeing here
542
 * is safe even inside the routing callback.
543
 */
544
void ossl_dgram_demux_release_urxe(DGRAM_DEMUX *demux, DGRAM_URXE *e)
545
0
{
546
0
    int cache;
547
548
0
    assert(ossl_list_urxe_prev(e) == NULL && ossl_list_urxe_next(e) == NULL);
549
0
    assert(e->demux_state == URXE_DEMUX_STATE_ISSUED);
550
551
0
    if (demux->require_mutex)
552
0
        ossl_crypto_mutex_lock(demux->mutex);
553
0
    cache = demux->max_free_urxe == 0
554
0
        || ossl_list_urxe_num(&demux->urx_free) < demux->max_free_urxe;
555
0
    if (cache) {
556
0
        ossl_list_urxe_insert_tail(&demux->urx_free, e);
557
0
        e->demux_state = URXE_DEMUX_STATE_FREE;
558
0
    }
559
0
    if (demux->require_mutex)
560
0
        ossl_crypto_mutex_unlock(demux->mutex);
561
0
    if (!cache)
562
0
        OPENSSL_free(e);
563
0
}
564
565
void ossl_dgram_demux_reinject_urxe(DGRAM_DEMUX *demux, DGRAM_URXE *e)
566
0
{
567
0
    assert(ossl_list_urxe_prev(e) == NULL && ossl_list_urxe_next(e) == NULL);
568
0
    assert(e->demux_state == URXE_DEMUX_STATE_ISSUED);
569
570
0
    if (demux->require_mutex)
571
0
        ossl_crypto_mutex_lock(demux->mutex);
572
0
    ossl_list_urxe_insert_head(&demux->urx_pending, e);
573
0
    e->demux_state = URXE_DEMUX_STATE_PENDING;
574
0
    if (demux->require_mutex)
575
0
        ossl_crypto_mutex_unlock(demux->mutex);
576
0
}
577
578
int ossl_dgram_demux_has_pending(const DGRAM_DEMUX *demux)
579
0
{
580
    return ossl_list_urxe_head(&demux->urx_pending) != NULL;
581
0
}
582
583
#endif /* !OPENSSL_NO_QUIC || !OPENSSL_NO_DTLS */