Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Linux-specific getrandom call to obtain random data. #75

Merged
merged 1 commit into from
Jun 18, 2018

Conversation

Lastique
Copy link
Member

getrandom is the base implementation for getentropy on Linux. It is also
available in the form of a syscall, which can be called directly on systems with
glibc versions older than 2.25 which don't yet provide wrappers for getrandom or
getentropy but have a recent enough Linux kernel (for example, Debian Stretch).

On systems other than Linux (e.g. Solaris) getentropy is documented as a
source for initialization of a user-space PRNG instead of a direct source
for random data. Since we use the random data directly to initialize UUIDs,
using getrandom on other platforms, where available, would be more preferable
than getentropy. Unfortunately, the only other platform that is known to support
both getentropy and getrandom (Solaris) documents getrandom to return 0
on error, which is a valid return value on Linux. It's not clear if this is
a documentation error or a true incompatibility, and I have no way to test,
so do not use getrandom on Solaris for now. For this reason (and in case
if it is also used on some other platforms) getentropy backend is still
preserved.

Copy link
Collaborator

@jeking3 jeking3 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the performance difference between getentropy and getrandom so much that it warrants another code path?

In the test Jamfile you may want to add explicit cases that force both of the linux implementations to execute in positive and negative test cases to ensure test coverage. Without that, most (maybe all) CI builds will test getrandom and nothing will be testing getentropy any more.

@@ -15,6 +15,8 @@
# include <boost/uuid/detail/random_provider_arc4random.ipp>
#elif defined(BOOST_UUID_RANDOM_PROVIDER_BCRYPT)
# include <boost/uuid/detail/random_provider_bcrypt.ipp>
#elif defined(BOOST_UUID_RANDOM_PROVIDER_GETRANDOM)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was trying to keep these in alphabetical order :)

{
#if defined(BOOST_UUID_RANDOM_PROVIDER_GETRANDOM_IMPL_GETRANDOM)
return BOOST_UUID_RANDOM_PROVIDER_GETRANDOM_IMPL_GETRANDOM(buf, size, flags);
#elif defined(BOOST_UUID_RANDOM_PROVIDER_GETRANDOM_HAS_LIBC_WRAPPER)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To implement the unit test could you have the mock implement ::getrandom and have the mock header define BOOST_UUID_RANDOM_PROVIDER_GETRANDOM_HAS_LIBC_WRAPPER? Unfortunately we're going to have a drop in coverage on the syscall since that (probably) can't be mocked.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like redefining system functions. I've seen you did this with getentropy and I deliberately did not follow this route. I think, that mock should be changed as well, but didn't do it in this PR as it was unrelated.

#if BOOST_LIB_C_GNU >= BOOST_VERSION_NUMBER(2, 25, 0)
#define BOOST_UUID_RANDOM_PROVIDER_GETRANDOM_HAS_LIBC_WRAPPER
#elif defined(__has_include)
#if __has_include(<sys/random.h>)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've never seen __has_include before. I was just thinking about how nice it would be to have the following include syntax in C++:

#include <boost/uuid/sha1.hpp> or <boost/uuid/detail/sha1.hpp>

To handle headers that move without leaving behind forwarding headers.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've never seen __has_include before.

It's one of the SD-6 macros most recent compilers support.

https://en.cppreference.com/w/cpp/experimental/feature_test

@Lastique
Copy link
Member Author

Is the performance difference between getentropy and getrandom so much that it warrants another code path?

I don't expect performance to be significantly different. The main reasons for this backend are (a) supporting more platforms (glibc < 2.25) and (b) using the more appropriate API for random data generation. As I noted, getentropy is mostly targeted for seeding user-space PRNGs. I.e. read some (not much) random data to initialize a UPRNG and then obtain most of the random data from UPRNG. Given that on Linux getentropy is based on getrandom, this part is mostly puristic, but still worth mentioning. It may be significant on other systems.

In the test Jamfile you may want to add explicit cases that force both of the linux implementations to execute in positive and negative test cases to ensure test coverage. Without that, most (maybe all) CI builds will test getrandom and nothing will be testing getentropy any more.

I'm not sure it is worth doing. On Linux, getentropy backend is not going to be used, ever, so why test it there. I guess, you probably want to "emulate" other systems by forcing getentropy?

@jeking3
Copy link
Collaborator

jeking3 commented Jun 17, 2018

Yes, since we don't have a Solaris CI environment, it's nice to ensure the code doesn't rot somehow.

getrandom is the base implementation for getentropy on Linux. It is also
available in the form of a syscall, which can be called directly on systems with
glibc versions older than 2.25 which don't yet provide wrappers for getrandom or
getentropy but have a recent enough Linux kernel (for example, Debian Stretch).

On systems other than Linux (e.g. Solaris) getentropy is documented as a
source for initialization of a user-space PRNG instead of a direct source
for random data. Since we use the random data directly to initialize UUIDs,
using getrandom on other platforms, where available, would be more preferable
than getentropy. Unfortunately, the only other platform that is known to support
both getentropy and getrandom (Solaris) documents getrandom to return 0
on error, which is a valid return value on Linux. It's not clear if this is
a documentation error or a true incompatibility, and I have no way to test,
so do not use getrandom on Solaris for now. For this reason (and in case
if it is also used on some other platforms) getentropy backend is still
preserved.

For running tests in the CI on the getentropy backend added the
BOOST_UUID_RANDOM_PROVIDER_DISABLE_GETRANDOM macro, which will disable getrandom
if one is detected. Currently, the macro is only used for tests on Linux.
@codecov
Copy link

codecov bot commented Jun 17, 2018

Codecov Report

Merging #75 into develop will not change coverage.
The diff coverage is n/a.

Impacted file tree graph

@@           Coverage Diff            @@
##           develop      #75   +/-   ##
========================================
  Coverage    78.34%   78.34%           
========================================
  Files           13       13           
  Lines          605      605           
  Branches       156      156           
========================================
  Hits           474      474           
  Misses          17       17           
  Partials       114      114

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 0d0aa87...6c060f6. Read the comment docs.

@Lastique
Copy link
Member Author

I've updated the PR. For tests, I've added the internal BOOST_UUID_RANDOM_PROVIDER_DISABLE_GETRANDOM macro, which is only used by tests on Linux, currently. I've also updated the docs.

@jeking3 jeking3 merged commit 405f961 into boostorg:develop Jun 18, 2018
@Lastique Lastique deleted the add_getrandom_backend branch June 20, 2018 14:18
@bajizhh
Copy link

bajizhh commented Oct 10, 2018

::syscall(SYS_getrandom, buf, size, flags) failed on ubuntu 16.04.1

throws an exception blow:
boost::exception_detail::clone_impl<boost::exception_detail::error_info_injectorboost::uuids::entropy_error >

system kernel info:
Linux app2 3.13.0-32-generic #57-Ubuntu SMP Tue Jul 15 03:51:08 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux

@Lastique
Copy link
Member Author

I've replied in #79.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants