Coverage Report

Created: 2026-09-14 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fwupd/libfwupdplugin/fu-mem.c
Line
Count
Source
1
/*
2
 * Copyright 2017 Richard Hughes <richard@hughsie.com>
3
 *
4
 * SPDX-License-Identifier: LGPL-2.1-or-later
5
 */
6
7
0
#define G_LOG_DOMAIN "FuCommon"
8
9
#include "config.h"
10
11
#include "fwupd-error.h"
12
13
#include "fu-common.h"
14
#include "fu-mem-private.h"
15
#include "fu-string.h"
16
17
/**
18
 * fu_memwrite_uint16:
19
 * @buf: a writable buffer
20
 * @val_native: a value in host byte-order
21
 * @endian: an endian type, e.g. %G_LITTLE_ENDIAN
22
 *
23
 * Writes a value to a buffer using a specified endian.
24
 *
25
 * Since: 1.8.2
26
 **/
27
void
28
fu_memwrite_uint16(guint8 *buf, guint16 val_native, FuEndianType endian)
29
11.7M
{
30
11.7M
  guint16 val_hw;
31
11.7M
  switch (endian) {
32
462k
  case G_BIG_ENDIAN:
33
462k
    val_hw = GUINT16_TO_BE(val_native); /* nocheck:blocked */
34
462k
    break;
35
11.3M
  case G_LITTLE_ENDIAN:
36
11.3M
    val_hw = GUINT16_TO_LE(val_native); /* nocheck:blocked */
37
11.3M
    break;
38
0
  default:
39
0
    val_hw = val_native;
40
0
    break;
41
11.7M
  }
42
11.7M
  memcpy(buf, &val_hw, sizeof(val_hw)); /* nocheck:blocked */
43
11.7M
}
44
45
/**
46
 * fu_memwrite_uint24:
47
 * @buf: a writable buffer
48
 * @val_native: a value in host byte-order
49
 * @endian: an endian type, e.g. %G_LITTLE_ENDIAN
50
 *
51
 * Writes a value to a buffer using a specified endian.
52
 *
53
 * Since: 1.8.2
54
 **/
55
void
56
fu_memwrite_uint24(guint8 *buf, guint32 val_native, FuEndianType endian)
57
18.3k
{
58
18.3k
  guint32 val_hw;
59
18.3k
  switch (endian) {
60
0
  case G_BIG_ENDIAN:
61
0
    val_hw = GUINT32_TO_BE(val_native);      /* nocheck:blocked */
62
0
    memcpy(buf, ((const guint8 *)&val_hw) + 0x1, 0x3); /* nocheck:blocked */
63
0
    break;
64
18.3k
  case G_LITTLE_ENDIAN:
65
18.3k
    val_hw = GUINT32_TO_LE(val_native); /* nocheck:blocked */
66
18.3k
    memcpy(buf, &val_hw, 0x3);      /* nocheck:blocked */
67
18.3k
    break;
68
0
  default:
69
0
    g_assert_not_reached();
70
18.3k
  }
71
18.3k
}
72
73
/**
74
 * fu_memwrite_uint32:
75
 * @buf: a writable buffer
76
 * @val_native: a value in host byte-order
77
 * @endian: an endian type, e.g. %G_LITTLE_ENDIAN
78
 *
79
 * Writes a value to a buffer using a specified endian.
80
 *
81
 * Since: 1.8.2
82
 **/
83
void
84
fu_memwrite_uint32(guint8 *buf, guint32 val_native, FuEndianType endian)
85
1.02M
{
86
1.02M
  guint32 val_hw;
87
1.02M
  switch (endian) {
88
260k
  case G_BIG_ENDIAN:
89
260k
    val_hw = GUINT32_TO_BE(val_native); /* nocheck:blocked */
90
260k
    break;
91
761k
  case G_LITTLE_ENDIAN:
92
761k
    val_hw = GUINT32_TO_LE(val_native); /* nocheck:blocked */
93
761k
    break;
94
0
  default:
95
0
    val_hw = val_native;
96
0
    break;
97
1.02M
  }
98
1.02M
  memcpy(buf, &val_hw, sizeof(val_hw)); /* nocheck:blocked */
99
1.02M
}
100
101
/**
102
 * fu_memwrite_uint64:
103
 * @buf: a writable buffer
104
 * @val_native: a value in host byte-order
105
 * @endian: an endian type, e.g. %G_LITTLE_ENDIAN
106
 *
107
 * Writes a value to a buffer using a specified endian.
108
 *
109
 * Since: 1.8.2
110
 **/
111
void
112
fu_memwrite_uint64(guint8 *buf, guint64 val_native, FuEndianType endian)
113
11.3k
{
114
11.3k
  guint64 val_hw;
115
11.3k
  switch (endian) {
116
123
  case G_BIG_ENDIAN:
117
123
    val_hw = GUINT64_TO_BE(val_native); /* nocheck:blocked */
118
123
    break;
119
11.2k
  case G_LITTLE_ENDIAN:
120
11.2k
    val_hw = GUINT64_TO_LE(val_native); /* nocheck:blocked */
121
11.2k
    break;
122
0
  default:
123
0
    val_hw = val_native;
124
0
    break;
125
11.3k
  }
126
11.3k
  memcpy(buf, &val_hw, sizeof(val_hw)); /* nocheck:blocked */
127
11.3k
}
128
129
/**
130
 * fu_memread_uint16:
131
 * @buf: a readable buffer
132
 * @endian: an endian type, e.g. %G_LITTLE_ENDIAN
133
 *
134
 * Read a value from a buffer using a specified endian.
135
 *
136
 * Returns: a value in host byte-order
137
 *
138
 * Since: 1.8.2
139
 **/
