Coverage Report

Created: 2025-06-22 06:29

/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
50.4M
{
29
50.4M
  guint16 val_hw;
30
50.4M
  switch (endian) {
31
495k
  case G_BIG_ENDIAN:
32
495k
    val_hw = GUINT16_TO_BE(val_native); /* nocheck:blocked */
33
495k
    break;
34
49.9M
  case G_LITTLE_ENDIAN:
35
49.9M
    val_hw = GUINT16_TO_LE(val_native); /* nocheck:blocked */
36
49.9M
    break;
37
0
  default:
38
0
    val_hw = val_native;
39
0
    break;
40
50.4M
  }
41
50.4M
  memcpy(buf, &val_hw, sizeof(val_hw)); /* nocheck:blocked */
42
50.4M
}
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.1k
{
57
14.1k
  guint32 val_hw;
58
14.1k
  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.1k
  case G_LITTLE_ENDIAN:
64
14.1k
    val_hw = GUINT32_TO_LE(val_native); /* nocheck:blocked */
65
14.1k
    memcpy(buf, &val_hw, 0x3);      /* nocheck:blocked */
66
14.1k
    break;
67
0
  default:
68
0
    g_assert_not_reached();
69
14.1k
  }
70
14.1k
}
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
366k
{
85
366k
  guint32 val_hw;
86
366k
  switch (endian) {
87
264k
  case G_BIG_ENDIAN:
88
264k
    val_hw = GUINT32_TO_BE(val_native); /* nocheck:blocked */
89
264k
    break;
90
102k
  case G_LITTLE_ENDIAN:
91
102k
    val_hw = GUINT32_TO_LE(val_native); /* nocheck:blocked */
92
102k
    break;
93
0
  default:
94
0
    val_hw = val_native;
95
0
    break;
96
366k
  }
97
366k
  memcpy(buf, &val_hw, sizeof(val_hw)); /* nocheck:blocked */
98
366k
}
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.5k
{
113
11.5k
  guint64 val_hw;
114
11.5k
  switch (endian) {
115
0
  case G_BIG_ENDIAN:
116
0
    val_hw = GUINT64_TO_BE(val_native); /* nocheck:blocked */
117
0
    break;
118
11.5k
  case G_LITTLE_ENDIAN:
119
11.5k
    val_hw = GUINT64_TO_LE(val_native); /* nocheck:blocked */
120
11.5k
    break;
121
0
  default:
122
0
    val_hw = val_native;
123
0
    break;
124
11.5k
  }
125
11.5k
  memcpy(buf, &val_hw, sizeof(val_hw)); /* nocheck:blocked */
126
11.5k
}
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
91.9M
{
142
91.9M
  guint16 val_hw, val_native;
143
91.9M
  memcpy(&val_hw, buf, sizeof(val_hw)); /* nocheck:blocked */
144
91.9M
  switch (endian) {
145
12.5k
  case G_BIG_ENDIAN:
146
12.5k
    val_native = GUINT16_FROM_BE(val_hw); /* nocheck:blocked */
147
12.5k
    break;
148
91.9M
  case G_LITTLE_ENDIAN:
149
91.9M
    val_native = GUINT16_FROM_LE(val_hw); /* nocheck:blocked */
150
91.9M
    break;
151
0
  default:
152
0
    val_native = val_hw;
153
0
    break;
154
91.9M
  }
155
91.9M
  return val_native;
156
91.9M
}
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
124k
{
172
124k
  guint32 val_hw = 0;
173
124k
  guint32 val_native;
174
124k
  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
124k
  case G_LITTLE_ENDIAN:
180
124k
    memcpy(&val_hw, buf, 0x3);        /* nocheck:blocked */
181
124k
    val_native = GUINT32_FROM_LE(val_hw); /* nocheck:blocked */
182
124k
    break;
183
0
  default:
184
0
    val_native = val_hw;
185
0
    break;
186
124k
  }
187
124k
  return val_native;
