| File: | builds/wireshark/wireshark/epan/tvbuff_base64.c |
| Warning: | line 249, column 9 Potential leak of memory pointed to by 'data' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* tvbuff_base64.c | |||
| 2 | * Base-64 tvbuff implementation (based on real tvb) | |||
| 3 | * | |||
| 4 | * Wireshark - Network traffic analyzer | |||
| 5 | * By Gerald Combs <[email protected]> | |||
| 6 | * Copyright 1998 Gerald Combs | |||
| 7 | * | |||
| 8 | * SPDX-License-Identifier: GPL-2.0-or-later | |||
| 9 | */ | |||
| 10 | ||||
| 11 | #include "config.h" | |||
| 12 | ||||
| 13 | #include <glib.h> | |||
| 14 | ||||
| 15 | #include <epan/tvbuff.h> | |||
| 16 | #include <wsutil/ws_padding_to.h> | |||
| 17 | #include "proto.h" | |||
| 18 | ||||
| 19 | /* Copy of glib function modified for base64uri */ | |||
| 20 | ||||
| 21 | static const unsigned char mime_base64uri_rank[256] = { | |||
| 22 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, | |||
| 23 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, | |||
| 24 | 255,255,255,255,255,255,255,255,255,255,255, 255,255,63,255,255, | |||
| 25 | 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,255,255,255, 0,255,255, | |||
| 26 | 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, | |||
| 27 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,255,255,255,255, 63, | |||
| 28 | 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, | |||
| 29 | 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,255,255,255,255,255, | |||
| 30 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, | |||
| 31 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, | |||
| 32 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, | |||
| 33 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, | |||
| 34 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, | |||
| 35 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, | |||
| 36 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, | |||
| 37 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, | |||
| 38 | }; | |||
| 39 | /** | |||
| 40 | * Copy of glib function modified for base64uri | |||
| 41 | * g_base64uri_decode_step: (skip) | |||
| 42 | * @in: (array length=len) (element-type uint8_t): binary input data | |||
| 43 | * @len: max length of @in data to decode | |||
| 44 | * @out: (out caller-allocates) (array) (element-type uint8_t): output buffer | |||
| 45 | * @state: (inout): Saved state between steps, initialize to 0 | |||
| 46 | * @save: (inout): Saved state between steps, initialize to 0 | |||
| 47 | * | |||
| 48 | * Incrementally decode a sequence of binary data from its Base-64 stringified | |||
| 49 | * representation. By calling this function multiple times you can convert | |||
| 50 | * data in chunks to avoid having to have the full encoded data in memory. | |||
| 51 | * | |||
| 52 | * The output buffer must be large enough to fit all the data that will | |||
| 53 | * be written to it. Since base64 encodes 3 bytes in 4 chars you need | |||
| 54 | * at least: (@len / 4) * 3 + 3 bytes (+ 3 may be needed in case of non-zero | |||
| 55 | * state). | |||
| 56 | * | |||
| 57 | * Returns: The number of bytes of output that was written | |||
| 58 | * | |||
| 59 | * Since: 2.12 | |||
| 60 | **/ | |||
| 61 | static size_t | |||
| 62 | g_base64uri_decode_step(const char* in, | |||
| 63 | size_t len, | |||
| 64 | unsigned char* out, | |||
| 65 | int* state, | |||
| 66 | unsigned* save) | |||
| 67 | { | |||
| 68 | const unsigned char* inptr; | |||
| 69 | unsigned char* outptr; | |||
| 70 | const unsigned char* inend; | |||
| 71 | unsigned char c, rank; | |||
| 72 | unsigned char last[2]; | |||
| 73 | unsigned int v; | |||
| 74 | int i; | |||
| 75 | ||||
| 76 | g_return_val_if_fail(in != NULL || len == 0, 0)do { if ((in != ((void*)0) || len == 0)) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "in != NULL || len == 0" ); return (0); } } while (0); | |||
| 77 | g_return_val_if_fail(out != NULL, 0)do { if ((out != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "out != NULL"); return (0); } } while (0); | |||
| 78 | g_return_val_if_fail(state != NULL, 0)do { if ((state != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "state != NULL"); return (0); } } while (0); | |||
| 79 | g_return_val_if_fail(save != NULL, 0)do { if ((save != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "save != NULL"); return (0); } } while (0); | |||
| 80 | ||||
| 81 | if (len == 0) | |||
| 82 | return 0; | |||
| 83 | ||||
| 84 | inend = (const unsigned char*)in + len; | |||
| 85 | outptr = out; | |||
| 86 | ||||
| 87 | /* convert 4 base64 bytes to 3 normal bytes */ | |||
| 88 | v = *save; | |||
| 89 | i = *state; | |||
| 90 | ||||
| 91 | last[0] = last[1] = 0; | |||
| 92 | ||||
| 93 | /* we use the sign in the state to determine if we got a padding character | |||
| 94 | in the previous sequence */ | |||
| 95 | if (i < 0) | |||
| 96 | { | |||
| 97 | i = -i; | |||
| 98 | last[0] = '='; | |||
| 99 | } | |||
| 100 | ||||
| 101 | inptr = (const unsigned char*)in; | |||
| 102 | while (inptr < inend) | |||
| 103 | { | |||
| 104 | c = *inptr++; | |||
| 105 | rank = mime_base64uri_rank[c]; | |||
| 106 | if (rank != 0xff) | |||
| 107 | { | |||
| 108 | last[1] = last[0]; | |||
| 109 | last[0] = c; | |||
| 110 | v = (v << 6) | rank; | |||
| 111 | i++; | |||
| 112 | if (i == 4) | |||
| 113 | { | |||
| 114 | *outptr++ = v >> 16; | |||
| 115 | if (last[1] != '=') | |||
| 116 | *outptr++ = v >> 8; | |||
| 117 | if (last[0] != '=') | |||
| 118 | *outptr++ = v; | |||
| 119 | i = 0; | |||
| 120 | } | |||
| 121 | } | |||
| 122 | } | |||
| 123 | ||||
| 124 | *save = v; | |||
| 125 | *state = last[0] == '=' ? -i : i; | |||
| 126 | ||||
| 127 | return outptr - out; | |||
| 128 | } | |||
| 129 | /** | |||
| 130 | * Copy of glib function modified for base64uri | |||
| 131 | * g_base64uri_decode: | |||
| 132 | * @text: (not nullable): zero-terminated string with base64 text to decode | |||
| 133 | * @out_len: (out): The length of the decoded data is written here | |||
| 134 | * | |||
| 135 | * Decode a sequence of Base-64 encoded text into binary data. Note | |||
| 136 | * that the returned binary data is not necessarily zero-terminated, | |||
| 137 | * so it should not be used as a character string. | |||
| 138 | * | |||
| 139 | * Returns: (transfer full) (array length=out_len) (element-type uint8_t): | |||
| 140 | * newly allocated buffer containing the binary data | |||
| 141 | * that @text represents. The returned buffer must | |||
| 142 | * be freed with g_free(). | |||
| 143 | * | |||
| 144 | * Since: 2.12 | |||
| 145 | */ | |||
| 146 | static unsigned char* | |||
| 147 | g_base64uri_decode(const char* text, | |||
| 148 | size_t* out_len) | |||
| 149 | { | |||
| 150 | const char pad[4] = "==="; | |||
| 151 | unsigned char* ret; | |||
| 152 | size_t input_length; | |||
| 153 | int state = 0; | |||
| 154 | unsigned save = 0; | |||
| 155 | ||||
| 156 | g_return_val_if_fail(text != NULL, NULL)do { if ((text != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "text != NULL"); return (((void*)0)); } } while (0); | |||
| 157 | g_return_val_if_fail(out_len != NULL, NULL)do { if ((out_len != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "out_len != NULL" ); return (((void*)0)); } } while (0); | |||
| 158 | ||||
| 159 | /* XXX - We could just pass in the length instead of calling strlen, | |||
| 160 | * which would allow using tvb_get_ptr. */ | |||
| 161 | input_length = strlen(text); | |||
| 162 | ||||
| 163 | /* In base64url padding is optional. | |||
| 164 | * https://www.rfc-editor.org/info/rfc4648/#section-5 | |||
| 165 | * https://www.rfc-editor.org/info/rfc4648/#section-3.2 | |||
| 166 | * | |||
| 167 | * https://www.rfc-editor.org/info/rfc4648/#section-4 | |||
| 168 | */ | |||
| 169 | ||||
| 170 | /* We can use a smaller limit here, since we know the saved state is 0, | |||
| 171 | +1 used to avoid calling g_malloc0(0), and hence returning NULL */ | |||
| 172 | /* Add an additional 1 to ensure there's enough space for the padding | |||
| 173 | * omitted case. (g_base64_decode_step mentions adding + 3 in the | |||
| 174 | * case of non-zero state, but that's only if the extra bytes added | |||
| 175 | * in are not all '='.) */ | |||
| 176 | ret = (unsigned char * )g_malloc0((input_length / 4) * 3 + 2); | |||
| 177 | ||||
| 178 | *out_len = g_base64uri_decode_step(text, input_length, ret, &state, &save); | |||
| 179 | ||||
| 180 | input_length = WS_PADDING_TO_4(input_length)((4U - ((input_length) % 4U)) % 4U); | |||
| 181 | if (input_length
| |||
| 182 | *out_len += g_base64uri_decode_step(pad, input_length, &ret[*out_len], &state, &save); | |||
| 183 | ||||
| 184 | return ret; | |||
| 185 | } | |||
| 186 | ||||
| 187 | tvbuff_t * | |||
| 188 | base64_to_tvb(tvbuff_t *parent, const char *base64) | |||
| 189 | { | |||
| 190 | tvbuff_t *tvb; | |||
| 191 | uint8_t *data; | |||
| 192 | size_t len; | |||
| 193 | ||||
| 194 | data = g_base64_decode(base64, &len); | |||
| 195 | tvb = tvb_new_child_real_data(parent, data, (unsigned)len, (unsigned)len); | |||
| 196 | ||||
| 197 | tvb_set_free_cb(tvb, g_free); | |||
| 198 | ||||
| 199 | return tvb; | |||
| 200 | } | |||
| 201 | ||||
| 202 | tvbuff_t* | |||
| 203 | base64_tvb_to_new_tvb(tvbuff_t* parent, unsigned offset, unsigned length) | |||
| 204 | { | |||
| 205 | tvbuff_t* tvb; | |||
| 206 | uint8_t* data, *tmp; | |||
| 207 | size_t len; | |||
| 208 | ||||
| 209 | /* g_base64_decode only requires NULL termination, not a valid UTF-8 | |||
| 210 | * or ASCII string (it silently skips over invalid bytes, we don't | |||
| 211 | * check that either). So tvb_get_raw_bytes_as_string() would work, | |||
| 212 | * but we would need to check the length before allocating the buffer | |||
| 213 | * to avoid a memory leak (or push a CLEANUP function on exception). | |||
| 214 | * | |||
| 215 | * We could also implement our own function that took a length and | |||
| 216 | * didn't require NULL termination. We could also do that by simply | |||
| 217 | * calling g_base64_decode_step() directly. | |||
| 218 | */ | |||
| 219 | tmp = tvb_get_string_enc(NULL((void*)0), parent, offset, length, ENC_ASCII0x00000000); | |||
| 220 | data = g_base64_decode((const char*)tmp, &len); | |||
| 221 | wmem_free(NULL((void*)0), tmp); | |||
| 222 | ||||
| 223 | tvb = tvb_new_child_real_data(parent, data, (unsigned)len, (unsigned)len); | |||
| 224 | ||||
| 225 | tvb_set_free_cb(tvb, g_free); | |||
| 226 | ||||
| 227 | return tvb; | |||
| 228 | } | |||
| 229 | ||||
| 230 | tvbuff_t* | |||
| 231 | base64uri_tvb_to_new_tvb(tvbuff_t* parent, unsigned offset, unsigned length) | |||
| 232 | { | |||
| 233 | tvbuff_t* tvb; | |||
| 234 | uint8_t* data, *tmp; | |||
| 235 | size_t len = 0; | |||
| 236 | ||||
| 237 | #if 0 | |||
| 238 | size_t expected_output_len; | |||
| 239 | expected_output_length = (input_length / 4) * 3; | |||
| 240 | /* Note that input_length % 4 == 1 represents bad input and _should_ | |||
| 241 | * never happen. Perhaps we should just consider it a failure. */ | |||
| 242 | experted_output_length += ((input_length % 4) + 1) / 2; | |||
| 243 | #endif | |||
| 244 | ||||
| 245 | tmp = tvb_get_string_enc(NULL((void*)0), parent, offset, length, ENC_ASCII0x00000000); | |||
| 246 | data = g_base64uri_decode((const char*)tmp, &len); | |||
| ||||
| 247 | wmem_free(NULL((void*)0), tmp); | |||
| 248 | ||||
| 249 | tvb = tvb_new_child_real_data(parent, data, (unsigned)len, (unsigned)len); | |||
| ||||
| 250 | ||||
| 251 | tvb_set_free_cb(tvb, g_free); | |||
| 252 | ||||
| 253 | return tvb; | |||
| 254 | } | |||
| 255 | /* | |||
| 256 | * Editor modelines - https://www.wireshark.org/tools/modelines.html | |||
| 257 | * | |||
| 258 | * Local Variables: | |||
| 259 | * c-basic-offset: 2 | |||
| 260 | * tab-width: 8 | |||
| 261 | * indent-tabs-mode: nil | |||
| 262 | * End: | |||
| 263 | * | |||
| 264 | * ex: set shiftwidth=2 tabstop=8 expandtab: | |||
| 265 | * :indentSize=2:tabSize=8:noTabs=true: | |||
| 266 | */ |