140
guint16
141
fu_memread_uint16(const guint8 *buf, FuEndianType endian)
142
14.3M
{
143
14.3M
  guint16 val_hw;
144
14.3M
  guint16 val_native;
145
14.3M
  memcpy(&val_hw, buf, sizeof(val_hw)); /* nocheck:blocked */
146
14.3M
  switch (endian) {
147
17.1k
  case G_BIG_ENDIAN:
148
17.1k
    val_native = GUINT16_FROM_BE(val_hw); /* nocheck:blocked */
149
17.1k
    break;
150
14.3M
  case G_LITTLE_ENDIAN:
151
14.3M
    val_native = GUINT16_FROM_LE(val_hw); /* nocheck:blocked */
152
14.3M
    break;
153
0
  default:
154
0
    val_native = val_hw;
155
0
    break;
156
14.3M
  }
157
14.3M
  return val_native;
158
14.3M
}
159
160
/**
161
 * fu_memread_uint24:
162
 * @buf: a readable buffer
163
 * @endian: an endian type, e.g. %G_LITTLE_ENDIAN
164
 *
165
 * Read a value from a buffer using a specified endian.
166
 *
167
 * Returns: a value in host byte-order
168
 *
169
 * Since: 1.8.2
170
 **/
171
guint32
172
fu_memread_uint24(const guint8 *buf, FuEndianType endian)
173
149k
{
174
149k
  guint32 val_hw = 0;
175
149k
  guint32 val_native;
176
149k
  switch (endian) {
177
0
  case G_BIG_ENDIAN:
178
0
    memcpy(((guint8 *)&val_hw) + 0x1, buf, 0x3); /* nocheck:blocked */
179
0
    val_native = GUINT32_FROM_BE(val_hw);      /* nocheck:blocked */
180
0
    break;
181
149k
  case G_LITTLE_ENDIAN:
182
149k
    memcpy(&val_hw, buf, 0x3);        /* nocheck:blocked */
183
149k
    val_native = GUINT32_FROM_LE(val_hw); /* nocheck:blocked */
184
149k
    break;
185
0
  default:
186
0
    val_native = val_hw;
187
0
    break;
188
149k
  }
189
149k
  return val_native;
190
149k
}
191
192
/**
193
 * fu_memread_uint32:
194
 * @buf: a readable buffer
195
 * @endian: an endian type, e.g. %G_LITTLE_ENDIAN
196
 *
197
 * Read a value from a buffer using a specified endian.
198
 *
199
 * Returns: a value in host byte-order
200
 *
201
 * Since: 1.8.2
202
 **/
203
guint32
204
fu_memread_uint32(const guint8 *buf, FuEndianType endian)
205
9.48M
{
206
9.48M
  guint32 val_hw;
207
9.48M
  guint32 val_native;
208
9.48M
  memcpy(&val_hw, buf, sizeof(val_hw)); /* nocheck:blocked */
209
9.48M
  switch (endian) {
210
427k
  case G_BIG_ENDIAN:
211
427k
    val_native = GUINT32_FROM_BE(val_hw); /* nocheck:blocked */
212
427k
    break;
213
9.05M
  case G_LITTLE_ENDIAN:
214
9.05M
    val_native = GUINT32_FROM_LE(val_hw); /* nocheck:blocked */
215
9.05M
    break;
216
0
  default:
217
0
    val_native = val_hw;
218
0
    break;
219
9.48M
  }
220
9.48M
  return val_native;
221
9.48M
}
222
223
/**
224
 * fu_memread_uint64:
225
 * @buf: a readable buffer
226
 * @endian: an endian type, e.g. %G_LITTLE_ENDIAN
227
 *
228
 * Read a value from a buffer using a specified endian.
229
 *
230
 * Returns: a value in host byte-order
231
 *
232
 * Since: 1.8.2
233
 **/
234
guint64
235
fu_memread_uint64(const guint8 *buf, FuEndianType endian)
236
1.31M
{
237
1.31M
  guint64 val_hw;
238
1.31M
  guint64 val_native;
239
1.31M
  memcpy(&val_hw, buf, sizeof(val_hw)); /* nocheck:blocked */
240
1.31M
  switch (endian) {
241
131k
  case G_BIG_ENDIAN:
242
131k
    val_native = GUINT64_FROM_BE(val_hw); /* nocheck:blocked */
243
131k
    break;
244
1.18M
  case G_LITTLE_ENDIAN:
245
1.18M
    val_native = GUINT64_FROM_LE(val_hw); /* nocheck:blocked */
246
1.18M
    break;
247
0
  default:
248
0
    val_native = val_hw;
249
0
    break;
250
1.31M
  }
251
1.31M
  return val_native;
252
1.31M
}
253
254
/**
255
 * fu_memcmp_safe:
256
 * @buf1: a buffer
257
 * @buf1_sz: sizeof @buf1
258
 * @buf1_offset: offset into @buf1
259
 * @buf2: another buffer
260
 * @buf2_sz: sizeof @buf2
261
 * @buf2_offset: offset into @buf1
262
 * @n: number of bytes to compare from @buf1+@buf1_offset from
263
 * @error: (nullable): optional return location for an error
264
 *
265
 * Compares the buffers for equality.
266
 *
267
 * Returns: %TRUE if @buf1 and @buf2 are identical
268
 *
269
 * Since: 1.8.2
270
 **/