188
124k
}
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
100M
{
204
100M
  guint32 val_hw, val_native;
205
100M
  memcpy(&val_hw, buf, sizeof(val_hw)); /* nocheck:blocked */
206
100M
  switch (endian) {
207
23.5M
  case G_BIG_ENDIAN:
208
23.5M
    val_native = GUINT32_FROM_BE(val_hw); /* nocheck:blocked */
209
23.5M
    break;
210
76.8M
  case G_LITTLE_ENDIAN:
211
76.8M
    val_native = GUINT32_FROM_LE(val_hw); /* nocheck:blocked */
212
76.8M
    break;
213
0
  default:
214
0
    val_native = val_hw;
215
0
    break;
216
100M
  }
217
100M
  return val_native;
218
100M
}
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
16.3M
{
234
16.3M
  guint64 val_hw, val_native;
235
16.3M
  memcpy(&val_hw, buf, sizeof(val_hw)); /* nocheck:blocked */
236
16.3M
  switch (endian) {
237
7.81M
  case G_BIG_ENDIAN:
238
7.81M
    val_native = GUINT64_FROM_BE(val_hw); /* nocheck:blocked */
239
7.81M
    break;
240
8.56M
  case G_LITTLE_ENDIAN:
241
8.56M
    val_native = GUINT64_FROM_LE(val_hw); /* nocheck:blocked */
242
8.56M
    break;
243
0
  default:
244
0
    val_native = val_hw;
245
0
    break;
246
16.3M
  }
247
16.3M
  return val_native;
248
16.3M
}
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
14.3M
{
325
14.3M
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
326
14.3M
  if (n == 0)
327
0
    return TRUE;
328
14.3M
  if (n > bufsz) {
329
353
    g_set_error(error,
330
353
          FWUPD_ERROR,
331
353
          FWUPD_ERROR_READ,
332
353
          "attempted to read 0x%02x bytes from buffer of 0x%02x",
333
353
          (guint)n,
334
353
          (guint)bufsz);
335
353
    return FALSE;
336
353
  }
337
14.3M
  if (offset > bufsz || n + offset > bufsz) {
338
1.12k
    g_set_error(error,
339
1.12k
          FWUPD_ERROR,
340
1.12k
          FWUPD_ERROR_READ,
341
1.12k
          "attempted to read 0x%02x bytes at offset 0x%02x from buffer of 0x%02x",
342
1.12k
          (guint)n,
343
1.12k
          (guint)offset,
344
1.12k
          (guint)bufsz);
345
1.12k
    return FALSE;
346
1.12k
  }
347
14.3M
  return TRUE;
348
14.3M
}
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
31.1M
{
371
31.1M
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
372
31.1M
  if (n == 0)
373
0
    return TRUE;
374
31.1M
  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
31.1M
  if (offset > bufsz || n + offset > bufsz) {
384
60
    g_set_error(error,
385
60
          FWUPD_ERROR,
386
60
          FWUPD_ERROR_WRITE,
387
60
          "attempted to write 0x%02x bytes at offset 0x%02x to buffer of 0x%02x",
388
60
          (guint)n,
389
60
          (guint)offset,
390
60
          (guint)bufsz);
391
60
    return FALSE;
392
60
  }
393
31.1M
  return TRUE;
394
31.1M
}
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
14.1M
{
432
14.1M
  g_return_val_if_fail(dst != NULL, FALSE);
433
14.1M
  g_return_val_if_fail(src != NULL, FALSE);
434
14.1M
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
435
436
14.1M
  if (!fu_memchk_read(src_sz, src_offset, n, error))
437
1.36k
    return FALSE;
438
14.1M
  if (!fu_memchk_write(dst_sz, dst_offset, n, error))
439
60
    return FALSE;
440
14.1M
  memcpy(dst + dst_offset, src + src_offset, n); /* nocheck:blocked */
441
14.1M
  return TRUE;
442
14.1M
}
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
23
    g_set_error(error,
484
23
          FWUPD_ERROR,
485
23
          FWUPD_ERROR_NOT_FOUND,
486
23
          "needle of 0x%02x bytes is larger than haystack of 0x%02x bytes",
487
23
          (guint)needle_sz,
488
23
          (guint)haystack_sz);
489
23
    return FALSE;
490
23
  }
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.39M
  for (gsize i = 0; i < haystack_sz - needle_sz; i++) {
502
3.39M
    if (memcmp(haystack + i, needle, needle_sz) == 0) {
503
850
      if (offset != NULL)
504
850
        *offset = i;
505
850
      return TRUE;
506
850
    }
507
3.39M
  }
508
281
#endif
509
510
  /* not found */
