aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xconfigure88
-rw-r--r--configure.ac3
-rw-r--r--src/common/linux/guid_creator.cc94
-rw-r--r--src/config.h.in9
4 files changed, 182 insertions, 12 deletions
diff --git a/configure b/configure
index 200d1dc9..dcfd3c76 100755
--- a/configure
+++ b/configure
@@ -1875,6 +1875,73 @@ $as_echo "$ac_res" >&6; }
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
} # ac_fn_c_check_header_compile
+
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $2 (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_func
cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
@@ -6572,18 +6639,31 @@ fi
done
-for ac_header in a.out.h
+for ac_header in a.out.h sys/random.h
do :
- ac_fn_c_check_header_mongrel "$LINENO" "a.out.h" "ac_cv_header_a_out_h" "$ac_includes_default"
-if test "x$ac_cv_header_a_out_h" = xyes; then :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
cat >>confdefs.h <<_ACEOF
-#define HAVE_A_OUT_H 1
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
_ACEOF
fi
done
+for ac_func in arc4random getrandom
+do :
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
ax_cxx_compile_cxx11_required=true
diff --git a/configure.ac b/configure.ac
index bc72017c..fe4e8a5a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -72,7 +72,8 @@ AC_ARG_ENABLE(m32,
AC_HEADER_STDC
AC_SYS_LARGEFILE
AX_PTHREAD
-AC_CHECK_HEADERS([a.out.h])
+AC_CHECK_HEADERS([a.out.h sys/random.h])
+AC_CHECK_FUNCS([arc4random getrandom])
AX_CXX_COMPILE_STDCXX(11, noext, mandatory)
diff --git a/src/common/linux/guid_creator.cc b/src/common/linux/guid_creator.cc
index bfb308ee..c92e69f4 100644
--- a/src/common/linux/guid_creator.cc
+++ b/src/common/linux/guid_creator.cc
@@ -27,15 +27,22 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#include "common/linux/eintr_wrapper.h"
#include "common/linux/guid_creator.h"
#include <assert.h>
+#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
+#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
+#if defined(HAVE_SYS_RANDOM_H)
+#include <sys/random.h>
+#endif
+
//
// GUIDGenerator
//
@@ -61,28 +68,101 @@ class GUIDGenerator {
}
static bool CreateGUID(GUID *guid) {
- InitOnce();
- guid->data1 = random();
- guid->data2 = (uint16_t)(random());
- guid->data3 = (uint16_t)(random());
- UInt32ToBytes(&guid->data4[0], random());
- UInt32ToBytes(&guid->data4[4], random());
+#if defined(HAVE_ARC4RANDOM) // Android, BSD, ...
+ CreateGuidFromArc4Random(guid);
+#else // Linux
+ bool success = false;
+
+#if defined(HAVE_SYS_RANDOM_H) && defined(HAVE_GETRANDOM)
+ success = CreateGUIDFromGetrandom(guid);
+#endif // HAVE_SYS_RANDOM_H && HAVE_GETRANDOM
+ if (!success) {
+ success = CreateGUIDFromDevUrandom(guid);
+ }
+
+ if (!success) {
+ CreateGUIDFromRand(guid);
+ success = true;
+ }
+#endif
+
+ // Put in the version according to RFC 4122.
+ guid->data3 &= 0x0fff;
+ guid->data3 |= 0x4000;
+
+ // Put in the variant according to RFC 4122.
+ guid->data4[0] &= 0x3f;
+ guid->data4[0] |= 0x80;
+
return true;
}
private:
+#ifdef HAVE_ARC4RANDOM
+ static void CreateGuidFromArc4Random(GUID *guid) {
+ char *buf = reinterpret_cast<char *>(guid);
+
+ for (size_t i = 0; i < sizeof(GUID); i += sizeof(uint32_t)) {
+ uint32_t random_data = arc4random();
+
+ memcpy(buf + i, &random_data, sizeof(uint32_t));
+ }
+ }
+#else
static void InitOnce() {
pthread_once(&once_control, &InitOnceImpl);
}
static void InitOnceImpl() {
- srandom(time(NULL));
+ // time(NULL) is a very poor seed, so lacking anything better mix an
+ // address into it. We drop the four rightmost bits as they're likely to
+ // be 0 on almost all architectures.
+ srand(time(NULL) | ((uintptr_t)&once_control >> 4));
}
static pthread_once_t once_control;
+
+#if defined(HAVE_SYS_RANDOM_H) && defined(HAVE_GETRANDOM)
+ static bool CreateGUIDFromGetrandom(GUID *guid) {
+ char *buf = reinterpret_cast<char *>(guid);
+ int read_bytes = getrandom(buf, sizeof(GUID), GRND_NONBLOCK);
+
+ return (read_bytes == static_cast<int>(sizeof(GUID)));
+ }
+#endif // HAVE_SYS_RANDOM_H && HAVE_GETRANDOM
+
+ // Populate the GUID using random bytes read from /dev/urandom, returns false
+ // if the GUID wasn't fully populated with random data.
+ static bool CreateGUIDFromDevUrandom(GUID *guid) {
+ char *buf = reinterpret_cast<char *>(guid);
+ int fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC);
+
+ if (fd == -1) {
+ return false;
+ }
+
+ ssize_t read_bytes = HANDLE_EINTR(read(fd, buf, sizeof(GUID)));
+ close(fd);
+
+ return (read_bytes == static_cast<ssize_t>(sizeof(GUID)));
+ }
+
+ // Populate the GUID using a stream of random bytes obtained from rand().
+ static void CreateGUIDFromRand(GUID *guid) {
+ char *buf = reinterpret_cast<char *>(guid);
+
+ InitOnce();
+
+ for (size_t i = 0; i < sizeof(GUID); i++) {
+ buf[i] = rand();
+ }
+ }
+#endif
};
+#ifndef HAVE_ARC4RANDOM
pthread_once_t GUIDGenerator::once_control = PTHREAD_ONCE_INIT;
+#endif
bool CreateGUID(GUID *guid) {
return GUIDGenerator::CreateGUID(guid);
diff --git a/src/config.h.in b/src/config.h.in
index ee6a67ad..a436d6ba 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -1,11 +1,17 @@
/* src/config.h.in. Generated from configure.ac by autoheader. */
+/* Define to 1 if you have the `arc4random' function. */
+#undef HAVE_ARC4RANDOM
+
/* Define to 1 if you have the <a.out.h> header file. */
#undef HAVE_A_OUT_H
/* define if the compiler supports basic C++11 syntax */
#undef HAVE_CXX11
+/* Define to 1 if you have the `getrandom' function. */
+#undef HAVE_GETRANDOM
+
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
@@ -27,6 +33,9 @@
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
+/* Define to 1 if you have the <sys/random.h> header file. */
+#undef HAVE_SYS_RANDOM_H
+
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H