271
gboolean
272
fu_memcmp_safe(const guint8 *buf1,
273
         gsize buf1_sz,
274
         gsize buf1_offset,
275
         const guint8 *buf2,
276
         gsize buf2_sz,
277
         gsize buf2_offset,
278
         gsize n,
279
         GError **error)
280
0
{
281
0
  g_return_val_if_fail(buf1 != NULL, FALSE);
282
0
  g_return_val_if_fail(buf2 != NULL, FALSE);
283
0
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
284
285
0
  if (!fu_memchk_read(buf1_sz, buf1_offset, n, error))
286
0
    return FALSE;
287
0
  if (!fu_memchk_read(buf2_sz, buf2_offset, n, error))
288
0
    return FALSE;
289
290
  /* check matches */
291
0
  for (guint i = 0x0; i < n; i++) {
292
0
    if (buf1[buf1_offset + i] != buf2[buf2_offset + i]) {
293
0
      g_set_error(error,
294
0
            FWUPD_ERROR,
295
0
            FWUPD_ERROR_INVALID_DATA,
296
0
            "got 0x%02x, expected 0x%02x @ 0x%04x",
297
0
            buf1[buf1_offset + i],
298
0
            buf2[buf2_offset + i],
299
0
            i);
300
0
      return FALSE;
301
0
    }
302
0
  }
303
304
  /* success */
305
0
  return TRUE;
306
0
}
307
308
/**
309
 * fu_memchk_read:
310
 * @bufsz: maximum size of a buffer, typically `sizeof(buf)`
311
 * @offset: offset in bytes
312
 * @n: number of bytes
313
 * @error: (nullable): optional return location for an error
314
 *
315
 * Works out if reading from a buffer is safe. Providing the buffer sizes allows us to check for
316
 * buffer overflow.
317
 *
318
 * You don't need to use this function in "obviously correct" cases, nor should
319
 * you use it when performance is a concern. Only us it when you're not sure if
320
 * malicious data from a device or firmware could cause memory corruption.
321
 *
322
 * Returns: %TRUE if the access is safe, %FALSE otherwise
323
 *
324
 * Since: 1.9.1
325
 **/
326
gboolean
327
fu_memchk_read(gsize bufsz, gsize offset, gsize n, GError **error)
328
15.8M
{
329
15.8M
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
330
15.8M
  if (n == 0)
331
3
    return TRUE;
332
15.8M
  if (n > bufsz) {
333
434
    g_set_error(error,
334
434
          FWUPD_ERROR,
335
434
          FWUPD_ERROR_READ,
336
434
          "attempted to read 0x%02x bytes from buffer of 0x%02x",
337
434
          (guint)n,
338
434
          (guint)bufsz);
339
434
    return FALSE;
340
434
  }
341
15.8M
  if (fu_size_checked_add(offset, n) == G_MAXSIZE) {
342
0
    g_set_error(error,
343
0
          FWUPD_ERROR,
344
0
          FWUPD_ERROR_READ,
345
0
          "offset 0x%02x + 0x%02x overflowed",
346
0
          (guint)offset,
347
0
          (guint)n);
348
0
    return FALSE;
349
0
  }
350
15.8M
  if (offset > bufsz || n + offset > bufsz) {
351
829
    g_set_error(error,
352
829
          FWUPD_ERROR,
353
829
          FWUPD_ERROR_READ,
354
829
          "attempted to read 0x%02x bytes at offset 0x%02x from buffer of 0x%02x",
355
829
          (guint)n,
356
829
          (guint)offset,
357
829
          (guint)bufsz);
358
829
    return FALSE;
359
829
  }
360
15.8M
  return TRUE;
361
15.8M
}
362
363
/**
364
 * fu_memchk_write:
365
 * @bufsz: maximum size of a buffer, typically `sizeof(buf)`
366
 * @offset: offset in bytes
367
 * @n: number of bytes
368
 * @error: (nullable): optional return location for an error
369
 *
370
 * Works out if writing to a buffer is safe. Providing the buffer sizes allows us to check for
371
 * buffer overflow.
372
 *
373
 * You don't need to use this function in "obviously correct" cases, nor should
374
 * you use it when performance is a concern. Only us it when you're not sure if
375
 * malicious data from a device or firmware could cause memory corruption.
376
 *
377
 * Returns: %TRUE if the access is safe, %FALSE otherwise
378
 *
379
 * Since: 1.9.1
380
 **/
