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