Coverage Report

Created: 2026-01-16 06:48

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
63.9M
{
30
63.9M
  guint16 val_hw;
31
63.9M
  switch (endian) {
32
483k
  case G_BIG_ENDIAN:
33
483k
    val_hw = GUINT16_TO_BE(val_native); /* nocheck:blocked */
34
483k
    break;
35
63.4M
  case G_LITTLE_ENDIAN:
36
63.4M
    val_hw = GUINT16_TO_LE(val_native); /* nocheck:blocked */
37
63.4M
    break;
38
0
  default:
39
0
    val_hw = val_native;
40
0
    break;
41
63.9M
  }
42
63.9M
  memcpy(buf, &val_hw, sizeof(val_hw)); /* nocheck:blocked */
43
63.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
5.01k
{
58
5.01k
  guint32 val_hw;
59
5.01k
  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
5.01k
  case G_LITTLE_ENDIAN:
65
5.01k
    val_hw = GUINT32_TO_LE(val_native); /* nocheck:blocked */
66
5.01k
    memcpy(buf, &val_hw, 0x3);      /* nocheck:blocked */
67
5.01k
    break;
68
0
  default:
69
0
    g_assert_not_reached();
70
5.01k
  }
71
5.01k
}
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
931k
{
86
931k
  guint32 val_hw;
87
931k
  switch (endian) {
88
196k
  case G_BIG_ENDIAN:
89
196k
    val_hw = GUINT32_TO_BE(val_native); /* nocheck:blocked */
90
196k
    break;
91
735k
  case G_LITTLE_ENDIAN:
92
735k
    val_hw = GUINT32_TO_LE(val_native); /* nocheck:blocked */
93
735k
    break;
94
0
  default:
95
0
    val_hw = val_native;
96
0
    break;
97
931k
  }
98
931k
  memcpy(buf, &val_hw, sizeof(val_hw)); /* nocheck:blocked */
99
931k
}
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
9.34k
{
114
9.34k
  guint64 val_hw;
115
9.34k
  switch (endian) {
116
0
  case G_BIG_ENDIAN:
117
0
    val_hw = GUINT64_TO_BE(val_native); /* nocheck:blocked */
118
0
    break;
119
9.34k
  case G_LITTLE_ENDIAN:
120
9.34k
    val_hw = GUINT64_TO_LE(val_native); /* nocheck:blocked */
121
9.34k
    break;
122
0
  default:
123
0
    val_hw = val_native;
124
0
    break;
125
9.34k
  }
126
9.34k
  memcpy(buf, &val_hw, sizeof(val_hw)); /* nocheck:blocked */
127
9.34k
}
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
99.2M
{
143
99.2M
  guint16 val_hw, val_native;
144
99.2M
  memcpy(&val_hw, buf, sizeof(val_hw)); /* nocheck:blocked */
145
99.2M
  switch (endian) {
146
13.3k
  case G_BIG_ENDIAN:
147
13.3k
    val_native = GUINT16_FROM_BE(val_hw); /* nocheck:blocked */
148
13.3k
    break;
149
99.2M
  case G_LITTLE_ENDIAN:
150
99.2M
    val_native = GUINT16_FROM_LE(val_hw); /* nocheck:blocked */
151
99.2M
    break;
152
0
  default:
153
0
    val_native = val_hw;
154
0
    break;
155
99.2M
  }
156
99.2M
  return val_native;
157
99.2M
}
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
69.0k
{
173
69.0k
  guint32 val_hw = 0;
174
69.0k
  guint32 val_native;
175
69.0k
  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
69.0k
  case G_LITTLE_ENDIAN:
181
69.0k
    memcpy(&val_hw, buf, 0x3);        /* nocheck:blocked */
182
69.0k
    val_native = GUINT32_FROM_LE(val_hw); /* nocheck:blocked */
183
69.0k
    break;
184
0
  default:
185
0
    val_native = val_hw;
186
0
    break;
187
69.0k
  }
188
69.0k
  return val_native;