381
gboolean
382
fu_memchk_write(gsize bufsz, gsize offset, gsize n, GError **error)
383
17.4M
{
384
17.4M
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
385
17.4M
  if (n == 0)
386
0
    return TRUE;
387
17.4M
  if (n > bufsz) {
388
135
    g_set_error(error,
389
135
          FWUPD_ERROR,
390
135
          FWUPD_ERROR_WRITE,
391
135
          "attempted to write 0x%02x bytes to buffer of 0x%02x",
392
135
          (guint)n,
393
135
          (guint)bufsz);
394
135
    return FALSE;
395
135
  }
396
17.4M
  if (fu_size_checked_add(offset, n) == G_MAXSIZE) {
397
0
    g_set_error(error,
398
0
          FWUPD_ERROR,
399
0
          FWUPD_ERROR_WRITE,
400
0
          "offset 0x%02x + 0x%02x overflowed",
401
0
          (guint)offset,
402
0
          (guint)n);
403
0
    return FALSE;
404
0
  }
405
17.4M
  if (offset > bufsz || n + offset > bufsz) {
406
32
    g_set_error(error,
407
32
          FWUPD_ERROR,
408
32
          FWUPD_ERROR_WRITE,
409
32
          "attempted to write 0x%02x bytes at offset 0x%02x to buffer of 0x%02x",
410
32
          (guint)n,
411
32
          (guint)offset,
412
32
          (guint)bufsz);
413
32
    return FALSE;
414
32
  }
415
17.4M
  return TRUE;
416
17.4M
}
417
418
/**
419
 * fu_memcpy_safe:
420
 * @dst: destination buffer
421
 * @dst_sz: maximum size of @dst, typically `sizeof(dst)`
422
 * @dst_offset: offset in bytes into @dst to copy to
423
 * @src: source buffer
424
 * @src_sz: maximum size of @dst, typically `sizeof(src)`
425
 * @src_offset: offset in bytes into @src to copy from
426
 * @n: number of bytes to copy from @src+@offset from
427
 * @error: (nullable): optional return location for an error
428
 *
429
 * Copies some memory using memcpy in a safe way. Providing the buffer sizes
430
 * of both the destination and the source allows us to check for buffer overflow.
431
 *
432
 * Providing the buffer offsets also allows us to check reading past the end of
433
 * the source buffer. For this reason the caller should NEVER add an offset to
434
 * @src or @dst.
435
 *
436
 * You don't need to use this function in "obviously correct" cases, nor should
437
 * you use it when performance is a concern. Only us it when you're not sure if
438
 * malicious data from a device or firmware could cause memory corruption.
439
 *
440
 * Returns: %TRUE if the bytes were copied, %FALSE otherwise
441
 *
442
 * Since: 1.8.2
443
 **/
444
gboolean
445
fu_memcpy_safe(guint8 *dst,
446
         gsize dst_sz,
447
         gsize dst_offset,
448
         const guint8 *src,
449
         gsize src_sz,
450
         gsize src_offset,
451
         gsize n,
452
         GError **error)
453
15.2M
{
454
15.2M
  g_return_val_if_fail(dst != NULL, FALSE);
455
15.2M
  g_return_val_if_fail(src != NULL, FALSE);
456
15.2M
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
457
458
15.2M
  if (!fu_memchk_read(src_sz, src_offset, n, error))
459
844
    return FALSE;
460
15.2M
  if (!fu_memchk_write(dst_sz, dst_offset, n, error))
461
167
    return FALSE;
462
15.2M
  memcpy(dst + dst_offset, src + src_offset, n); /* nocheck:blocked */
463
15.2M
  return TRUE;
464
15.2M
}
465
466
/**
467
 * fu_memmem_safe:
468
 * @haystack: destination buffer
469
 * @haystack_sz: maximum size of @haystack, typically `sizeof(haystack)`
470
 * @needle: source buffer
471
 * @needle_sz: maximum size of @haystack, typically `sizeof(needle)`
472
 * @offset: (out) (nullable): offset in bytes @needle has been found in @haystack
473
 * @error: (nullable): optional return location for an error
474
 *
475
 * Finds a block of memory in another block of memory in a safe way.
476
 *
477
 * Returns: %TRUE if the needle was found in the haystack, %FALSE otherwise
478
 *
479
 * Since: 1.8.2
480
 **/
481
gboolean
482
fu_memmem_safe(const guint8 *haystack,
483
         gsize haystack_sz,
484
         const guint8 *needle,
485
         gsize needle_sz,
486
         gsize *offset,
487
         GError **error)
