Coverage Report

Created: 2025-06-13 06:35

/src/cryptsetup/lib/utils.c
Line
Count
Source (jump to first uncovered line)
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
 * utils - miscellaneous device utilities for cryptsetup
4
 *
5
 * Copyright (C) 2004 Jana Saout <jana@saout.de>
6
 * Copyright (C) 2004-2007 Clemens Fruhwirth <clemens@endorphin.org>
7
 * Copyright (C) 2009-2025 Red Hat, Inc. All rights reserved.
8
 * Copyright (C) 2009-2025 Milan Broz
9
 */
10
11
#include <stdio.h>
12
#include <errno.h>
13
#include <sys/mman.h>
14
#include <sys/resource.h>
15
#include <sys/stat.h>
16
#include <sys/utsname.h>
17
18
#include "internal.h"
19
20
size_t crypt_getpagesize(void)
21
0
{
22
0
  long r = sysconf(_SC_PAGESIZE);
23
0
  return r <= 0 ? DEFAULT_MEM_ALIGNMENT : (size_t)r;
24
0
}
25
26
unsigned crypt_cpusonline(void)
27
0
{
28
0
  long r = sysconf(_SC_NPROCESSORS_ONLN);
29
0
  return r < 0 ? 1 : r;
30
0
}
31
32
uint64_t crypt_getphysmemory_kb(void)
33
0
{
34
0
  long pagesize, phys_pages;
35
0
  uint64_t phys_memory_kb, page_size_kb;
36
37
0
  pagesize = sysconf(_SC_PAGESIZE);
38
0
  phys_pages = sysconf(_SC_PHYS_PAGES);
39
40
0
  if (pagesize <= 0 || phys_pages <= 0)
41
0
    return 0;
42
43
0
  page_size_kb = pagesize / 1024;
44
0
  phys_memory_kb = page_size_kb * phys_pages;
45
46
  /* sanity check for overflow */
47
0
  if (phys_memory_kb / phys_pages != page_size_kb)
48
0
    return 0;
49
50
  /* coverity[return_overflow:FALSE] */
51
0
  return phys_memory_kb;
52
0
}
53
54
uint64_t crypt_getphysmemoryfree_kb(void)
55
0
{
56
0
  long pagesize, phys_pages;
57
0
  uint64_t phys_memoryfree_kb, page_size_kb;
58
59
0
  pagesize = sysconf(_SC_PAGESIZE);
60
0
  phys_pages = sysconf(_SC_AVPHYS_PAGES);
61
62
0
  if (pagesize <= 0 || phys_pages <= 0)
63
0
    return 0;
64
65
0
  page_size_kb = pagesize / 1024;
66
0
  phys_memoryfree_kb = page_size_kb * phys_pages;
67
68
  /* sanity check for overflow */
69
0
  if (phys_memoryfree_kb / phys_pages != page_size_kb)
70
0
    return 0;
71
72
  /* coverity[return_overflow:FALSE] */
73
0
  return phys_memoryfree_kb;
74
0
}
75
76
bool crypt_swapavailable(void)
77
0
{
78
0
  int fd;
79
0
  ssize_t size;
80
0
  char buf[4096], *p;
81
0
  uint64_t total;
82
83
0
  if ((fd = open("/proc/meminfo", O_RDONLY)) < 0)
84
0
    return true;
85
86
0
  size = read(fd, buf, sizeof(buf));
87
0
  close(fd);
88
0
  if (size < 1)
89
0
    return true;
90
91
0
  if (size < (ssize_t)sizeof(buf))
92
0
    buf[size] = 0;
93
0
  else
94
0
    buf[sizeof(buf) - 1] = 0;
95
96
0
  p = strstr(buf, "SwapTotal:");
97
0
  if (!p)
98
0
    return true;
99
100
0
  if (sscanf(p, "SwapTotal: %" PRIu64 " kB", &total) != 1)
101
0
    return true;
102
103
0
  return total > 0;
104
0
}
105
106
void crypt_process_priority(struct crypt_device *cd, int *priority, bool raise)
107
0
{
108
0
  int _priority, new_priority;
109
110
0
  if (raise) {
111
0
    _priority = getpriority(PRIO_PROCESS, 0);
112
0
    if (_priority < 0)
113
0
      _priority = 0;
114
0
    if (priority)
115
0
      *priority = _priority;
116
117
    /*
118
     * Do not bother checking CAP_SYS_NICE as device activation
119
     * requires CAP_SYSADMIN later anyway.
120
     */
121
0
    if (getuid() || geteuid())
122
0
      new_priority = 0;
123
0
    else
124
0
      new_priority = -18;
125
126
0
    if (setpriority(PRIO_PROCESS, 0, new_priority))
127
0
      log_dbg(cd, "Cannot raise process priority.");
128
0
  } else {
129
0
    _priority = priority ? *priority : 0;
130
0
    if (setpriority(PRIO_PROCESS, 0, _priority))
131
0
      log_dbg(cd, "Cannot reset process priority.");
132
0
  }
133
0
}
134
135
/* Keyfile processing */
136
137
/*
138
 * A simple call to lseek(3) might not be possible for some inputs (e.g.
139
 * reading from a pipe), so this function instead reads of up to BUFSIZ bytes
140
 * at a time until the specified number of bytes. It returns -1 on read error
141
 * or when it reaches EOF before the requested number of bytes have been
142
 * discarded.
143
 */
