• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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