488
72.1k
{
489
#ifdef HAVE_MEMMEM
490
  const guint8 *tmp;
491
#endif
492
72.1k
  g_return_val_if_fail(haystack != NULL, FALSE);
493
72.1k
  g_return_val_if_fail(needle != NULL, FALSE);
494
72.1k
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
495
496
  /* nothing to find */
497
72.1k
  if (needle_sz == 0) {
498
0
    if (offset != NULL)
499
0
      *offset = 0;
500
0
    return TRUE;
501
0
  }
502
503
  /* impossible */
504
72.1k
  if (needle_sz > haystack_sz) {
505
642
    g_set_error(error,
506
642
          FWUPD_ERROR,
507
642
          FWUPD_ERROR_NOT_FOUND,
508
642
          "needle of 0x%02x bytes is larger than haystack of 0x%02x bytes",
509
642
          (guint)needle_sz,
510
642
          (guint)haystack_sz);
511
642
    return FALSE;
512
642
  }
513
514
#ifdef HAVE_MEMMEM
515
  /* trust glibc to do a binary or linear search as appropriate */
516
  tmp = memmem(haystack, haystack_sz, needle, needle_sz);
517
  if (tmp != NULL) {
518
    if (offset != NULL)
519
      *offset = tmp - haystack;
520
    return TRUE;
521
  }
522
#else
523
20.2M
  for (gsize i = 0; i < haystack_sz - needle_sz; i++) {
524
20.2M
    if (memcmp(haystack + i, needle, needle_sz) == 0) {
525
67.7k
      if (offset != NULL)
526
67.7k
        *offset = i;
527
67.7k
      return TRUE;
528
67.7k
    }
529
20.2M
  }
530
3.69k
#endif
531
532
  /* not found */
533
3.69k
  g_set_error(error,
534
3.69k
        FWUPD_ERROR,
535
3.69k
        FWUPD_ERROR_NOT_FOUND,
536
3.69k
        "needle of 0x%02x bytes was not found in haystack of 0x%02x bytes",
537
3.69k
        (guint)needle_sz,
538
3.69k
        (guint)haystack_sz);
539
3.69k
  return FALSE;
540
71.4k
}
541
542
/**
543
 * fu_memdup_safe:
544
 * @src: (nullable): source buffer
545
 * @n: number of bytes to copy from @src
546
 * @error: (nullable): optional return location for an error
547
 *
548
 * Duplicates some memory using memdup in a safe way.
549
 *
550
 * You don't need to use this function in "obviously correct" cases, nor should
551
 * you use it when performance is a concern. Only us it when you're not sure if
552
 * malicious data from a device or firmware could cause memory corruption.
553
 *
554
 * NOTE: This function intentionally limits allocation size to 1GB.
555
 *
556
 * Returns: (transfer full): block of allocated memory, or %NULL for an error.
557
 *
558
 * Since: 1.8.2
559
 **/
560
guint8 *
561
fu_memdup_safe(const guint8 *src, gsize n, GError **error)
562
0
{
563
  /* sanity check */
564
0
  if (n > 0x40000000) {
565
0
    g_set_error(error,
566
0
          FWUPD_ERROR,
567
0
          FWUPD_ERROR_NOT_SUPPORTED,
568
0
          "cannot allocate %uGB of memory",
569
0
          (guint)(n / 0x40000000));
570
0
    return NULL;
571
0
  }
572
573
  /* linear block of memory */
574
0
  return g_memdup2(src, n);
575
0
}
576
577
/**
578
 * fu_memread_uint8_safe:
579
 * @buf: source buffer
580
 * @bufsz: maximum size of @buf, typically `sizeof(buf)`
581
 * @offset: offset in bytes into @buf to copy from
582
 * @value: (out) (nullable): the parsed value
583
 * @error: (nullable): optional return location for an error
584
 *
585
 * Read a value from a buffer in a safe way.
586
 *
587
 * You don't need to use this function in "obviously correct" cases, nor should
588
 * you use it when performance is a concern. Only us it when you're not sure if
589
 * malicious data from a device or firmware could cause memory corruption.
590
 *
591
 * Returns: %TRUE if @value was set, %FALSE otherwise
592
 *
593
 * Since: 1.8.2
594
 **/
595
gboolean
596
fu_memread_uint8_safe(const guint8 *buf, gsize bufsz, gsize offset, guint8 *value, GError **error)
597
9.83M
{
598
9.83M
  guint8 tmp;
599
600
9.83M
  g_return_val_if_fail(buf != NULL, FALSE);
601
9.83M
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
602
603
9.83M
  if (!fu_memcpy_safe(&tmp,
604
9.83M
          sizeof(tmp),
605
9.83M
          0x0, /* dst */
606
9.83M
          buf,
607
9.83M
          bufsz,
608
9.83M
          offset, /* src */
609
9.83M
          sizeof(tmp),
610
9.83M
          error))
611
150
    return FALSE;
612
9.83M
  if (value != NULL)
613
9.83M
    *value = tmp;
614
9.83M
  return TRUE;
615
9.83M
}
616
617
/**
618
 * fu_memread_uint16_safe:
619
 * @buf: source buffer
620
 * @bufsz: maximum size of @buf, typically `sizeof(buf)`
621
 * @offset: offset in bytes into @buf to copy from
622
 * @value: (out) (nullable): the parsed value
623
 * @endian: an endian type, e.g. %G_LITTLE_ENDIAN
624
 * @error: (nullable): optional return location for an error
625
 *
626
 * Read a value from a buffer using a specified endian in a safe way.
627
 *
628
 * You don't need to use this function in "obviously correct" cases, nor should
629
 * you use it when performance is a concern. Only us it when you're not sure if
630
 * malicious data from a device or firmware could cause memory corruption.
631
 *
632
 * Returns: %TRUE if @value was set, %FALSE otherwise
633
 *
634
 * Since: 1.8.2
635
 **/
