Coverage Report

Created: 2026-03-31 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gnutls/lib/nettle/sysrng-linux.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2010-2016 Free Software Foundation, Inc.
3
 * Copyright (C) 2015-2016 Red Hat, Inc.
4
 *
5
 * Author: Nikos Mavrogiannopoulos
6
 *
7
 * This file is part of GNUTLS.
8
 *
9
 * The GNUTLS library is free software; you can redistribute it and/or
10
 * modify it under the terms of the GNU Lesser General Public License
11
 * as published by the Free Software Foundation; either version 2.1 of
12
 * the License, or (at your option) any later version.
13
 *
14
 * This library is distributed in the hope that it will be useful, but
15
 * WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
 * Lesser General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Lesser General Public License
20
 * along with this program.  If not, see <https://www.gnu.org/licenses/>
21
 *
22
 */
23
24
/* The Linux style system random generator: That is,
25
 * getrandom() -> /dev/urandom, where "->" indicates fallback.
26
 */
27
28
#ifndef RND_NO_INCLUDES
29
#include "gnutls_int.h"
30
#include "errors.h"
31
#include "num.h"
32
#include <errno.h>
33
#include "rnd-common.h"
34
#endif
35
36
#include <sys/types.h>
37
#include <sys/stat.h>
38
#include <unistd.h>
39
40
/* gnulib wants to claim strerror even if it cannot provide it. WTF */
41
#undef strerror
42
43
#include <time.h>
44
#include <sys/types.h>
45
#include <sys/stat.h>
46
#include <sys/time.h>
47
#include <fcntl.h>
48
49
get_entropy_func _rnd_get_system_entropy = NULL;
50
51
#if defined(__linux__)
52
#ifdef HAVE_GETRANDOM
53
#include <sys/random.h>
54
#else
55
#include <sys/syscall.h>
56
#undef SYS_getrandom
57
#undef getrandom
58
#if defined(SYS_getrandom)
59
#define getrandom(dst, s, flags) \
60
  syscall(SYS_getrandom, (void *)dst, (size_t)s, (unsigned int)flags)
61
#else
62
static ssize_t _getrandom0(void *buf, size_t buflen, unsigned int flags)
63
{
64
  errno = ENOSYS;
65
  return -1;
66
}
67
68
#define getrandom(dst, s, flags) _getrandom0(dst, s, flags)
69
#endif
70
#endif
71
72
static unsigned have_getrandom(void)
73
52
{
74
52
  char c;
75
52
  int ret;
76
52
  ret = getrandom(&c, 1, 1 /*GRND_NONBLOCK */);
77
52
  if (ret == 1 || (ret == -1 && errno == EAGAIN))
78
52
    return 1;
79
0
  return 0;
80
52
}
81
82
/* returns exactly the amount of bytes requested */
83
static int force_getrandom(void *buf, size_t buflen, unsigned int flags)
84
0
{
85
0
  int left = buflen;
86
0
  int ret;
87
0
  uint8_t *p = buf;
88
89
0
  while (left > 0) {
90
0
    ret = getrandom(p, left, flags);
91
0
    if (ret == -1) {
92
0
      if (errno != EINTR)
93
0
        return ret;
94
0
    }
95
96
0
    if (ret > 0) {
97
0
      left -= ret;
98
0
      p += ret;
99
0
    }
100
0
  }
101
102
0
  return buflen;
103
0
}
104
105
static int _rnd_get_system_entropy_getrandom(void *_rnd, size_t size)
106
0
{
107
0
  int ret;
108
0
  ret = force_getrandom(_rnd, size, 0);
109
0
  if (ret == -1) {
110
0
    int e = errno;
111
0
    gnutls_assert();
112
0
    _gnutls_debug_log("Failed to use getrandom: %s\n", strerror(e));
113
0
    return GNUTLS_E_RANDOM_DEVICE_ERROR;
114
0
  }
115
116
0
  return 0;
117
0
}
118
#else /* not linux */
119
#define have_getrandom() 0
120
#endif
121
122
static int _rnd_get_system_entropy_urandom(void *_rnd, size_t size)
123
0
{
124
0
  uint8_t *rnd = _rnd;
125
0
  uint32_t done;
126
0
  int urandom_fd;
127
128
0
  urandom_fd = open("/dev/urandom", O_RDONLY);
129
0
  if (urandom_fd < 0) {
130
0
    _gnutls_debug_log("Cannot open /dev/urandom!\n");
131
0
    return GNUTLS_E_RANDOM_DEVICE_ERROR;
132
0
  }
133
134
0
  for (done = 0; done < size;) {
135
0
    int res;
136
0
    do {
137
0
      res = read(urandom_fd, rnd + done, size - done);
138
0
    } while (res < 0 && errno == EINTR);
139
140
0
    if (res <= 0) {
141
0
      int e = errno;
142
0
      if (res < 0) {
143
0
        _gnutls_debug_log(
144
0
          "Failed to read /dev/urandom: %s\n",
145
0
          strerror(e));
146
0
      } else {
147
0
        _gnutls_debug_log(
148
0
          "Failed to read /dev/urandom: end of file\n");
149
0
      }
150
151
0
      close(urandom_fd);
152
0
      return GNUTLS_E_RANDOM_DEVICE_ERROR;
153
0
    }
154
155
0
    done += res;
156
0
  }
157
158
0
  close(urandom_fd);
159
0
  return 0;
160
0
}
161
162
int _rnd_system_entropy_init(void)
163
52
{
164
52
  int urandom_fd;
165
166
52
#if defined(__linux__)
167
  /* Enable getrandom() usage if available */
168
52
  if (have_getrandom()) {
169
52
    _rnd_get_system_entropy = _rnd_get_system_entropy_getrandom;
170
52
    _gnutls_debug_log("getrandom random generator was selected\n");
171
52
    return 0;
172
52
  } else {
173
0
    _gnutls_debug_log("getrandom is not available\n");
174
0
  }
175
0
#endif
176
177
  /* Fallback: /dev/urandom */
178
179
  /* Check that we can open it */
180
0
  urandom_fd = open("/dev/urandom", O_RDONLY);
181
0
  if (urandom_fd < 0) {
182
0
    _gnutls_debug_log(
183
0
      "Cannot open /dev/urandom during initialization!\n");
184
0
    return gnutls_assert_val(GNUTLS_E_RANDOM_DEVICE_ERROR);
185
0
  }
186
0
  close(urandom_fd);
187
188
0
  _rnd_get_system_entropy = _rnd_get_system_entropy_urandom;
189
0
  _gnutls_debug_log("/dev/urandom random generator was selected\n");
190
191
0
  return 0;
192
0
}
193
194
void _rnd_system_entropy_deinit(void)
195
0
{
196
  /* A no-op now when we open and close /dev/urandom every time */
197
0
  return;
198
0
}