1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
|
// SPDX-License-Identifier: GPL-2.0+ OR Apache-2.0
/*
* Copyright (C) 2023 Norbert Lange <nolange79@gmail.com>
*/
#include <string.h>
#include <errno.h>
#include "erofs/config.h"
#include "erofs/defs.h"
#include "liberofs_uuid.h"
#ifdef HAVE_LIBUUID
#include <uuid.h>
#else
#include <stdlib.h>
#ifdef HAVE_SYS_RANDOM_H
#include <sys/random.h>
#else
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>
#endif
/* Flags to be used, will be modified if kernel does not support them */
static unsigned int erofs_grnd_flag =
#ifdef GRND_INSECURE
GRND_INSECURE;
#else
0x0004;
#endif
static int s_getrandom(void *out, unsigned size, bool insecure)
{
unsigned int kflags = erofs_grnd_flag;
unsigned int flags = insecure ? kflags : 0;
for (;;)
{
ssize_t r;
int err;
#if defined(HAVE_SYS_RANDOM_H) && defined(HAVE_GETRANDOM)
r = getrandom(out, size, flags);
#elif defined(__linux__) && defined(__NR_getrandom)
r = (ssize_t)syscall(__NR_getrandom, out, size, flags);
#else
r = -1;
errno = ENOSYS;
(void)flags;
#endif
if (r == size)
break;
err = errno;
if (err != EINTR) {
if (__erofs_unlikely(err == ENOSYS && insecure)) {
while (size) {
*(u8 *)out++ = rand() % 256;
--size;
}
err = 0;
} else if (err == EINVAL && kflags) {
// Kernel likely does not support GRND_INSECURE
erofs_grnd_flag = 0;
kflags = 0;
continue;
}
return -err;
}
}
return 0;
}
#endif
void erofs_uuid_generate(unsigned char *out)
{
#ifdef HAVE_LIBUUID
uuid_t new_uuid;
do {
uuid_generate(new_uuid);
} while (uuid_is_null(new_uuid));
#else
unsigned char new_uuid[16];
int res __maybe_unused;
res = s_getrandom(new_uuid, sizeof(new_uuid), true);
BUG_ON(res != 0);
// UID type + version bits
new_uuid[0] = (new_uuid[4 + 2] & 0x0f) | 0x40;
new_uuid[1] = (new_uuid[4 + 2 + 2] & 0x3f) | 0x80;
#endif
memcpy(out, new_uuid, sizeof(new_uuid));
}
int erofs_uuid_parse(const char *in, unsigned char *uu) {
#ifdef HAVE_LIBUUID
return uuid_parse((char *)in, uu);
#else
unsigned char new_uuid[16];
unsigned int hypens = ((1U << 3) | (1U << 5) | (1U << 7) | (1U << 9));
int i;
for (i = 0; i < sizeof(new_uuid); hypens >>= 1, i++)
{
char c[] = { in[0], in[1], '\0' };
char* endptr = c;
unsigned long val = strtoul(c, &endptr, 16);
if (endptr - c != 2)
return -EINVAL;
in += 2;
if ((hypens & 1U) != 0) {
if (*in++ != '-')
return -EINVAL;
}
new_uuid[i] = (unsigned char)val;
}
if (*in != '\0')
return -EINVAL;
memcpy(uu, new_uuid, sizeof(new_uuid));
return 0;
#endif
}
|