xref: /aosp_15_r20/external/google-breakpad/src/common/linux/guid_creator.cc (revision 9712c20fc9bbfbac4935993a2ca0b3958c5adad2)
1 // Copyright 2006 Google LLC
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are
5 // met:
6 //
7 //     * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 //     * Redistributions in binary form must reproduce the above
10 // copyright notice, this list of conditions and the following disclaimer
11 // in the documentation and/or other materials provided with the
12 // distribution.
13 //     * Neither the name of Google LLC nor the names of its
14 // contributors may be used to endorse or promote products derived from
15 // this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 
29 #ifdef HAVE_CONFIG_H
30 #include <config.h>  // Must come first
31 #endif
32 
33 #include "common/linux/eintr_wrapper.h"
34 #include "common/linux/guid_creator.h"
35 
36 #include <assert.h>
37 #include <fcntl.h>
38 #include <pthread.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <sys/stat.h>
43 #include <time.h>
44 #include <unistd.h>
45 
46 #if defined(HAVE_SYS_RANDOM_H)
47 #include <sys/random.h>
48 #endif
49 
50 //
51 // GUIDGenerator
52 //
53 // This class is used to generate random GUID.
54 // Currently use random number to generate a GUID since Linux has
55 // no native GUID generator. This should be OK since we don't expect
56 // crash to happen very offen.
57 //
58 class GUIDGenerator {
59  public:
BytesToUInt32(const uint8_t bytes[])60   static uint32_t BytesToUInt32(const uint8_t bytes[]) {
61     return ((uint32_t) bytes[0]
62             | ((uint32_t) bytes[1] << 8)
63             | ((uint32_t) bytes[2] << 16)
64             | ((uint32_t) bytes[3] << 24));
65   }
66 
UInt32ToBytes(uint8_t bytes[],uint32_t n)67   static void UInt32ToBytes(uint8_t bytes[], uint32_t n) {
68     bytes[0] = n & 0xff;
69     bytes[1] = (n >> 8) & 0xff;
70     bytes[2] = (n >> 16) & 0xff;
71     bytes[3] = (n >> 24) & 0xff;
72   }
73 
CreateGUID(GUID * guid)74   static bool CreateGUID(GUID *guid) {
75 #if defined(HAVE_ARC4RANDOM) // Android, BSD, ...
76     CreateGuidFromArc4Random(guid);
77 #else // Linux
78     bool success = false;
79 
80 #if defined(HAVE_SYS_RANDOM_H) && defined(HAVE_GETRANDOM)
81     success = CreateGUIDFromGetrandom(guid);
82 #endif // HAVE_SYS_RANDOM_H && HAVE_GETRANDOM
83     if (!success) {
84       success = CreateGUIDFromDevUrandom(guid);
85     }
86 
87     if (!success) {
88       CreateGUIDFromRand(guid);
89       success = true;
90     }
91 #endif
92 
93     // Put in the version according to RFC 4122.
94     guid->data3 &= 0x0fff;
95     guid->data3 |= 0x4000;
96 
97     // Put in the variant according to RFC 4122.
98     guid->data4[0] &= 0x3f;
99     guid->data4[0] |= 0x80;
100 
101     return true;
102   }
103 
104  private:
105 #ifdef HAVE_ARC4RANDOM
CreateGuidFromArc4Random(GUID * guid)106   static void CreateGuidFromArc4Random(GUID *guid) {
107     char *buf = reinterpret_cast<char*>(guid);
108 
109     for (size_t i = 0; i < sizeof(GUID); i += sizeof(uint32_t)) {
110       uint32_t random_data = arc4random();
111 
112       memcpy(buf + i, &random_data, sizeof(uint32_t));
113     }
114   }
115 #else
116   static void InitOnce() {
117     pthread_once(&once_control, &InitOnceImpl);
118   }
119 
120   static void InitOnceImpl() {
121     // time(NULL) is a very poor seed, so lacking anything better mix an
122     // address into it. We drop the four rightmost bits as they're likely to
123     // be 0 on almost all architectures.
124     srand(time(NULL) | ((uintptr_t)&once_control >> 4));
125   }
126 
127   static pthread_once_t once_control;
128 
129 #if defined(HAVE_SYS_RANDOM_H) && defined(HAVE_GETRANDOM)
130   static bool CreateGUIDFromGetrandom(GUID *guid) {
131     char *buf = reinterpret_cast<char*>(guid);
132     int read_bytes = getrandom(buf, sizeof(GUID), GRND_NONBLOCK);
133 
134     return (read_bytes == static_cast<int>(sizeof(GUID)));
135   }
136 #endif // HAVE_SYS_RANDOM_H && HAVE_GETRANDOM
137 
138   // Populate the GUID using random bytes read from /dev/urandom, returns false
139   // if the GUID wasn't fully populated with random data.
140   static bool CreateGUIDFromDevUrandom(GUID *guid) {
141     char *buf = reinterpret_cast<char*>(guid);
142     int fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC);
143 
144     if (fd == -1) {
145       return false;
146     }
147 
148     ssize_t read_bytes = HANDLE_EINTR(read(fd, buf, sizeof(GUID)));
149     close(fd);
150 
151     return (read_bytes == static_cast<ssize_t>(sizeof(GUID)));
152   }
153 
154   // Populate the GUID using a stream of random bytes obtained from rand().
155   static void CreateGUIDFromRand(GUID *guid) {
156     char *buf = reinterpret_cast<char*>(guid);
157 
158     InitOnce();
159 
160     for (size_t i = 0; i < sizeof(GUID); i++) {
161       buf[i] = rand();
162     }
163   }
164 #endif
165 };
166 
167 #ifndef HAVE_ARC4RANDOM
168 pthread_once_t GUIDGenerator::once_control = PTHREAD_ONCE_INIT;
169 #endif
170 
CreateGUID(GUID * guid)171 bool CreateGUID(GUID *guid) {
172   return GUIDGenerator::CreateGUID(guid);
173 }
174 
175 // Parse guid to string.
GUIDToString(const GUID * guid,char * buf,int buf_len)176 bool GUIDToString(const GUID *guid, char *buf, int buf_len) {
177   // Should allow more space the the max length of GUID.
178   assert(buf_len > kGUIDStringLength);
179   int num = snprintf(buf, buf_len, kGUIDFormatString,
180                      guid->data1, guid->data2, guid->data3,
181                      GUIDGenerator::BytesToUInt32(&(guid->data4[0])),
182                      GUIDGenerator::BytesToUInt32(&(guid->data4[4])));
183   if (num != kGUIDStringLength)
184     return false;
185 
186   buf[num] = '\0';
187   return true;
188 }
189