Coverage Report

Created: 2026-09-06 07:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cryptsetup/lib/utils_safe_memory.c
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
 * utils_safe_memory - safe memory helpers
4
 *
5
 * Copyright (C) 2009-2026 Red Hat, Inc. All rights reserved.
6
 * Copyright (C) 2009-2026 Milan Broz
7
 */
8
9
#include <string.h>
10
#include <sys/mman.h>
11
#include "internal.h"
12
13
struct safe_allocation {
14
  size_t size;
15
  bool locked;
16
  char data[0] __attribute__((aligned(8)));
17
};
18
2.56k
#define OVERHEAD offsetof(struct safe_allocation, data)
19
20
/*
21
 * Replacement for memset(s, 0, n) on stack that can be optimized out
22
 * Also used in safe allocations for explicit memory wipe.
23
 */
24
void crypt_safe_memzero(void *data, size_t size)
25
35.7k
{
26
35.7k
  if (!data)
27
0
    return;
28
29
35.7k
  return crypt_backend_memzero(data, size);
30
35.7k
}
31
32
/* Memcpy helper to avoid spilling sensitive data through additional registers */
33
void *crypt_safe_memcpy(void *dst, const void *src, size_t size)
34
734
{
35
734
  if (!dst || !src)
36
0
    return NULL;
37
38
734
  return crypt_backend_memcpy(dst, src, size);
39
734
}
40
41
/* safe allocations */
42
void *crypt_safe_alloc(size_t size)
43
367
{
44
367
  struct safe_allocation *alloc;
45
46
367
  if (!size || size > (SIZE_MAX - OVERHEAD))
47
0
    return NULL;
48
49
367
  alloc = malloc(size + OVERHEAD);
50
367
  if (!alloc)
51
0
    return NULL;
52
53
367
  crypt_backend_memzero(alloc, size + OVERHEAD);
54
367
  alloc->size = size;
55
56
  /* Ignore failure if it is over limit. */
57
367
  if (!mlock(alloc, size + OVERHEAD))
58
367
    alloc->locked = true;
59
60
  /* coverity[leaked_storage] */
61
367
  return &alloc->data;
62
367
}
63
64
void crypt_safe_free(void *data)
65
367
{
66
367
  struct safe_allocation *alloc;
67
367
  volatile size_t *s;
68
367
  void *p;
69
70
367
  if (!data)
71
0
    return;
72
73
367
  p = (char *)data - OVERHEAD;
74
367
  alloc = (struct safe_allocation *)p;
75
76
367
  crypt_backend_memzero(data, alloc->size);
77
78
367
  if (alloc->locked) {
79
367
    munlock(alloc, alloc->size + OVERHEAD);
80
367
    alloc->locked = false;
81
367
  }
82
83
367
  s = (volatile size_t *)&alloc->size;
84
367
  *s = 0x55aa55aa;
85
367
  free(alloc);
86
367
}
87
88
void *crypt_safe_realloc(void *data, size_t size)
89
0
{
90
0
  struct safe_allocation *alloc;
91
0
  void *new_data;
92
0
  void *p;
93
94
0
  new_data = crypt_safe_alloc(size);
95
96
0
  if (new_data && data) {
97
98
0
    p = (char *)data - OVERHEAD;
99
0
    alloc = (struct safe_allocation *)p;
100
101
0
    if (size > alloc->size)
102
0
      size = alloc->size;
103
104
0
    crypt_backend_memcpy(new_data, data, size);
105
0
  }
106
107
0
  crypt_safe_free(data);
108
0
  return new_data;
109
0
}
110
111
size_t crypt_safe_alloc_size(const void *data)
112
367
{
113
367
  const void *p;
114
115
367
  if (!data)
116
0
    return 0;
117
118
367
  p = (const char *)data - OVERHEAD;
119
120
367
  return ((const struct safe_allocation *)p)->size;
121
367
}