636
gboolean
637
fu_memread_uint16_safe(const guint8 *buf,
638
           gsize bufsz,
639
           gsize offset,
640
           guint16 *value,
641
           FuEndianType endian,
642
           GError **error)
643
25.0k
{
644
25.0k
  guint8 dst[2] = {0x0};
645
646
25.0k
  g_return_val_if_fail(buf != NULL, FALSE);
647
25.0k
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
648
649
25.0k
  if (!fu_memcpy_safe(dst,
650
25.0k
          sizeof(dst),
651
25.0k
          0x0, /* dst */
652
25.0k
          buf,
653
25.0k
          bufsz,
654
25.0k
          offset, /* src */
655
25.0k
          sizeof(dst),
656
25.0k
          error))
657
5
    return FALSE;
658
25.0k
  if (value != NULL)
659
25.0k
    *value = fu_memread_uint16(dst, endian);
660
25.0k
  return TRUE;
661
25.0k
}
662
663
/**
664
 * fu_memread_uint24_safe:
665
 * @buf: source buffer
666
 * @bufsz: maximum size of @buf, typically `sizeof(buf)`
667
 * @offset: offset in bytes into @buf to copy from
668
 * @value: (out) (nullable): the parsed value
669
 * @endian: an endian type, e.g. %G_LITTLE_ENDIAN
670
 * @error: (nullable): optional return location for an error
671
 *
672
 * Read a value from a buffer using a specified endian in a safe way.
673
 *
674
 * You don't need to use this function in "obviously correct" cases, nor should
675
 * you use it when performance is a concern. Only us it when you're not sure if
676
 * malicious data from a device or firmware could cause memory corruption.
677
 *
678
 * Returns: %TRUE if @value was set, %FALSE otherwise
679
 *
680
 * Since: 1.8.3
681
 **/
682
gboolean
683
fu_memread_uint24_safe(const guint8 *buf,
684
           gsize bufsz,
685
           gsize offset,
686
           guint32 *value,
687
           FuEndianType endian,
688
           GError **error)
689
0
{
690
0
  guint8 dst[3] = {0x0};
691
692
0
  g_return_val_if_fail(buf != NULL, FALSE);
693
0
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
694
695
0
  if (!fu_memcpy_safe(dst,
696
0
          sizeof(dst),
697
0
          0x0, /* dst */
698
0
          buf,
699
0
          bufsz,
700
0
          offset, /* src */
701
0
          sizeof(dst),
702
0
          error))
703
0
    return FALSE;
704
0
  if (value != NULL)
705
0
    *value = fu_memread_uint24(dst, endian);
706
0
  return TRUE;
707
0
}
708
709
/**
710
 * fu_memread_uint32_safe:
711
 * @buf: source buffer
712
 * @bufsz: maximum size of @buf, typically `sizeof(buf)`
713
 * @offset: offset in bytes into @buf to copy from
714
 * @value: (out) (nullable): the parsed value
715
 * @endian: an endian type, e.g. %G_LITTLE_ENDIAN
716
 * @error: (nullable): optional return location for an error
717
 *
718
 * Read a value from a buffer using a specified endian in a safe way.
719
 *
720
 * You don't need to use this function in "obviously correct" cases, nor should
721
 * you use it when performance is a concern. Only us it when you're not sure if
722
 * malicious data from a device or firmware could cause memory corruption.
723
 *
724
 * Returns: %TRUE if @value was set, %FALSE otherwise
725
 *
726
 * Since: 1.8.2
727
 **/
728
gboolean
729
fu_memread_uint32_safe(const guint8 *buf,
730
           gsize bufsz,
731
           gsize offset,
732
           guint32 *value,
733
           FuEndianType endian,
734
           GError **error)
735
326k
{
736
326k
  guint8 dst[4] = {0x0};
737
738
326k
  g_return_val_if_fail(buf != NULL, FALSE);
739
326k
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
740
741
326k
  if (!fu_memcpy_safe(dst,
742
326k
          sizeof(dst),
743
326k
          0x0, /* dst */
744
326k
          buf,
745
326k
          bufsz,
746
326k
          offset, /* src */
747
326k
          sizeof(dst),
748
326k
          error))
749
410
    return FALSE;
750
326k
  if (value != NULL)
751
326k
    *value = fu_memread_uint32(dst, endian);
752
326k
  return TRUE;
753
326k
}
754
755
/**
756
 * fu_memread_uint64_safe:
757
 * @buf: source buffer
758
 * @bufsz: maximum size of @buf, typically `sizeof(buf)`
759
 * @offset: offset in bytes into @buf to copy from
760
 * @value: (out) (nullable): the parsed value
761
 * @endian: an endian type, e.g. %G_LITTLE_ENDIAN
762
 * @error: (nullable): optional return location for an error
763
 *
764
 * Read a value from a buffer using a specified endian in a safe way.
765
 *
766
 * You don't need to use this function in "obviously correct" cases, nor should
767
 * you use it when performance is a concern. Only us it when you're not sure if
768
 * malicious data from a device or firmware could cause memory corruption.
769
 *
770
 * Returns: %TRUE if @value was set, %FALSE otherwise
771
 *
772
 * Since: 1.8.2
773
 **/
