// SPDX-License-Identifier: GPL-2.0+ OR Apache-2.0 /* * Copyright (C) 2023 Norbert Lange */ #include #include #include "erofs/config.h" #include "erofs/defs.h" #include "liberofs_uuid.h" #ifdef HAVE_LIBUUID #include #else #include #ifdef HAVE_SYS_RANDOM_H #include #else #define _GNU_SOURCE #include #include #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; #ifdef HAVE_SYS_RANDOM_H r = getrandom(out, size, flags); #elif 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 }