Coverage Report

Created: 2025-08-26 06:55

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