144
static int keyfile_seek(int fd, uint64_t bytes)
145
0
{
146
0
  char tmp[BUFSIZ];
147
0
  size_t next_read;
148
0
  ssize_t bytes_r;
149
0
  off_t r;
150
151
0
  r = lseek(fd, bytes, SEEK_CUR);
152
0
  if (r > 0)
153
0
    return 0;
154
0
  if (r < 0 && errno != ESPIPE)
155
0
    return -1;
156
157
0
  while (bytes > 0) {
158
    /* figure out how much to read */
159
0
    next_read = bytes > sizeof(tmp) ? sizeof(tmp) : (size_t)bytes;
160
161
0
    bytes_r = read(fd, tmp, next_read);
162
0
    if (bytes_r < 0) {
163
0
      if (errno == EINTR)
164
0
        continue;
165
166
0
      crypt_safe_memzero(tmp, sizeof(tmp));
167
      /* read error */
168
0
      return -1;
169
0
    }
170
171
0
    if (bytes_r == 0)
172
      /* EOF */
173
0
      break;
174
175
0
    bytes -= bytes_r;
176
0
  }
177
178
0
  crypt_safe_memzero(tmp, sizeof(tmp));
179
0
  return bytes == 0 ? 0 : -1;
180
0
}
181
182
int crypt_keyfile_device_read(struct crypt_device *cd,  const char *keyfile,
183
            char **key, size_t *key_size_read,
184
            uint64_t keyfile_offset, size_t key_size,
185
            uint32_t flags)