774
gboolean
775
fu_memread_uint64_safe(const guint8 *buf,
776
           gsize bufsz,
777
           gsize offset,
778
           guint64 *value,
779
           FuEndianType endian,
780
           GError **error)
781
6
{
782
6
  guint8 dst[8] = {0x0};
783
784
6
  g_return_val_if_fail(buf != NULL, FALSE);
785
6
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
786
787
6
  if (!fu_memcpy_safe(dst,
788
6
          sizeof(dst),
789
6
          0x0, /* dst */
790
6
          buf,
791
6
          bufsz,
792
6
          offset, /* src */
793
6
          sizeof(dst),
794
6
          error))
795
5
    return FALSE;
796
1
  if (value != NULL)
797
1
    *value = fu_memread_uint64(dst, endian);
798
1
  return TRUE;
799
6
}
800
801
/**
802
 * fu_memwrite_uint8_safe:
803
 * @buf: source buffer
804
 * @bufsz: maximum size of @buf, typically `sizeof(buf)`
805
 * @offset: offset in bytes into @buf to write to
806
 * @value: the value to write
807
 * @error: (nullable): optional return location for an error
808
 *
809
 * Write a value to a buffer in a safe way.
810
 *
811
 * You don't need to use this function in "obviously correct" cases, nor should
812
 * you use it when performance is a concern. Only us it when you're not sure if
813
 * malicious data from a device or firmware could cause memory corruption.
814
 *
815
 * Returns: %TRUE if @value was written, %FALSE otherwise
816
 *
817
 * Since: 1.8.2
818
 **/
819
gboolean
820
fu_memwrite_uint8_safe(guint8 *buf, gsize bufsz, gsize offset, guint8 value, GError **error)
821
0
{
822
0
  g_return_val_if_fail(buf != NULL, FALSE);
823
0
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
824
825
0
  return fu_memcpy_safe(buf,
826
0
            bufsz,
827
0
            offset, /* dst */
828
0
            &value,
829
0
            sizeof(value),
830
0
            0x0, /* src */
831
0
            sizeof(value),
832
0
            error);
833
0
}
834
835
/**
836
 * fu_memwrite_uint16_safe:
837
 * @buf: source buffer
838
 * @bufsz: maximum size of @buf, typically `sizeof(buf)`
839
 * @offset: offset in bytes into @buf to write to
840
 * @value: the value to write
841
 * @endian: an endian type, e.g. %G_LITTLE_ENDIAN
842
 * @error: (nullable): optional return location for an error
843
 *
844
 * Write a value to a buffer using a specified endian in a safe way.
845
 *
846
 * You don't need to use this function in "obviously correct" cases, nor should
847
 * you use it when performance is a concern. Only us it when you're not sure if
848
 * malicious data from a device or firmware could cause memory corruption.
849
 *
850
 * Returns: %TRUE if @value was written, %FALSE otherwise
851
 *
852
 * Since: 1.8.2
853
 **/
854
gboolean
855
fu_memwrite_uint16_safe(guint8 *buf,
856
      gsize bufsz,
857
      gsize offset,
858
      guint16 value,
859
      FuEndianType endian,
860
      GError **error)
861
453
{
862
453
  guint8 tmp[2] = {0x0};
863
864
453
  g_return_val_if_fail(buf != NULL, FALSE);
865
453
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
866
867
453
  fu_memwrite_uint16(tmp, value, endian);
868
453
  return fu_memcpy_safe(buf,
869
453
            bufsz,
870
453
            offset, /* dst */
871
453
            tmp,
872
453
            sizeof(tmp),
873
453
            0x0, /* src */
874
453
            sizeof(tmp),
875
453
            error);
876
453
}
877
878
/**
879
 * fu_memwrite_uint32_safe:
880
 * @buf: source buffer
881
 * @bufsz: maximum size of @buf, typically `sizeof(buf)`
882
 * @offset: offset in bytes into @buf to write to
883
 * @value: the value to write
884
 * @endian: an endian type, e.g. %G_LITTLE_ENDIAN
885
 * @error: (nullable): optional return location for an error
886
 *
887
 * Write a value to a buffer using a specified endian in a safe way.
888
 *
889
 * You don't need to use this function in "obviously correct" cases, nor should
890
 * you use it when performance is a concern. Only us it when you're not sure if
891
 * malicious data from a device or firmware could cause memory corruption.
892
 *
893
 * Returns: %TRUE if @value was written, %FALSE otherwise
894
 *
895
 * Since: 1.8.2
896
 **/
897
gboolean
898
fu_memwrite_uint32_safe(guint8 *buf,
899
      gsize bufsz,
900
      gsize offset,
901
      guint32 value,
902
      FuEndianType endian,
903
      GError **error)
