Coverage Report

Created: 2026-01-25 06:22

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