189
69.0k
}
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
106M
{
205
106M
  guint32 val_hw, val_native;
206
106M
  memcpy(&val_hw, buf, sizeof(val_hw)); /* nocheck:blocked */
207
106M
  switch (endian) {
208
845k
  case G_BIG_ENDIAN:
209
845k
    val_native = GUINT32_FROM_BE(val_hw); /* nocheck:blocked */
210
845k
    break;
211
106M
  case G_LITTLE_ENDIAN:
212
106M
    val_native = GUINT32_FROM_LE(val_hw); /* nocheck:blocked */
213
106M
    break;
214
0
  default:
215
0
    val_native = val_hw;
216
0
    break;
217
106M
  }
218
106M
  return val_native;
219
106M
}
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.8M
{
235
12.8M
  guint64 val_hw, val_native;
236
12.8M
  memcpy(&val_hw, buf, sizeof(val_hw)); /* nocheck:blocked */
237
12.8M
  switch (endian) {
238
1.88M
  case G_BIG_ENDIAN:
239
1.88M
    val_native = GUINT64_FROM_BE(val_hw); /* nocheck:blocked */
240
1.88M
    break;
241
10.9M
  case G_LITTLE_ENDIAN:
242
10.9M
    val_native = GUINT64_FROM_LE(val_hw); /* nocheck:blocked */
243
10.9M
    break;
244
0
  default:
245
0
    val_native = val_hw;
246
0
    break;
247
12.8M
  }
248
12.8M
  return val_native;
249
12.8M
}
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
10.3M
{
326
10.3M
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
327
10.3M
  if (n == 0)
328
1
    return TRUE;
329
10.3M
  if (n > bufsz) {
330
329
    g_set_error(error,
331
329
          FWUPD_ERROR,
332
329
          FWUPD_ERROR_READ,
333
329
          "attempted to read 0x%02x bytes from buffer of 0x%02x",
334
329
          (guint)n,
335
329
          (guint)bufsz);
336
329
    return FALSE;
337
329
  }
338
10.3M
  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
10.3M
  if (offset > bufsz || n + offset > bufsz) {
348
1.14k
    g_set_error(error,
349
1.14k
          FWUPD_ERROR,
350
1.14k
          FWUPD_ERROR_READ,
351
1.14k
          "attempted to read 0x%02x bytes at offset 0x%02x from buffer of 0x%02x",
352
1.14k
          (guint)n,
353
1.14k
          (guint)offset,
354
1.14k
          (guint)bufsz);
355
1.14k
    return FALSE;
356
1.14k
  }
357
10.3M
  return TRUE;
358
10.3M
}
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
11.3M
{
381
11.3M
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
382
11.3M
  if (n == 0)
383
0
    return TRUE;
384
11.3M
  if (n > bufsz) {
385
0
    g_set_error(error,
386
0
          FWUPD_ERROR,
387
0
          FWUPD_ERROR_WRITE,
388
0
          "attempted to write 0x%02x bytes to buffer of 0x%02x",
389
0
          (guint)n,
390
0
          (guint)bufsz);
391
0
    return FALSE;
392
0
  }
393
11.3M
  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
11.3M
  if (offset > bufsz || n + offset > bufsz) {
403
54
    g_set_error(error,
404
54
          FWUPD_ERROR,
405
54
          FWUPD_ERROR_WRITE,
406
54
          "attempted to write 0x%02x bytes at offset 0x%02x to buffer of 0x%02x",
407
54
          (guint)n,
408
54
          (guint)offset,
409
54
          (guint)bufsz);
410
54
    return FALSE;
411
54
  }
412
11.3M
  return TRUE;
413
11.3M
}
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
9.04M
{
451
9.04M
  g_return_val_if_fail(dst != NULL, FALSE);
452
9.04M
  g_return_val_if_fail(src != NULL, FALSE);
453
9.04M
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
454
455
9.04M
  if (!fu_memchk_read(src_sz, src_offset, n, error))
456
1.34k
    return FALSE;
457
9.04M
  if (!fu_memchk_write(dst_sz, dst_offset, n, error))
458
54
    return FALSE;
459
9.04M
  memcpy(dst + dst_offset, src + src_offset, n); /* nocheck:blocked */
460
9.04M
  return TRUE;
461
9.04M
}
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
143k
{
486
#ifdef HAVE_MEMMEM
487
  const guint8 *tmp;
488
#endif
489
143k
  g_return_val_if_fail(haystack != NULL, FALSE);
490
143k
  g_return_val_if_fail(needle != NULL, FALSE);
491
143k
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
492
493
  /* nothing to find */
494
143k
  if (needle_sz == 0) {
495
0
    if (offset != NULL)
496
0
      *offset = 0;
497
0
    return TRUE;
498
0
  }
499
500
  /* impossible */
501
143k
  if (needle_sz > haystack_sz) {
502
198
    g_set_error(error,
503
198
          FWUPD_ERROR,
504
198
          FWUPD_ERROR_NOT_FOUND,
505
198
          "needle of 0x%02x bytes is larger than haystack of 0x%02x bytes",
506
198
          (guint)needle_sz,
507
198
          (guint)haystack_sz);
508
198
    return FALSE;
509
198
  }
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
51.9M
  for (gsize i = 0; i < haystack_sz - needle_sz; i++) {
521
51.9M
    if (memcmp(haystack + i, needle, needle_sz) == 0) {
522
138k
      if (offset != NULL)
523
138k
        *offset = i;
524
138k
      return TRUE;
525
138k
    }
526
51.9M
  }
527
5.44k
#endif
528
529
  /* not found */
530
5.44k
  g_set_error(error,
531
5.44k
        FWUPD_ERROR,
532
5.44k
        FWUPD_ERROR_NOT_FOUND,
533
5.44k
        "needle of 0x%02x bytes was not found in haystack of 0x%02x bytes",
534
5.44k
        (guint)needle_sz,
535
5.44k
        (guint)haystack_sz);
536
5.44k
  return FALSE;
537
143k
}
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
2.69k
{
595
2.69k
  guint8 tmp;
596
597
2.69k
  g_return_val_if_fail(buf != NULL, FALSE);
598
2.69k
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
599
600
2.69k
  if (!fu_memcpy_safe(&tmp,
601
2.69k
          sizeof(tmp),
602
2.69k
          0x0, /* dst */
603
2.69k
          buf,
604
2.69k
          bufsz,
605
2.69k
          offset, /* src */
606
2.69k
          sizeof(tmp),
607
2.69k
          error))
608
0
    return FALSE;
609
2.69k
  if (value != NULL)
610
2.69k
    *value = tmp;
611
2.69k
  return TRUE;
612
2.69k
}
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
28.7k
{
641
28.7k
  guint8 dst[2] = {0x0};
642
643
28.7k
  g_return_val_if_fail(buf != NULL, FALSE);
644
28.7k
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
645
646
28.7k
  if (!fu_memcpy_safe(dst,
647
28.7k
          sizeof(dst),
648
28.7k
          0x0, /* dst */
649
28.7k
          buf,
650
28.7k
          bufsz,
651
28.7k
          offset, /* src */
652
28.7k
          sizeof(dst),
653
28.7k
          error))
654
11
    return FALSE;
655
28.7k
  if (value != NULL)
656
28.7k
    *value = fu_memread_uint16(dst, endian);
657
28.7k
  return TRUE;
658
28.7k
}
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
360k
{
733
360k
  guint8 dst[4] = {0x0};
734
735
360k
  g_return_val_if_fail(buf != NULL, FALSE);
736
360k
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
737
738
360k
  if (!fu_memcpy_safe(dst,
739
360k
          sizeof(dst),
740
360k
          0x0, /* dst */
741
360k
          buf,
742
360k
          bufsz,
743
360k
          offset, /* src */
744
360k
          sizeof(dst),
745
360k
          error))
746
419
    return FALSE;
747
360k
  if (value != NULL)
748
360k
    *value = fu_memread_uint32(dst, endian);
749
360k
  return TRUE;
750
360k
}
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
300
{
859
300
  guint8 tmp[2] = {0x0};
860
861
300
  g_return_val_if_fail(buf != NULL, FALSE);
862
300
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
863
864
300
  fu_memwrite_uint16(tmp, value, endian);
865
300
  return fu_memcpy_safe(buf,
866
300
            bufsz,
867
300
            offset, /* dst */
868
300
            tmp,
869
300
            sizeof(tmp),
870
300
            0x0, /* src */
871
300
            sizeof(tmp),
872
300
            error);
873
300
}
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
164
{
902
164
  guint8 tmp[4] = {0x0};
903
904
164
  g_return_val_if_fail(buf != NULL, FALSE);
905
164
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
906
907
164
  fu_memwrite_uint32(tmp, value, endian);
908
164
  return fu_memcpy_safe(buf,
909
164
            bufsz,
910
164
            offset, /* dst */
911
164
            tmp,
912
164
            sizeof(tmp),
913
164
            0x0, /* src */
914
164
            sizeof(tmp),
915
164
            error);
916
164
}
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
1.23M
{
978
1.23M
  g_autofree gchar *str = NULL;
979
980
1.23M
  g_return_val_if_fail(buf != NULL, NULL);
981
1.23M
  g_return_val_if_fail(error == NULL || *error == NULL, NULL);
982
983
1.23M
  if (!fu_memchk_read(bufsz, offset, maxsz, error))
984
22
    return NULL;
985
1.23M
  str = fu_strsafe((const gchar *)buf + offset, maxsz);
986
1.23M
  if (str == NULL) {
987
469k
    g_set_error_literal(error,
988
469k
            FWUPD_ERROR,
989
469k
            FWUPD_ERROR_INVALID_DATA,
990
469k
            "invalid ASCII string");
991
469k
    return NULL;
992
469k
  }
993
763k
  return g_steal_pointer(&str);
994
1.23M
}