Bug Summary

File:build-scan/../src/basic/hexdecoct.c
Warning:line 600, column 24
Potential leak of memory pointed to by 'x'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name hexdecoct.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -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 -mframe-pointer=all -relaxed-aliasing -menable-no-infs -menable-no-nans -menable-unsafe-fp-math -fno-signed-zeros -mreassociate -freciprocal-math -fdenormal-fp-math=preserve-sign,preserve-sign -ffp-contract=fast -fno-rounding-math -ffast-math -ffinite-math-only -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.0.0 -include config.h -I src/basic/libbasic.a.p -I src/basic -I ../src/basic -I src/shared -I ../src/shared -I src/systemd -I ../src/systemd -I src/journal -I ../src/journal -I src/journal-remote -I ../src/journal-remote -I src/nspawn -I ../src/nspawn -I src/resolve -I ../src/resolve -I src/timesync -I ../src/timesync -I ../src/time-wait-sync -I src/login -I ../src/login -I src/udev -I ../src/udev -I src/libudev -I ../src/libudev -I src/core -I ../src/core -I ../src/libsystemd/sd-bus -I ../src/libsystemd/sd-device -I ../src/libsystemd/sd-hwdb -I ../src/libsystemd/sd-id128 -I ../src/libsystemd/sd-netlink -I ../src/libsystemd/sd-network -I src/libsystemd-network -I ../src/libsystemd-network -I . -I .. -I /usr/include/blkid -I /usr/include/libmount -D _FILE_OFFSET_BITS=64 -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wwrite-strings -Wno-unused-parameter -Wno-missing-field-initializers -Wno-unused-result -Wno-format-signedness -Wno-error=nonnull -std=gnu99 -fconst-strings -fdebug-compilation-dir /home/mrc0mmand/repos/@redhat-plumbers/systemd-rhel8/build-scan -ferror-limit 19 -fvisibility default -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -analyzer-output=html -faddrsig -o /tmp/scan-build-2021-07-16-221226-1465241-1 -x c ../src/basic/hexdecoct.c
1/* SPDX-License-Identifier: LGPL-2.1+ */
2
3#include <ctype.h>
4#include <errno(*__errno_location ()).h>
5#include <stdint.h>
6#include <stdlib.h>
7
8#include "alloc-util.h"
9#include "hexdecoct.h"
10#include "macro.h"
11#include "string-util.h"
12#include "util.h"
13
14char octchar(int x) {
15 return '0' + (x & 7);
16}
17
18int unoctchar(char c) {
19
20 if (c >= '0' && c <= '7')
21 return c - '0';
22
23 return -EINVAL22;
24}
25
26char decchar(int x) {
27 return '0' + (x % 10);
28}
29
30int undecchar(char c) {
31
32 if (c >= '0' && c <= '9')
33 return c - '0';
34
35 return -EINVAL22;
36}
37
38char hexchar(int x) {
39 static const char table[16] = "0123456789abcdef";
40
41 return table[x & 15];
42}
43
44int unhexchar(char c) {
45
46 if (c >= '0' && c <= '9')
47 return c - '0';
48
49 if (c >= 'a' && c <= 'f')
50 return c - 'a' + 10;
51
52 if (c >= 'A' && c <= 'F')
53 return c - 'A' + 10;
54
55 return -EINVAL22;
56}
57
58char *hexmem(const void *p, size_t l) {
59 const uint8_t *x;
60 char *r, *z;
61
62 z = r = new(char, l * 2 + 1)((char*) malloc_multiply(sizeof(char), (l * 2 + 1)));
63 if (!r)
64 return NULL((void*)0);
65
66 for (x = p; x < (const uint8_t*) p + l; x++) {
67 *(z++) = hexchar(*x >> 4);
68 *(z++) = hexchar(*x & 15);
69 }
70
71 *z = 0;
72 return r;
73}
74
75static int unhex_next(const char **p, size_t *l) {
76 int r;
77
78 assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("p"), "../src/basic/hexdecoct.c", 78, __PRETTY_FUNCTION__
); } while (0)
;
79 assert(l)do { if ((__builtin_expect(!!(!(l)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("l"), "../src/basic/hexdecoct.c", 79, __PRETTY_FUNCTION__
); } while (0)
;
80
81 /* Find the next non-whitespace character, and decode it. We
82 * greedily skip all preceeding and all following whitespace. */
83
84 for (;;) {
85 if (*l == 0)
86 return -EPIPE32;
87
88 if (!strchr(WHITESPACE" \t\n\r", **p))
89 break;
90
91 /* Skip leading whitespace */
92 (*p)++, (*l)--;
93 }
94
95 r = unhexchar(**p);
96 if (r < 0)
97 return r;
98
99 for (;;) {
100 (*p)++, (*l)--;
101
102 if (*l == 0 || !strchr(WHITESPACE" \t\n\r", **p))
103 break;
104
105 /* Skip following whitespace */
106 }
107
108 return r;
109}
110
111int unhexmem(const char *p, size_t l, void **ret, size_t *ret_len) {
112 _cleanup_free___attribute__((cleanup(freep))) uint8_t *buf = NULL((void*)0);
113 const char *x;
114 uint8_t *z;
115
116 assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret"), "../src/basic/hexdecoct.c", 116,
__PRETTY_FUNCTION__); } while (0)
;
117 assert(ret_len)do { if ((__builtin_expect(!!(!(ret_len)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret_len"), "../src/basic/hexdecoct.c", 117
, __PRETTY_FUNCTION__); } while (0)
;
118 assert(p || l == 0)do { if ((__builtin_expect(!!(!(p || l == 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("p || l == 0"), "../src/basic/hexdecoct.c"
, 118, __PRETTY_FUNCTION__); } while (0)
;
119
120 if (l == (size_t) -1)
121 l = strlen(p);
122
123 /* Note that the calculation of memory size is an upper boundary, as we ignore whitespace while decoding */
124 buf = malloc((l + 1) / 2 + 1);
125 if (!buf)
126 return -ENOMEM12;
127
128 for (x = p, z = buf;;) {
129 int a, b;
130
131 a = unhex_next(&x, &l);
132 if (a == -EPIPE32) /* End of string */
133 break;
134 if (a < 0)
135 return a;
136
137 b = unhex_next(&x, &l);
138 if (b < 0)
139 return b;
140
141 *(z++) = (uint8_t) a << 4 | (uint8_t) b;
142 }
143
144 *z = 0;
145
146 *ret_len = (size_t) (z - buf);
147 *ret = TAKE_PTR(buf)({ typeof(buf) _ptr_ = (buf); (buf) = ((void*)0); _ptr_; });
148
149 return 0;
150}
151
152/* https://tools.ietf.org/html/rfc4648#section-6
153 * Notice that base32hex differs from base32 in the alphabet it uses.
154 * The distinction is that the base32hex representation preserves the
155 * order of the underlying data when compared as bytestrings, this is
156 * useful when representing NSEC3 hashes, as one can then verify the
157 * order of hashes directly from their representation. */
158char base32hexchar(int x) {
159 static const char table[32] = "0123456789"
160 "ABCDEFGHIJKLMNOPQRSTUV";
161
162 return table[x & 31];
163}
164
165int unbase32hexchar(char c) {
166 unsigned offset;
167
168 if (c >= '0' && c <= '9')
169 return c - '0';
170
171 offset = '9' - '0' + 1;
172
173 if (c >= 'A' && c <= 'V')
174 return c - 'A' + offset;
175
176 return -EINVAL22;
177}
178
179char *base32hexmem(const void *p, size_t l, bool_Bool padding) {
180 char *r, *z;
181 const uint8_t *x;
182 size_t len;
183
184 assert(p || l == 0)do { if ((__builtin_expect(!!(!(p || l == 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("p || l == 0"), "../src/basic/hexdecoct.c"
, 184, __PRETTY_FUNCTION__); } while (0)
;
185
186 if (padding)
187 /* five input bytes makes eight output bytes, padding is added so we must round up */
188 len = 8 * (l + 4) / 5;
189 else {
190 /* same, but round down as there is no padding */
191 len = 8 * l / 5;
192
193 switch (l % 5) {
194 case 4:
195 len += 7;
196 break;
197 case 3:
198 len += 5;
199 break;
200 case 2:
201 len += 4;
202 break;
203 case 1:
204 len += 2;
205 break;
206 }
207 }
208
209 z = r = malloc(len + 1);
210 if (!r)
211 return NULL((void*)0);
212
213 for (x = p; x < (const uint8_t*) p + (l / 5) * 5; x += 5) {
214 /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ
215 * x[3] == QQQQQQQQ; x[4] == WWWWWWWW */
216 *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
217 *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
218 *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
219 *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
220 *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */
221 *(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */
222 *(z++) = base32hexchar((x[3] & 3) << 3 | x[4] >> 5); /* 000QQWWW */
223 *(z++) = base32hexchar((x[4] & 31)); /* 000WWWWW */
224 }
225
226 switch (l % 5) {
227 case 4:
228 *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
229 *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
230 *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
231 *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
232 *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */
233 *(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */
234 *(z++) = base32hexchar((x[3] & 3) << 3); /* 000QQ000 */
235 if (padding)
236 *(z++) = '=';
237
238 break;
239
240 case 3:
241 *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
242 *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
243 *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
244 *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
245 *(z++) = base32hexchar((x[2] & 15) << 1); /* 000ZZZZ0 */
246 if (padding) {
247 *(z++) = '=';
248 *(z++) = '=';
249 *(z++) = '=';
250 }
251
252 break;
253
254 case 2:
255 *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
256 *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
257 *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
258 *(z++) = base32hexchar((x[1] & 1) << 4); /* 000Y0000 */
259 if (padding) {
260 *(z++) = '=';
261 *(z++) = '=';
262 *(z++) = '=';
263 *(z++) = '=';
264 }
265
266 break;
267
268 case 1:
269 *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
270 *(z++) = base32hexchar((x[0] & 7) << 2); /* 000XXX00 */
271 if (padding) {
272 *(z++) = '=';
273 *(z++) = '=';
274 *(z++) = '=';
275 *(z++) = '=';
276 *(z++) = '=';
277 *(z++) = '=';
278 }
279
280 break;
281 }
282
283 *z = 0;
284 return r;
285}
286
287int unbase32hexmem(const char *p, size_t l, bool_Bool padding, void **mem, size_t *_len) {
288 _cleanup_free___attribute__((cleanup(freep))) uint8_t *r = NULL((void*)0);
289 int a, b, c, d, e, f, g, h;
290 uint8_t *z;
291 const char *x;
292 size_t len;
293 unsigned pad = 0;
294
295 assert(p || l == 0)do { if ((__builtin_expect(!!(!(p || l == 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("p || l == 0"), "../src/basic/hexdecoct.c"
, 295, __PRETTY_FUNCTION__); } while (0)
;
296 assert(mem)do { if ((__builtin_expect(!!(!(mem)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("mem"), "../src/basic/hexdecoct.c", 296,
__PRETTY_FUNCTION__); } while (0)
;
297 assert(_len)do { if ((__builtin_expect(!!(!(_len)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("_len"), "../src/basic/hexdecoct.c", 297
, __PRETTY_FUNCTION__); } while (0)
;
298
299 if (l == (size_t) -1)
300 l = strlen(p);
301
302 /* padding ensures any base32hex input has input divisible by 8 */
303 if (padding && l % 8 != 0)
304 return -EINVAL22;
305
306 if (padding) {
307 /* strip the padding */
308 while (l > 0 && p[l - 1] == '=' && pad < 7) {
309 pad++;
310 l--;
311 }
312 }
313
314 /* a group of eight input bytes needs five output bytes, in case of
315 * padding we need to add some extra bytes */
316 len = (l / 8) * 5;
317
318 switch (l % 8) {
319 case 7:
320 len += 4;
321 break;
322 case 5:
323 len += 3;
324 break;
325 case 4:
326 len += 2;
327 break;
328 case 2:
329 len += 1;
330 break;
331 case 0:
332 break;
333 default:
334 return -EINVAL22;
335 }
336
337 z = r = malloc(len + 1);
338 if (!r)
339 return -ENOMEM12;
340
341 for (x = p; x < p + (l / 8) * 8; x += 8) {
342 /* a == 000XXXXX; b == 000YYYYY; c == 000ZZZZZ; d == 000WWWWW
343 * e == 000SSSSS; f == 000QQQQQ; g == 000VVVVV; h == 000RRRRR */
344 a = unbase32hexchar(x[0]);
345 if (a < 0)
346 return -EINVAL22;
347
348 b = unbase32hexchar(x[1]);
349 if (b < 0)
350 return -EINVAL22;
351
352 c = unbase32hexchar(x[2]);
353 if (c < 0)
354 return -EINVAL22;
355
356 d = unbase32hexchar(x[3]);
357 if (d < 0)
358 return -EINVAL22;
359
360 e = unbase32hexchar(x[4]);
361 if (e < 0)
362 return -EINVAL22;
363
364 f = unbase32hexchar(x[5]);
365 if (f < 0)
366 return -EINVAL22;
367
368 g = unbase32hexchar(x[6]);
369 if (g < 0)
370 return -EINVAL22;
371
372 h = unbase32hexchar(x[7]);
373 if (h < 0)
374 return -EINVAL22;
375
376 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
377 *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
378 *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
379 *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */
380 *(z++) = (uint8_t) g << 5 | (uint8_t) h; /* VVVRRRRR */
381 }
382
383 switch (l % 8) {
384 case 7:
385 a = unbase32hexchar(x[0]);
386 if (a < 0)
387 return -EINVAL22;
388
389 b = unbase32hexchar(x[1]);
390 if (b < 0)
391 return -EINVAL22;
392
393 c = unbase32hexchar(x[2]);
394 if (c < 0)
395 return -EINVAL22;
396
397 d = unbase32hexchar(x[3]);
398 if (d < 0)
399 return -EINVAL22;
400
401 e = unbase32hexchar(x[4]);
402 if (e < 0)
403 return -EINVAL22;
404
405 f = unbase32hexchar(x[5]);
406 if (f < 0)
407 return -EINVAL22;
408
409 g = unbase32hexchar(x[6]);
410 if (g < 0)
411 return -EINVAL22;
412
413 /* g == 000VV000 */
414 if (g & 7)
415 return -EINVAL22;
416
417 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
418 *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
419 *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
420 *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */
421
422 break;
423 case 5:
424 a = unbase32hexchar(x[0]);
425 if (a < 0)
426 return -EINVAL22;
427
428 b = unbase32hexchar(x[1]);
429 if (b < 0)
430 return -EINVAL22;
431
432 c = unbase32hexchar(x[2]);
433 if (c < 0)
434 return -EINVAL22;
435
436 d = unbase32hexchar(x[3]);
437 if (d < 0)
438 return -EINVAL22;
439
440 e = unbase32hexchar(x[4]);
441 if (e < 0)
442 return -EINVAL22;
443
444 /* e == 000SSSS0 */
445 if (e & 1)
446 return -EINVAL22;
447
448 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
449 *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
450 *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
451
452 break;
453 case 4:
454 a = unbase32hexchar(x[0]);
455 if (a < 0)
456 return -EINVAL22;
457
458 b = unbase32hexchar(x[1]);
459 if (b < 0)
460 return -EINVAL22;
461
462 c = unbase32hexchar(x[2]);
463 if (c < 0)
464 return -EINVAL22;
465
466 d = unbase32hexchar(x[3]);
467 if (d < 0)
468 return -EINVAL22;
469
470 /* d == 000W0000 */
471 if (d & 15)
472 return -EINVAL22;
473
474 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
475 *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
476
477 break;
478 case 2:
479 a = unbase32hexchar(x[0]);
480 if (a < 0)
481 return -EINVAL22;
482
483 b = unbase32hexchar(x[1]);
484 if (b < 0)
485 return -EINVAL22;
486
487 /* b == 000YYY00 */
488 if (b & 3)
489 return -EINVAL22;
490
491 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
492
493 break;
494 case 0:
495 break;
496 default:
497 return -EINVAL22;
498 }
499
500 *z = 0;
501
502 *mem = TAKE_PTR(r)({ typeof(r) _ptr_ = (r); (r) = ((void*)0); _ptr_; });
503 *_len = len;
504
505 return 0;
506}
507
508/* https://tools.ietf.org/html/rfc4648#section-4 */
509char base64char(int x) {
510 static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
511 "abcdefghijklmnopqrstuvwxyz"
512 "0123456789+/";
513 return table[x & 63];
514}
515
516int unbase64char(char c) {
517 unsigned offset;
518
519 if (c >= 'A' && c <= 'Z')
520 return c - 'A';
521
522 offset = 'Z' - 'A' + 1;
523
524 if (c >= 'a' && c <= 'z')
525 return c - 'a' + offset;
526
527 offset += 'z' - 'a' + 1;
528
529 if (c >= '0' && c <= '9')
530 return c - '0' + offset;
531
532 offset += '9' - '0' + 1;
533
534 if (c == '+')
535 return offset;
536
537 offset++;
538
539 if (c == '/')
540 return offset;
541
542 return -EINVAL22;
543}
544
545ssize_t base64mem(const void *p, size_t l, char **out) {
546 char *r, *z;
547 const uint8_t *x;
548
549 assert(p || l == 0)do { if ((__builtin_expect(!!(!(p || l == 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("p || l == 0"), "../src/basic/hexdecoct.c"
, 549, __PRETTY_FUNCTION__); } while (0)
;
4
Assuming 'p' is non-null
5
Taking false branch
6
Loop condition is false. Exiting loop
550 assert(out)do { if ((__builtin_expect(!!(!(out)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("out"), "../src/basic/hexdecoct.c", 550,
__PRETTY_FUNCTION__); } while (0)
;
7
Taking false branch
8
Loop condition is false. Exiting loop
551
552 /* three input bytes makes four output bytes, padding is added so we must round up */
553 z = r = malloc(4 * (l + 2) / 3 + 1);
9
Memory is allocated
554 if (!r)
10
Assuming 'r' is non-null
11
Taking false branch
555 return -ENOMEM12;
556
557 for (x = p; x < (const uint8_t*) p + (l / 3) * 3; x += 3) {
12
Assuming the condition is false
13
Loop condition is false. Execution continues on line 565
558 /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ */
559 *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
560 *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */
561 *(z++) = base64char((x[1] & 15) << 2 | x[2] >> 6); /* 00YYYYZZ */
562 *(z++) = base64char(x[2] & 63); /* 00ZZZZZZ */
563 }
564
565 switch (l % 3) {
14
'Default' branch taken. Execution continues on line 582
566 case 2:
567 *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
568 *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */
569 *(z++) = base64char((x[1] & 15) << 2); /* 00YYYY00 */
570 *(z++) = '=';
571
572 break;
573 case 1:
574 *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
575 *(z++) = base64char((x[0] & 3) << 4); /* 00XX0000 */
576 *(z++) = '=';
577 *(z++) = '=';
578
579 break;
580 }
581
582 *z = 0;
583 *out = r;
584 return z - r;
585}
586
587static int base64_append_width(
588 char **prefix, int plen,
589 const char *sep, int indent,
590 const void *p, size_t l,
591 int width) {
592
593 _cleanup_free___attribute__((cleanup(freep))) char *x = NULL((void*)0);
594 char *t, *s;
595 ssize_t slen, len, avail;
596 int line, lines;
597
598 len = base64mem(p, l, &x);
3
Calling 'base64mem'
15
Returned allocated memory via 3rd parameter
599 if (len
15.1
'len' is <= 0
<= 0)
16
Taking true branch
600 return len;
17
Potential leak of memory pointed to by 'x'
601
602 lines = DIV_ROUND_UP(len, width)({ const typeof((len)) __unique_prefix_X20 = ((len)); const typeof
((width)) __unique_prefix_Y21 = ((width)); (__unique_prefix_X20
/ __unique_prefix_Y21 + !!(__unique_prefix_X20 % __unique_prefix_Y21
)); })
;
603
604 slen = strlen_ptr(sep);
605 t = realloc(*prefix, plen + 1 + slen + (indent + width + 1) * lines);
606 if (!t)
607 return -ENOMEM12;
608
609 memcpy_safe(t + plen, sep, slen);
610
611 for (line = 0, s = t + plen + slen, avail = len; line < lines; line++) {
612 int act = MIN(width, avail)__extension__ ({ const typeof((width)) __unique_prefix_A22 = (
(width)); const typeof((avail)) __unique_prefix_B23 = ((avail
)); __unique_prefix_A22 < __unique_prefix_B23 ? __unique_prefix_A22
: __unique_prefix_B23; })
;
613
614 if (line > 0 || sep) {
615 memset(s, ' ', indent);
616 s += indent;
617 }
618
619 memcpy(s, x + width * line, act);
620 s += act;
621 *(s++) = line < lines - 1 ? '\n' : '\0';
622 avail -= act;
623 }
624 assert(avail == 0)do { if ((__builtin_expect(!!(!(avail == 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("avail == 0"), "../src/basic/hexdecoct.c"
, 624, __PRETTY_FUNCTION__); } while (0)
;
625
626 *prefix = t;
627 return 0;
628}
629
630int base64_append(
631 char **prefix, int plen,
632 const void *p, size_t l,
633 int indent, int width) {
634
635 if (plen > width / 2 || plen + indent > width)
1
Assuming the condition is true
636 /* leave indent on the left, keep last column free */
637 return base64_append_width(prefix, plen, "\n", indent, p, l, width - indent - 1);
2
Calling 'base64_append_width'
638 else
639 /* leave plen on the left, keep last column free */
640 return base64_append_width(prefix, plen, NULL((void*)0), plen, p, l, width - plen - 1);
641}
642
643static int unbase64_next(const char **p, size_t *l) {
644 int ret;
645
646 assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("p"), "../src/basic/hexdecoct.c", 646, __PRETTY_FUNCTION__
); } while (0)
;
647 assert(l)do { if ((__builtin_expect(!!(!(l)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("l"), "../src/basic/hexdecoct.c", 647, __PRETTY_FUNCTION__
); } while (0)
;
648
649 /* Find the next non-whitespace character, and decode it. If we find padding, we return it as INT_MAX. We
650 * greedily skip all preceeding and all following whitespace. */
651
652 for (;;) {
653 if (*l == 0)
654 return -EPIPE32;
655
656 if (!strchr(WHITESPACE" \t\n\r", **p))
657 break;
658
659 /* Skip leading whitespace */
660 (*p)++, (*l)--;
661 }
662
663 if (**p == '=')
664 ret = INT_MAX2147483647; /* return padding as INT_MAX */
665 else {
666 ret = unbase64char(**p);
667 if (ret < 0)
668 return ret;
669 }
670
671 for (;;) {
672 (*p)++, (*l)--;
673
674 if (*l == 0)
675 break;
676 if (!strchr(WHITESPACE" \t\n\r", **p))
677 break;
678
679 /* Skip following whitespace */
680 }
681
682 return ret;
683}
684
685int unbase64mem(const char *p, size_t l, void **ret, size_t *ret_size) {
686 _cleanup_free___attribute__((cleanup(freep))) uint8_t *buf = NULL((void*)0);
687 const char *x;
688 uint8_t *z;
689 size_t len;
690
691 assert(p || l == 0)do { if ((__builtin_expect(!!(!(p || l == 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("p || l == 0"), "../src/basic/hexdecoct.c"
, 691, __PRETTY_FUNCTION__); } while (0)
;
692 assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret"), "../src/basic/hexdecoct.c", 692,
__PRETTY_FUNCTION__); } while (0)
;
693 assert(ret_size)do { if ((__builtin_expect(!!(!(ret_size)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret_size"), "../src/basic/hexdecoct.c",
693, __PRETTY_FUNCTION__); } while (0)
;
694
695 if (l == (size_t) -1)
696 l = strlen(p);
697
698 /* A group of four input bytes needs three output bytes, in case of padding we need to add two or three extra
699 * bytes. Note that this calculation is an upper boundary, as we ignore whitespace while decoding */
700 len = (l / 4) * 3 + (l % 4 != 0 ? (l % 4) - 1 : 0);
701
702 buf = malloc(len + 1);
703 if (!buf)
704 return -ENOMEM12;
705
706 for (x = p, z = buf;;) {
707 int a, b, c, d; /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */
708
709 a = unbase64_next(&x, &l);
710 if (a == -EPIPE32) /* End of string */
711 break;
712 if (a < 0)
713 return a;
714 if (a == INT_MAX2147483647) /* Padding is not allowed at the beginning of a 4ch block */
715 return -EINVAL22;
716
717 b = unbase64_next(&x, &l);
718 if (b < 0)
719 return b;
720 if (b == INT_MAX2147483647) /* Padding is not allowed at the second character of a 4ch block either */
721 return -EINVAL22;
722
723 c = unbase64_next(&x, &l);
724 if (c < 0)
725 return c;
726
727 d = unbase64_next(&x, &l);
728 if (d < 0)
729 return d;
730
731 if (c == INT_MAX2147483647) { /* Padding at the third character */
732
733 if (d != INT_MAX2147483647) /* If the third character is padding, the fourth must be too */
734 return -EINVAL22;
735
736 /* b == 00YY0000 */
737 if (b & 15)
738 return -EINVAL22;
739
740 if (l > 0) /* Trailing rubbish? */
741 return -ENAMETOOLONG36;
742
743 *(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */
744 break;
745 }
746
747 if (d == INT_MAX2147483647) {
748 /* c == 00ZZZZ00 */
749 if (c & 3)
750 return -EINVAL22;
751
752 if (l > 0) /* Trailing rubbish? */
753 return -ENAMETOOLONG36;
754
755 *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
756 *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
757 break;
758 }
759
760 *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
761 *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
762 *(z++) = (uint8_t) c << 6 | (uint8_t) d; /* ZZWWWWWW */
763 }
764
765 *z = 0;
766
767 *ret_size = (size_t) (z - buf);
768 *ret = TAKE_PTR(buf)({ typeof(buf) _ptr_ = (buf); (buf) = ((void*)0); _ptr_; });
769
770 return 0;
771}
772
773void hexdump(FILE *f, const void *p, size_t s) {
774 const uint8_t *b = p;
775 unsigned n = 0;
776
777 assert(b || s == 0)do { if ((__builtin_expect(!!(!(b || s == 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("b || s == 0"), "../src/basic/hexdecoct.c"
, 777, __PRETTY_FUNCTION__); } while (0)
;
778
779 if (!f)
780 f = stdoutstdout;
781
782 while (s > 0) {
783 size_t i;
784
785 fprintf(f, "%04x ", n);
786
787 for (i = 0; i < 16; i++) {
788
789 if (i >= s)
790 fputs(" ", f);
791 else
792 fprintf(f, "%02x ", b[i]);
793
794 if (i == 7)
795 fputc(' ', f);
796 }
797
798 fputc(' ', f);
799
800 for (i = 0; i < 16; i++) {
801
802 if (i >= s)
803 fputc(' ', f);
804 else
805 fputc(isprint(b[i])((*__ctype_b_loc ())[(int) ((b[i]))] & (unsigned short int
) _ISprint)
? (char) b[i] : '.', f);
806 }
807
808 fputc('\n', f);
809
810 if (s < 16)
811 break;
812
813 n += 16;
814 b += 16;
815 s -= 16;
816 }
817}