Mir

Merge lp:~vanvugt/mir/run-without-entropy into lp:mir

Proposed by Daniel van Vugt
Status: Superseded
Proposed branch: lp:~vanvugt/mir/run-without-entropy
Merge into: lp:mir
Prerequisite: lp:~vanvugt/mir/test-without-entropy
Diff against target: 106 lines (+14/-53)
3 files modified
src/cookie/authority.cpp (+12/-51)
tests/acceptance-tests/test_server_startup.cpp (+1/-1)
tests/unit-tests/test_mir_cookie.cpp (+1/-1)
To merge this branch: bzr merge lp:~vanvugt/mir/run-without-entropy
Reviewer Review Type Date Requested Status
Chris Halse Rogers Disapprove
Brandon Schaefer (community) Disapprove
Alan Griffiths Disapprove
Alexandros Frantzis (community) Approve
Mir CI Bot continuous-integration Needs Fixing
Review via email: mp+287266@code.launchpad.net

This proposal has been superseded by a proposal from 2016-02-29.

Commit message

Avoid hanging and/or crashing the Mir server when gathering entropy
(LP: #1536662 and LP: #1541188)

Hanging or crashing a visual system like a display server is
unacceptable. And I'm fairly confident we're not doing anything
sufficiently security-critical with "cookies" that could justify hanging
or crashing the system.

Unless you're trying to protect your data from a hardened professional
attacker, there is no justification for blocking indefinitely on
/dev/random, when the non-blocking /dev/urandom is sufficiently secure.

And even if you think you need /dev/random, you should gather data from
it _offline_ only, like ssh-keygen does. Because there's no telling
just how long it might take to read /dev/random. It can and will often
take more than the 30 seconds we were willing to wait (which was too
long anyway).

To post a comment you must log in.
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

FAILED: Continuous integration, rev:3347
https://mir-jenkins.ubuntu.com/job/mir-ci/411/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/212/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/236
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/228
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/228
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/219
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/219/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/219
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/219/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/219
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/219/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/219
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/219/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/219/console

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/411/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

Seems sensible (but of course I am not a security expert).

(ignoring the build failure in this approval)

review: Approve
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

I am not a security expert either, but I know this won't pass audit

review: Disapprove
Revision history for this message
Brandon Schaefer (brandontschaefer) wrote :

We cant do this with out a security team member approving this.

As this would RUIN our entire reasoning for even doing cookies to begin with. If we are having entropy issues to begin with on boot, then this is pretty much accepting that we will be generating a predictable secret. The best we can do is an attempted lazy create the secret we something is first requested vs doing it on boot.

review: Disapprove
Revision history for this message
Brandon Schaefer (brandontschaefer) wrote :

The other thing we can do, is check the kernel version, and based on that use get_random(). Wont solve our issues for prev versions or the phone. This could fix the issue on the desktop though (which seems to be the only place we are getting hit by this so far)

Revision history for this message
Brandon Schaefer (brandontschaefer) wrote :
Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

An interesting read (but once again I note that I don't have the expertise to judge):

http://www.2uo.de/myths-about-urandom/

Revision history for this message
Brandon Schaefer (brandontschaefer) wrote :

Well i am far from a security expert :). If we can get a security review saying this is the fine way to go, then im 100% fine with it. Im just being overly cautious because I dont want to break security!

Revision history for this message
Daniel van Vugt (vanvugt) wrote :

The logic is simple:

No other display server (or app?) hangs and/or crashes waiting for entropy. It's a bad user experience and obviously unacceptable.

I don't care if it "would fail audit", that misses the point. The bigger problem is that we currently fail basic usability. Mir needs to start up quickly and without crashing. Presently it does not do that.

Furthermore, Mir needs to keep responding quickly and without crashing. So to defer entropy collection only defers the problem without solving it.

This branch is the only way forward I can tell. If we've made heavy crypto a priority over a usable system, we've failed. It's not that the current design needs to pass security audit, but the current design is a failure if it can't pass a security audit without hanging indefinitely or crashing.

Revision history for this message
Chris Halse Rogers (raof) wrote :

Mir - or something - needs to generate a key, because we're securing copy/paste with a secret-key system.

Using /dev/urandom is unsafe for something that'll run in early-boot, before the random pool is initialised; if /dev/urandom is used at that time there's no entropy so it'd relatively simple to break the key and hence the copy/paste security.

Since USC doesn't require copy/paste we can avoid the most likely trigger for the problem by USC not providing cookies.

If this is insufficient, we could not provide cookies until a source of randomness has been initialised.

We could also rework the copy/paste API to not require a secret key.

We *shouldn't* handle this by throwing away the check. If this check is failing, then we're in precisely the situation where urandom has insufficient entropy to provide security guarantees!

review: Disapprove

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/cookie/authority.cpp'
--- src/cookie/authority.cpp 2016-01-29 08:18:22 +0000
+++ src/cookie/authority.cpp 2016-02-26 07:35:45 +0000
@@ -41,9 +41,6 @@
4141
42namespace42namespace
43{43{
44std::string const random_device_path{"/dev/random"};
45std::string const urandom_device_path{"/dev/urandom"};
46uint32_t const wait_seconds{30};
47uint32_t const mac_byte_size{20};44uint32_t const mac_byte_size{20};
4845
49size_t cookie_size_from_format(mir::cookie::Format const& format)46size_t cookie_size_from_format(mir::cookie::Format const& format)
@@ -62,55 +59,19 @@
6259
63static mir::cookie::Secret get_random_data(unsigned size)60static mir::cookie::Secret get_random_data(unsigned size)
64{61{
62 int fd = open("/dev/urandom", O_RDONLY);
63 if (fd < 0)
64 BOOST_THROW_EXCEPTION(std::system_error(errno, std::system_category(),
65 "open failed on urandom"));
66
65 mir::cookie::Secret buffer(size);67 mir::cookie::Secret buffer(size);
66 int random_fd;68 auto got = read(fd, buffer.data(), size);
67 int retval;69 int error = errno;
68 fd_set rfds;70 close(fd);
6971
70 struct timeval tv;72 if (got != size)
71 tv.tv_sec = wait_seconds;73 BOOST_THROW_EXCEPTION(std::system_error(error, std::system_category(),
72 tv.tv_usec = 0;74 "read failed on urandom"));
73
74 if ((random_fd = open(random_device_path.c_str(), O_RDONLY)) == -1)
75 {
76 int error = errno;
77 BOOST_THROW_EXCEPTION(std::system_error(error, std::system_category(),
78 "open failed on device " + random_device_path));
79 }
80
81 FD_ZERO(&rfds);
82 FD_SET(random_fd, &rfds);
83
84 /* We want to block until *some* entropy exists on boot, then use urandom once we have some */
85 retval = select(random_fd + 1, &rfds, NULL, NULL, &tv);
86
87 /* We are done with /dev/random at this point, and it is either an error or ready to be read */
88 if (close(random_fd) == -1)
89 {
90 int error = errno;
91 BOOST_THROW_EXCEPTION(std::system_error(error, std::system_category(),
92 "close failed on device " + random_device_path));
93 }
94
95 if (retval == -1)
96 {
97 int error = errno;
98 BOOST_THROW_EXCEPTION(std::system_error(error, std::system_category(),
99 "select failed on file descriptor " + std::to_string(random_fd) +
100 " from device " + random_device_path));
101 }
102 else if (retval && FD_ISSET(random_fd, &rfds))
103 {
104 std::uniform_int_distribution<uint8_t> dist;
105 std::random_device rand_dev(urandom_device_path);
106
107 std::generate(std::begin(buffer), std::end(buffer), [&]() { return dist(rand_dev); });
108 }
109 else
110 {
111 BOOST_THROW_EXCEPTION(std::runtime_error("Failed to read from device: " + random_device_path +
112 " after: " + std::to_string(wait_seconds) + " seconds"));
113 }
11475
115 return buffer;76 return buffer;
116}77}
11778
=== modified file 'tests/acceptance-tests/test_server_startup.cpp'
--- tests/acceptance-tests/test_server_startup.cpp 2016-02-26 03:37:46 +0000
+++ tests/acceptance-tests/test_server_startup.cpp 2016-02-26 07:35:45 +0000
@@ -68,7 +68,7 @@
68 });68 });
69}69}
7070
71TEST(ServerStartupReliability, DISABLED_can_start_with_low_entropy)71TEST(ServerStartupReliability, can_start_with_low_entropy)
72{ // Regression test for LP: #1536662 and LP: #154118872{ // Regression test for LP: #1536662 and LP: #1541188
73 using namespace ::testing;73 using namespace ::testing;
7474
7575
=== modified file 'tests/unit-tests/test_mir_cookie.cpp'
--- tests/unit-tests/test_mir_cookie.cpp 2016-02-26 03:37:46 +0000
+++ tests/unit-tests/test_mir_cookie.cpp 2016-02-26 07:35:45 +0000
@@ -119,7 +119,7 @@
119 Ge(mir::cookie::Authority::minimum_secret_size));119 Ge(mir::cookie::Authority::minimum_secret_size));
120}120}
121121
122TEST(MirCookieAuthority, DISABLED_given_low_entropy_does_not_hang_or_crash)122TEST(MirCookieAuthority, given_low_entropy_does_not_hang_or_crash)
123{ // Regression test for LP: #1536662 and LP: #1541188123{ // Regression test for LP: #1536662 and LP: #1541188
124 using namespace testing;124 using namespace testing;
125125

Subscribers

People subscribed via source and target branches