Coverage Report

Created: 2025-08-04 07:15

/src/wireshark/epan/tvbuff_brotli.c
Line
Count
Source (jump to first uncovered line)
1
/* tvbuff_brotli.c
2
 *
3
 * Wireshark - Network traffic analyzer
4
 * By Gerald Combs <gerald@wireshark.org>
5
 * Copyright 1998 Gerald Combs
6
 *
7
 * SPDX-License-Identifier: GPL-2.0-or-later
8
 */
9
10
#include <config.h>
11
12
#include <glib.h>
13
14
#include <string.h>
15
16
#ifdef HAVE_BROTLI
17
#include <brotli/decode.h>
18
#endif
19
20
#include "tvbuff.h"
21
22
#ifdef HAVE_BROTLI
23
24
/*
25
 * 512KiB is the buffer size used by the brotli tool, so we
26
 * use that too.
27
 */
28
#define TVB_BROTLI_BUFSIZ (1 << 19)
29
30
static void*
31
brotli_g_malloc_wrapper(void *opaque _U_, size_t size)
32
{
33
    return g_malloc(size);
34
}
35
36
static void
37
brotli_g_free_wrapper(void *opaque _U_, void *address)
38
{
39
    g_free(address);
40
}
41
42
/*
43
 * Uncompresses a brotli compressed packet inside a message of tvb at offset with
44
 * length comprlen.  Returns an uncompressed tvbuffer if uncompression
45
 * succeeded or NULL if uncompression failed.
46
 */
47
48
tvbuff_t *
49
tvb_uncompress_brotli(tvbuff_t *tvb, const int offset, int comprlen)
50
{
51
    uint8_t             *compr;
52
    uint8_t             *uncompr        = NULL;
53
    tvbuff_t            *uncompr_tvb;
54
    BrotliDecoderState  *decoder;
55
    uint8_t             *strmbuf;
56
    const size_t         bufsiz         = TVB_BROTLI_BUFSIZ;
57
    size_t               available_in;
58
    const uint8_t       *next_in;
59
    size_t               available_out;
60
    uint8_t             *next_out;
61
    size_t               total_out;
62
    unsigned             needs_more_output;
63
    unsigned             finished;
64
65
    if (tvb == NULL || comprlen <= 0) {
66
        return NULL;
67
    }
68
69
    compr = (uint8_t *)tvb_memdup(NULL, tvb, offset, comprlen);
70
    if (compr == NULL) {
71
        return NULL;
72
    }
73
74
    decoder = BrotliDecoderCreateInstance(
75
      &brotli_g_malloc_wrapper /*alloc_func*/,
76
      &brotli_g_free_wrapper /*free_func*/,
77
      NULL /*opaque*/);
78
    if (decoder == NULL) {
79
        wmem_free(NULL, compr);
80
        return NULL;
81
    }
82
    strmbuf = (uint8_t *)g_malloc(bufsiz);
83
84
    available_in = comprlen;
85
    next_in = compr;
86
    total_out = 0;
87
    needs_more_output = 0;
88
    finished = 0;
89
    while (available_in > 0 || needs_more_output) {
90
        needs_more_output = 0;
91
        available_out = bufsiz;
92
        next_out = strmbuf;
93
94
        BrotliDecoderResult result = BrotliDecoderDecompressStream(
95
          decoder, &available_in, &next_in, &available_out, &next_out, &total_out);
96
        switch (result) {
97
        case BROTLI_DECODER_RESULT_SUCCESS:
98
            if (available_in > 0) {
99
                goto cleanup;
100
            }
101
            finished = 1;
102
            break;
103
        case BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT:
104
            needs_more_output = 1;
105
            break;
106
        case BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT:
107
            /*
108
             * It's possible that not enough frames were captured
109
             * to decompress this fully, so return what we've done
110
             * so far, if any.
111
             */
112
            break;
113
        case BROTLI_DECODER_RESULT_ERROR:
114
        default:
115
            goto cleanup;
116
        }
117
118
        /*
119
         * Check if decompressed size is too large.
120
         */
121
        if (total_out > INT_MAX) {
122
            goto cleanup;
123
        }
124
125
        /*
126
         * BrotliDecoderDecompressStream sets available_out to the number of bytes
127
         * left unused from the buffer. But we are interested in the bytes it wrote
128
         * to the buffer in this pass, so we calculate pass_out.
129
         */
130
        size_t pass_out = bufsiz - available_out;
131
        if (pass_out > 0) {
132
            uncompr = (uint8_t *)g_realloc(uncompr, total_out);
133
            memcpy(uncompr + (total_out - pass_out), strmbuf, pass_out);
134
        }
135
    }
136
137
    if (uncompr == NULL) {
138
        /*
139
         * This is for the case when the validly decompressed
140
         * length is 0.
141
         */
142
        if (finished) {
143
            uncompr = (uint8_t *)g_strdup("");
144
        } else {
145
            goto cleanup;
146
        }
147
    }
148
149
    uncompr_tvb = tvb_new_real_data((uint8_t *)uncompr, (unsigned)total_out, (int)total_out);
150
    tvb_set_free_cb(uncompr_tvb, g_free);
151
152
    g_free(strmbuf);
153
    wmem_free(NULL, compr);
154
    BrotliDecoderDestroyInstance(decoder);
155
    return uncompr_tvb;
156
157
cleanup:
158
    g_free(strmbuf);
159
    g_free(uncompr);
160
    wmem_free(NULL, compr);
161
    BrotliDecoderDestroyInstance(decoder);
162
    return NULL;
163
}
164
#else
165
tvbuff_t *
166
tvb_uncompress_brotli(tvbuff_t *tvb _U_, const int offset _U_, int comprlen _U_)
167
0
{
168
0
    return NULL;
169
0
}
170
#endif
171
172
tvbuff_t *
173
tvb_child_uncompress_brotli(tvbuff_t *parent, tvbuff_t *tvb, const int offset, int comprlen)
174
0
{
175
0
    tvbuff_t *new_tvb = tvb_uncompress_brotli(tvb, offset, comprlen);
176
0
    if (new_tvb)
177
0
        tvb_set_child_real_data_tvbuff(parent, new_tvb);
178
0
    return new_tvb;
179
0
}
180
181
/*
182
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
183
 *
184
 * Local variables:
185
 * c-basic-offset: 4
186
 * tab-width: 8
187
 * indent-tabs-mode: nil
188
 * End:
189
 *
190
 * vi: set shiftwidth=4 tabstop=8 expandtab:
191
 * :indentSize=4:tabSize=8:noTabs=true:
192
 */