186
0
{
187
0
  int fd, regular_file, char_to_read = 0, char_read = 0, unlimited_read = 0;
188
0
  int r = -EINVAL, newline;
189
0
  char *pass = NULL;
190
0
  size_t buflen, i;
191
0
  uint64_t file_read_size;
192
0
  struct stat st;
193
0
  bool close_fd = false;
194
195
0
  if (!key || !key_size_read)
196
0
    return -EINVAL;
197
198
0
  *key = NULL;
199
0
  *key_size_read = 0;
200
201
0
  if (keyfile) {
202
0
    fd = open(keyfile, O_RDONLY);
203
0
    if (fd < 0) {
204
0
      log_err(cd, _("Failed to open key file."));
205
0
      return -EINVAL;
206
0
    }
207
0
    close_fd = true;
208
0
  } else
209
0
    fd = STDIN_FILENO;
210
211
0
  if (isatty(fd)) {
212
0
    log_err(cd, _("Cannot read keyfile from a terminal."));
213
0
    goto out;
214
0
  }
215
216
  /* If not requested otherwise, we limit input to prevent memory exhaustion */
217
0
  if (key_size == 0) {
218
0
    key_size = DEFAULT_KEYFILE_SIZE_MAXKB * 1024 + 1;
219
0
    unlimited_read = 1;
220
    /* use 4k for buffer (page divisor but avoid huge pages) */
221
0
    buflen = 4096 - 16; /* sizeof(struct safe_allocation); */
222
0
  } else
223
0
    buflen = key_size;
224
225
0
  regular_file = 0;
226
0
  if (keyfile) {
227
0
    if (stat(keyfile, &st) < 0) {
228
0
      log_err(cd, _("Failed to stat key file."));
229
0
      goto out;
230
0
    }
231
0
    if (S_ISREG(st.st_mode)) {
232
0
      regular_file = 1;
233
0
      file_read_size = (uint64_t)st.st_size;
234
235
0
      if (keyfile_offset > file_read_size) {
236
0
        log_err(cd, _("Cannot seek to requested keyfile offset."));
237
0
        goto out;
238
0
      }
239
0
      file_read_size -= keyfile_offset;
240
241
      /* known keyfile size, alloc it in one step */
242
0
      if (file_read_size >= (uint64_t)key_size)
243
0
        buflen = key_size;
244
0
      else if (file_read_size)
245
0
        buflen = file_read_size;
246
0
    }
247
0
  }
248
249
0
  pass = crypt_safe_alloc(buflen);
250
0
  if (!pass) {
251
0
    log_err(cd, _("Out of memory while reading passphrase."));
252
0
    goto out;
253
0
  }
254
255
  /* Discard keyfile_offset bytes on input */
256
0
  if (keyfile_offset && keyfile_seek(fd, keyfile_offset) < 0) {
257
0
    log_err(cd, _("Cannot seek to requested keyfile offset."));
258
0
    goto out;
259
0
  }
260
261
0
  for (i = 0, newline = 0; i < key_size; i += char_read) {
262
0
    if (i == buflen) {
263
0
      buflen += 4096;
264
0
      pass = crypt_safe_realloc(pass, buflen);
265
0
      if (!pass) {
266
0
        log_err(cd, _("Out of memory while reading passphrase."));
267
0
        r = -ENOMEM;
268
0
        goto out;
269
0
      }
270
0
    }
271
272
0
    if (flags & CRYPT_KEYFILE_STOP_EOL) {
273
      /* If we should stop on newline, we must read the input
274
       * one character at the time. Otherwise we might end up
275
       * having read some bytes after the newline, which we
276
       * promised not to do.
277
       */
278
0
      char_to_read = 1;
279
0
    } else {
280
      /* char_to_read = min(key_size - i, buflen - i) */
281
0
      char_to_read = key_size < buflen ?
282
0
        key_size - i : buflen - i;
283
0
    }
284
0
    char_read = read_buffer(fd, &pass[i], char_to_read);
285
0
    if (char_read < 0) {
286
0
      log_err(cd, _("Error reading passphrase."));
287
0
      r = -EPIPE;
288
0
      goto out;
289
0
    }
290
291
0
    if (char_read == 0)
292
0
      break;
293
    /* Stop on newline only if not requested read from keyfile */
294
0
    if ((flags & CRYPT_KEYFILE_STOP_EOL) && pass[i] == '\n') {
295
0
      newline = 1;
296
0
      pass[i] = '\0';
297
0
      break;
298
0
    }
299
0
  }
300
301
  /* Fail if piped input dies reading nothing */
302
0
  if (!i && !regular_file && !newline) {
303
0
    log_err(cd, _("Nothing to read on input."));
304
0
    r = -EPIPE;
305
0
    goto out;
306
0
  }
307
308
  /* Fail if we exceeded internal default (no specified size) */
309
0
  if (unlimited_read && i == key_size) {
310
0
    log_err(cd, _("Maximum keyfile size exceeded."));
311
0
    goto out;
312
0
  }
313
314
0
  if (!unlimited_read && i != key_size) {
315
0
    log_err(cd, _("Cannot read requested amount of data."));
316
0
    goto out;
317
0
  }
318
319
0
  *key = pass;
320
0
  *key_size_read = i;
321
0
  r = 0;
322
0
out:
323
0
  if (close_fd)
324
0
    close(fd);
325
326
0
  if (r)
327
0
    crypt_safe_free(pass);
328
0
  return r;
329
0
}
330
331
int crypt_keyfile_read(struct crypt_device *cd,  const char *keyfile,
332
           char **key, size_t *key_size_read,
333
           size_t keyfile_offset, size_t keyfile_size_max,
334
           uint32_t flags)
335
0
{
336
0
  return crypt_keyfile_device_read(cd, keyfile, key, key_size_read,
337
0
           keyfile_offset, keyfile_size_max, flags);
338
0
}
339
340
int kernel_version(uint64_t *kversion)
341
0
{
342
0
  struct utsname uts;
343
0
  uint16_t maj, min, patch, rel;
344
0
  int r = -EINVAL;
345
346
0
  if (uname(&uts) < 0)
347
0
    return r;
348
349
0
  if (sscanf(uts.release, "%" SCNu16  ".%" SCNu16 ".%" SCNu16 "-%" SCNu16,
350
0
       &maj, &min, &patch, &rel) == 4)
351
0
    r = 0;
352
0
  else if (sscanf(uts.release,  "%" SCNu16 ".%" SCNu16 ".%" SCNu16,
353
0
      &maj, &min, &patch) == 3) {
354
0
    rel = 0;
355
0
    r = 0;
356
0
  }
357
358
0
  if (!r)
359
0
    *kversion = compact_version(maj, min, patch, rel);
360
361
0
  return r;
362
0
}
363
364
bool crypt_string_in(const char *str, char **list, size_t list_size)
365
0
{
366
0
  size_t i;
367
368
0
  for (i = 0; *list && i < list_size; i++, list++)
369
0
    if (!strcmp(str, *list))
370
0
      return true;
371
372
0
  return false;
373
0
}
374
375
/* compare two strings (allows NULL values) */
376
int crypt_strcmp(const char *a, const char *b)
377
0
{
378
0
  if (!a && !b)
379
0
    return 0;
380
0
  else if (!a || !b)
381
0
    return 1;
382
0
  return strcmp(a, b);
383
0
}