511
281
  g_set_error(error,
512
281
        FWUPD_ERROR,
513
281
        FWUPD_ERROR_NOT_FOUND,
514
281
        "needle of 0x%02x bytes was not found in haystack of 0x%02x bytes",
515
281
        (guint)needle_sz,
516
281
        (guint)haystack_sz);
517
281
  return FALSE;
518
1.13k
}
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
6.38k
{
576
6.38k
  guint8 tmp;
577
578
6.38k
  g_return_val_if_fail(buf != NULL, FALSE);
579
6.38k
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
580
581
6.38k
  if (!fu_memcpy_safe(&tmp,
582
6.38k
          sizeof(tmp),
583
6.38k
          0x0, /* dst */
584
6.38k
          buf,
585
6.38k
          bufsz,
586
6.38k
          offset, /* src */
587
6.38k
          sizeof(tmp),
588
6.38k
          error))
589
0
    return FALSE;
590
6.38k
  if (value != NULL)
591
6.38k
    *value = tmp;
592
6.38k
  return TRUE;
593
6.38k
}
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
30.6k
{
622
30.6k
  guint8 dst[2] = {0x0};
623
624
30.6k
  g_return_val_if_fail(buf != NULL, FALSE);
625
30.6k
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
626
627
30.6k
  if (!fu_memcpy_safe(dst,
628
30.6k
          sizeof(dst),
629
30.6k
          0x0, /* dst */
630
30.6k
          buf,
631
30.6k
          bufsz,
632
30.6k
          offset, /* src */
633
30.6k
          sizeof(dst),
634
30.6k
          error))
635
12
    return FALSE;
636
30.6k
  if (value != NULL)
637
30.6k
    *value = fu_memread_uint16(dst, endian);
638
30.6k
  return TRUE;
639
30.6k
}
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
485k
{
714
485k
  guint8 dst[4] = {0x0};
715
716
485k
  g_return_val_if_fail(buf != NULL, FALSE);
717
485k
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
718
719
485k
  if (!fu_memcpy_safe(dst,
720
485k
          sizeof(dst),
721
485k
          0x0, /* dst */
722
485k
          buf,
723
485k
          bufsz,
724
485k
          offset, /* src */
725
485k
          sizeof(dst),
726
485k
          error))
727
353
    return FALSE;
728
485k
  if (value != NULL)
729
485k
    *value = fu_memread_uint32(dst, endian);
730
485k
  return TRUE;
731
485k
}
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
373
{
840
373
  guint8 tmp[2] = {0x0};
841
842
373
  g_return_val_if_fail(buf != NULL, FALSE);
843
373
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
844
845
373
  fu_memwrite_uint16(tmp, value, endian);
846
373
  return fu_memcpy_safe(buf,
847
373
            bufsz,
848
373
            offset, /* dst */
849
373
            tmp,
850
373
            sizeof(tmp),
851
373
            0x0, /* src */
852
373
            sizeof(tmp),
853
373
            error);
854
373
}
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
387
{
883
387
  guint8 tmp[4] = {0x0};
884
885
387
  g_return_val_if_fail(buf != NULL, FALSE);
886
387
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
887
888
387
  fu_memwrite_uint32(tmp, value, endian);
889
387
  return fu_memcpy_safe(buf,
890
387
            bufsz,
891
387
            offset, /* dst */
892
387
            tmp,
893
387
            sizeof(tmp),
894
387
            0x0, /* src */
895
387
            sizeof(tmp),
896
387
            error);
897
387
}
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
132k
{
959
132k
  g_autofree gchar *str = NULL;
960
961
132k
  g_return_val_if_fail(buf != NULL, NULL);
962
132k
  g_return_val_if_fail(error == NULL || *error == NULL, NULL);
963
964
132k
  if (!fu_memchk_read(bufsz, offset, maxsz, error))
965
13
    return NULL;
966
132k
  str = fu_strsafe((const gchar *)buf + offset, maxsz);
967
132k
  if (str == NULL) {
968
57.2k
    g_set_error_literal(error,
969
57.2k
            FWUPD_ERROR,
970
57.2k
            FWUPD_ERROR_INVALID_DATA,
971
57.2k
            "invalid ASCII string");
972
57.2k
    return NULL;
973
57.2k
  }
974
74.9k
  return g_steal_pointer(&str);
975
132k
}