Bug Summary

File:builds/wireshark/wireshark/epan/tvbuff_zlib.c
Warning:line 280, column 15
Potential leak of memory pointed to by 'strmbuf'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name tvbuff_zlib.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -fno-delete-null-pointer-checks -mframe-pointer=all -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -ffloat16-excess-precision=fast -fbfloat16-excess-precision=fast -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/builds/wireshark/wireshark/build -fcoverage-compilation-dir=/builds/wireshark/wireshark/build -resource-dir /usr/lib/llvm-22/lib/clang/22 -isystem /usr/include/glib-2.0 -isystem /usr/lib/x86_64-linux-gnu/glib-2.0/include -isystem /builds/wireshark/wireshark/epan -isystem /builds/wireshark/wireshark/build/epan -isystem /usr/include/mit-krb5 -isystem /usr/include/lua5.5 -isystem /usr/include/libxml2 -D CARES_NO_DEPRECATED -D G_DISABLE_DEPRECATED -D G_DISABLE_SINGLE_INCLUDES -D WS_BUILD_DLL -D WS_DEBUG -D WS_DEBUG_UTF_8 -D epan_EXPORTS -I /builds/wireshark/wireshark/build -I /builds/wireshark/wireshark -I /builds/wireshark/wireshark/include -I /builds/wireshark/wireshark/wiretap -D _GLIBCXX_ASSERTIONS -internal-isystem /usr/lib/llvm-22/lib/clang/22/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/builds/wireshark/wireshark/= -fmacro-prefix-map=/builds/wireshark/wireshark/build/= -fmacro-prefix-map=../= -Wno-format-nonliteral -std=gnu17 -ferror-limit 19 -fvisibility=hidden -fwrapv -fwrapv-pointer -fstrict-flex-arrays=3 -stack-protector 2 -fstack-clash-protection -fcf-protection=full -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fexceptions -fcolor-diagnostics -analyzer-output=html -faddrsig -fdwarf2-cfi-asm -o /builds/wireshark/wireshark/sbout/2026-06-25-100411-3595-1 -x c /builds/wireshark/wireshark/epan/tvbuff_zlib.c
1/* tvbuff_zlib.c
2 *
3 * Copyright (c) 2000 by Gilbert Ramirez <[email protected]>
4 *
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <[email protected]>
7 * Copyright 1998 Gerald Combs
8 *
9 * SPDX-License-Identifier: GPL-2.0-or-later
10 */
11
12#include <config.h>
13#define WS_LOG_DOMAIN"Epan" LOG_DOMAIN_EPAN"Epan"
14
15#include <glib.h>
16
17#include <string.h>
18#include <wsutil/glib-compat.h>
19#include <wsutil/zlib_compat.h>
20
21#include "tvbuff.h"
22#include <wsutil/wslog.h>
23
24#ifdef USE_ZLIB_OR_ZLIBNG
25/*
26 * Uncompresses a zlib compressed packet inside a message of tvb at offset with
27 * length comprlen. Returns an uncompressed tvbuffer if uncompression
28 * succeeded or NULL if uncompression failed.
29 */
30#define TVB_Z_MIN_BUFSIZ32768 32768
31#define TVB_Z_MAX_BUFSIZ1048576 * 10 1048576 * 10
32
33tvbuff_t *
34tvb_uncompress_zlib(tvbuff_t *tvb, const unsigned offset, unsigned comprlen)
35{
36 int err;
37 /* bytes_out is an unsigned because tvb_new_real_data does not accept
38 * more than an unsigned. */
39 unsigned bytes_out = 0;
40 uint8_t *compr;
41 tvbuff_t *uncompr_tvb = NULL((void*)0);
42 zlib_stream strm = {0};
43 Bytef *strmbuf;
44 unsigned inits_done = 0;
45 int wbits = MAX_WBITS15;
46 uint8_t *next;
47 unsigned bufsiz;
48 unsigned inflate_passes = 0;
49 unsigned bytes_in = tvb_captured_length_remaining(tvb, offset);
50
51 if (tvb == NULL((void*)0) || comprlen <= 0) {
2
Assuming 'tvb' is not equal to NULL
3
Assuming 'comprlen' is > 0
4
Taking false branch
52 return NULL((void*)0);
53 }
54
55 compr = (uint8_t *)tvb_memdup(NULL((void*)0), tvb, offset, comprlen);
56 if (compr == NULL((void*)0)) {
5
Assuming 'compr' is not equal to NULL
6
Taking false branch
57 return NULL((void*)0);
58 }
59
60 /*
61 * Assume that the uncompressed data is at least twice as big as
62 * the compressed size.
63 */
64 if (ckd_mul(&bufsiz, bytes_in, 2)__builtin_mul_overflow((bytes_in), (2), (&bufsiz))) {
7
Taking true branch
65 bufsiz = TVB_Z_MAX_BUFSIZ1048576 * 10;
66 } else {
67 bufsiz = CLAMP(bufsiz, TVB_Z_MIN_BUFSIZ, TVB_Z_MAX_BUFSIZ)(((bufsiz) > (1048576 * 10)) ? (1048576 * 10) : (((bufsiz)
< (32768)) ? (32768) : (bufsiz)))
;
68 }
69
70 ws_debug("bufsiz: %u bytes\n", bufsiz)do { if (1) { ws_log_full("Epan", LOG_LEVEL_DEBUG, "epan/tvbuff_zlib.c"
, 70, __func__, "bufsiz: %u bytes\n", bufsiz); } } while (0)
;
8
Taking true branch
9
Loop condition is false. Exiting loop
71
72 next = compr;
73
74 strm.next_in = next;
75 strm.avail_in = comprlen;
76
77 strmbuf = (Bytef *)g_malloc(bufsiz);
78
79 err = ZLIB_PREFIX(inflateInit2)(&strm, wbits)inflateInit2_((&strm), (wbits), "1.3.1", (int)sizeof(z_stream
))
;
80 inits_done = 1;
81 if (err != Z_OK0) {
10
Assuming 'err' is equal to Z_OK
11
Taking false branch
82 ZLIB_PREFIX(inflateEnd)inflateEnd(&strm);
83 goto exit_err;
84 }
85
86 while (1) {
12
Loop condition is true. Entering loop body
87 strm.next_out = &strmbuf[bytes_out];
88 strm.avail_out = bufsiz;
89
90 err = ZLIB_PREFIX(inflate)inflate(&strm, Z_SYNC_FLUSH2);
91
92 if (err == Z_OK0 || err == Z_STREAM_END1) {
13
Assuming 'err' is not equal to Z_OK
14
Assuming 'err' is equal to Z_STREAM_END
15
Taking true branch
93 unsigned bytes_pass = bufsiz - strm.avail_out;
94
95 // This is an unsigned long, but won't overflow even
96 // on platforms where that is 32-bit, because bufsize
97 // is clamped, if we break when it reaches INT_MAX.
98 if (strm.total_out > INT_MAX2147483647) {
16
Assuming field 'total_out' is <= INT_MAX
17
Taking false branch
99 // Qt uses signed ints in various classes, so
100 // the GUI can't really handle anything
101 ws_debug("overflow, returning what we have")do { if (1) { ws_log_full("Epan", LOG_LEVEL_DEBUG, "epan/tvbuff_zlib.c"
, 101, __func__, "overflow, returning what we have"); } } while
(0)
;
102 ZLIB_PREFIX(inflateEnd)inflateEnd(&strm);
103 break;
104 }
105
106 /* Use this for a workaround for bug #6480
107 * (https://gitlab.com/wireshark/wireshark/-/issues/6480)
108 * When a zero length payload was compressed into 20 bytes
109 * bytes we want to return a tvb with 0 length instead
110 * of NULL. */
111 ++inflate_passes;
112
113 bytes_out += bytes_pass;
114 ws_assert(bytes_out == strm.total_out)do { if ((1) && !(bytes_out == strm.total_out)) ws_log_fatal_full
("Epan", LOG_LEVEL_ERROR, "epan/tvbuff_zlib.c", 114, __func__
, "assertion failed: %s", "bytes_out == strm.total_out"); } while
(0)
;
18
Assuming 'bytes_out' is equal to field 'total_out'
19
Taking false branch
20
Loop condition is false. Exiting loop
115
116 if (strm.avail_out == 0) {
21
Assuming field 'avail_out' is not equal to 0
22
Taking false branch
117 strmbuf = (uint8_t*)g_realloc(strmbuf, bytes_out + bufsiz);
118 }
119
120 if (err
22.1
'err' is equal to Z_STREAM_END
== Z_STREAM_END1) {
23
Taking true branch
121 ZLIB_PREFIX(inflateEnd)inflateEnd(&strm);
122 break;
24
Execution continues on line 274
123 }
124 } else if (err == Z_BUF_ERROR(-5)) {
125 /*
126 * It's possible that not enough frames were captured
127 * to decompress this fully, so return what we've done
128 * so far, if any.
129 */
130 ZLIB_PREFIX(inflateEnd)inflateEnd(&strm);
131
132 if (inflate_passes) {
133 break;
134 } else {
135 goto exit_err;
136 }
137
138 } else if (err == Z_DATA_ERROR(-3) && inits_done == 1
139 && inflate_passes == 0 && comprlen >= 2 &&
140 (*compr == 0x1f) && (*(compr + 1) == 0x8b)) {
141 /*
142 * inflate() is supposed to handle both gzip and deflate
143 * streams automatically, but in reality it doesn't
144 * seem to handle either (at least not within the
145 * context of an HTTP response.) We have to try
146 * several tweaks, depending on the type of data and
147 * version of the library installed.
148 */
149
150 /*
151 * Gzip file format. Skip past the header, since the
152 * fix to make it work (setting windowBits to 31)
153 * doesn't work with all versions of the library.
154 */
155 Bytef *c = compr + 2;
156 Bytef flags = 0;
157
158 /* we read two bytes already (0x1f, 0x8b) and
159 need at least Z_DEFLATED, 1 byte flags, 4
160 bytes MTIME, 1 byte XFL, 1 byte OS */
161 if (comprlen < 10 || *c != Z_DEFLATED8) {
162 ZLIB_PREFIX(inflateEnd)inflateEnd(&strm);
163 goto exit_err;
164 }
165
166 c++;
167 flags = *c;
168 c++;
169
170 /* Skip past the MTIME (4 bytes),
171 XFL, and OS fields (1 byte each). */
172 c += 6;
173
174 if (flags & (1 << 2)) {
175 /* An Extra field is present. It
176 consists of 2 bytes xsize and xsize
177 bytes of data.
178 Read byte-by-byte (least significant
179 byte first) to make sure we abort
180 cleanly when the xsize is truncated
181 after the first byte. */
182 uint16_t xsize = 0;
183
184 if ((unsigned)(c-compr) < comprlen) {
185 xsize += *c;
186 c++;
187 }
188 if ((unsigned)(c-compr) < comprlen) {
189 xsize += *c << 8;
190 c++;
191 }
192
193 c += xsize;
194 }
195
196 if (flags & (1 << 3)) {
197 /* A null terminated filename */
198
199 while ((unsigned)(c - compr) < comprlen && *c != '\0') {
200 c++;
201 }
202
203 c++;
204 }
205
206 if (flags & (1 << 4)) {
207 /* A null terminated comment */
208
209 while ((unsigned)(c - compr) < comprlen && *c != '\0') {
210 c++;
211 }
212
213 c++;
214 }
215
216
217 if ((unsigned)(c - compr) > comprlen) {
218 ZLIB_PREFIX(inflateEnd)inflateEnd(&strm);
219 goto exit_err;
220 }
221 /* Drop gzip header */
222 comprlen -= (unsigned)(c - compr);
223 next = c;
224
225 ZLIB_PREFIX(inflateReset)inflateReset(&strm);
226 strm.next_in = next;
227 strm.avail_in = comprlen;
228
229 ZLIB_PREFIX(inflateEnd)inflateEnd(&strm);
230 err = ZLIB_PREFIX(inflateInit2)(&strm, wbits)inflateInit2_((&strm), (wbits), "1.3.1", (int)sizeof(z_stream
))
;
231 inits_done++;
232 if (err != Z_OK0) {
233 goto exit_err;
234 }
235 } else if (err == Z_DATA_ERROR(-3) && inflate_passes == 0 &&
236 inits_done <= 3) {
237
238 /*
239 * Re-init the stream with a negative
240 * MAX_WBITS. This is necessary due to
241 * some servers (Apache) not sending
242 * the deflate header with the
243 * content-encoded response.
244 */
245 wbits = -MAX_WBITS15;
246
247 ZLIB_PREFIX(inflateReset)inflateReset(&strm);
248
249 strm.next_in = next;
250 strm.avail_in = comprlen;
251
252 ZLIB_PREFIX(inflateEnd)inflateEnd(&strm);
253 strm.next_out = strmbuf;
254 strm.avail_out = bufsiz;
255
256 err = ZLIB_PREFIX(inflateInit2)(&strm, wbits)inflateInit2_((&strm), (wbits), "1.3.1", (int)sizeof(z_stream
))
;
257
258 inits_done++;
259
260 if (err != Z_OK0) {
261 goto exit_err;
262 }
263 } else {
264 ZLIB_PREFIX(inflateEnd)inflateEnd(&strm);
265
266 if (!inflate_passes) {
267 goto exit_err;
268 }
269
270 break;
271 }
272 }
273
274 ws_debug("inflate() total passes: %u\n", inflate_passes)do { if (1) { ws_log_full("Epan", LOG_LEVEL_DEBUG, "epan/tvbuff_zlib.c"
, 274, __func__, "inflate() total passes: %u\n", inflate_passes
); } } while (0)
;
25
Taking true branch
26
Loop condition is false. Exiting loop
275 ws_debug("bytes in: %u\nbytes out: %u\n\n", bytes_in, bytes_out)do { if (1) { ws_log_full("Epan", LOG_LEVEL_DEBUG, "epan/tvbuff_zlib.c"
, 275, __func__, "bytes in: %u\nbytes out: %u\n\n", bytes_in
, bytes_out); } } while (0)
;
27
Taking true branch
28
Loop condition is false. Exiting loop
276
277 if (inflate_passes
28.1
'inflate_passes' is 1
) {
29
Taking true branch
278 /* g_realloc(..., 0) is well-defined, returns NULL. */
279 strmbuf = (uint8_t*)g_realloc(strmbuf, bytes_out);
30
Memory is allocated
280 uncompr_tvb = tvb_new_real_data(strmbuf, bytes_out, bytes_out);
31
Potential leak of memory pointed to by 'strmbuf'
281 tvb_set_free_cb(uncompr_tvb, g_free);
282 }
283 wmem_free(NULL((void*)0), compr);
284 return uncompr_tvb;
285
286exit_err:
287 wmem_free(NULL((void*)0), compr);
288 g_free(strmbuf)(__builtin_object_size ((strmbuf), 0) != ((size_t) - 1)) ? g_free_sized
(strmbuf, __builtin_object_size ((strmbuf), 0)) : (g_free) (
strmbuf)
;
289 return NULL((void*)0);
290}
291#else /* USE_ZLIB_OR_ZLIBNG */
292tvbuff_t *
293tvb_uncompress_zlib(tvbuff_t *tvb _U___attribute__((unused)), const unsigned offset _U___attribute__((unused)), unsigned comprlen _U___attribute__((unused)))
294{
295 return NULL((void*)0);
296}
297#endif /* USE_ZLIB_OR_ZLIBNG */
298
299tvbuff_t *
300tvb_child_uncompress_zlib(tvbuff_t *parent, tvbuff_t *tvb, const unsigned offset, unsigned comprlen)
301{
302 tvbuff_t *new_tvb = tvb_uncompress_zlib(tvb, offset, comprlen);
1
Calling 'tvb_uncompress_zlib'
303 if (new_tvb)
304 tvb_set_child_real_data_tvbuff (parent, new_tvb);
305 return new_tvb;
306}
307
308/*
309 * Editor modelines - https://www.wireshark.org/tools/modelines.html
310 *
311 * Local variables:
312 * c-basic-offset: 8
313 * tab-width: 8
314 * indent-tabs-mode: t
315 * End:
316 *
317 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
318 * :indentSize=8:tabSize=8:noTabs=false:
319 */