904
1.13k
{
905
1.13k
  guint8 tmp[4] = {0x0};
906
907
1.13k
  g_return_val_if_fail(buf != NULL, FALSE);
908
1.13k
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
909
910
1.13k
  fu_memwrite_uint32(tmp, value, endian);
911
1.13k
  return fu_memcpy_safe(buf,
912
1.13k
            bufsz,
913
1.13k
            offset, /* dst */
914
1.13k
            tmp,
915
1.13k
            sizeof(tmp),
916
1.13k
            0x0, /* src */
917
1.13k
            sizeof(tmp),
918
1.13k
            error);
919
1.13k
}
920
921
/**
922
 * fu_memwrite_uint64_safe:
923
 * @buf: source buffer
924
 * @bufsz: maximum size of @buf, typically `sizeof(buf)`
925
 * @offset: offset in bytes into @buf to write to
926
 * @value: the value to write
927
 * @endian: an endian type, e.g. %G_LITTLE_ENDIAN
928
 * @error: (nullable): optional return location for an error
929
 *
930
 * Write a value to a buffer using a specified endian in a safe way.
931
 *
932
 * You don't need to use this function in "obviously correct" cases, nor should
933
 * you use it when performance is a concern. Only us it when you're not sure if
934
 * malicious data from a device or firmware could cause memory corruption.
935
 *
936
 * Returns: %TRUE if @value was written, %FALSE otherwise
937
 *
938
 * Since: 1.8.2
939
 **/
940
gboolean
941
fu_memwrite_uint64_safe(guint8 *buf,
942
      gsize bufsz,
943
      gsize offset,
944
      guint64 value,
945
      FuEndianType endian,
946
      GError **error)
947
0
{
948
0
  guint8 tmp[8] = {0x0};
949
950
0
  g_return_val_if_fail(buf != NULL, FALSE);
951
0
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
952
953
0
  fu_memwrite_uint64(tmp, value, endian);
954
0
  return fu_memcpy_safe(buf,
955
0
            bufsz,
956
0
            offset, /* dst */
957
0
            tmp,
958
0
            sizeof(tmp),
959
0
            0x0, /* src */
960
0
            sizeof(tmp),
961
0
            error);
962
0
}
963
964
/**
965
 * fu_memstrsafe:
966
 * @buf: source buffer
967
 * @bufsz: maximum size of @buf, typically `sizeof(buf)`
968
 * @offset: offset in bytes into @buf to read from
969
 * @maxsz: maximum size of returned string
970
 * @error: (nullable): optional return location for an error
971
 *
972
 * Converts a byte buffer to a ASCII string.
973
 *
974
 * Returns: (transfer full): a string, or %NULL on error
975
 *
976
 * Since: 1.9.3
977
 **/
978
gchar *
979
fu_memstrsafe(const guint8 *buf, gsize bufsz, gsize offset, gsize maxsz, GError **error)
980
171k
{
981
171k
  g_autofree gchar *str = NULL;
982
983
171k
  g_return_val_if_fail(buf != NULL, NULL);
984
171k
  g_return_val_if_fail(error == NULL || *error == NULL, NULL);
985
986
171k
  if (!fu_memchk_read(bufsz, offset, maxsz, error))
987
26
    return NULL;
988
  /* nocheck:memread */
989
171k
  str = fu_strsafe((const gchar *)buf + offset, maxsz);
990
171k
  if (str == NULL) {
991
41.2k
    g_set_error_literal(error,
992
41.2k
            FWUPD_ERROR,
993
41.2k
            FWUPD_ERROR_INVALID_DATA,
994
41.2k
            "invalid ASCII string");
995
41.2k
    return NULL;
996
41.2k
  }
997
129k
  return g_steal_pointer(&str);
998
171k
}
999
1000
/**
1001
 * fu_memread_string_safe:
1002
 * @buf: source buffer
1003
 * @bufsz: maximum size of @buf, typically `sizeof(buf)`
1004
 * @offset: offset in bytes into @buf to read from
1005
 * @error: (nullable): optional return location for an error
1006
 *
1007
 * Reads a NUL-terminated string from a buffer.
1008
 *
1009
 * Returns: (transfer full): a string, or %NULL on error
1010
 *
1011
 * Since: 2.1.4
1012
 **/
1013
GString *
1014
fu_memread_string_safe(const guint8 *buf, gsize bufsz, gsize offset, GError **error)
1015
160k
{
1016
160k
  g_autoptr(GString) str = g_string_new(NULL);
1017
1018
  /* validate offset is within buffer bounds */
1019
160k
  if (offset >= bufsz) {
1020
130
    g_set_error(error,
1021
130
          FWUPD_ERROR,
1022
130
          FWUPD_ERROR_INVALID_DATA,
1023
130
          "string offset 0x%x exceeds buffer size 0x%x",
1024
130
          (guint)offset,
1025
130
          (guint)bufsz);
1026
130
    return NULL;
1027
130
  }
1028
1029
906M
  for (gsize i = offset; i < bufsz; i++) {
1030
906M
    if (buf[i] == '\0')
1031
160k
      return g_steal_pointer(&str);
1032
906M
    g_string_append_c(str, (gchar)buf[i]);
1033
906M
  }
1034
33
  g_set_error_literal(error,
1035
33
          FWUPD_ERROR,
1036
33
          FWUPD_ERROR_INVALID_DATA,
1037
33
          "buffer not NULL terminated");
1038
  return NULL;
1039
160k
}