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
1=== modified file 'src/cookie/authority.cpp'
2--- src/cookie/authority.cpp 2016-01-29 08:18:22 +0000
3+++ src/cookie/authority.cpp 2016-02-26 07:35:45 +0000
4@@ -41,9 +41,6 @@
5
6 namespace
7 {
8-std::string const random_device_path{"/dev/random"};
9-std::string const urandom_device_path{"/dev/urandom"};
10-uint32_t const wait_seconds{30};
11 uint32_t const mac_byte_size{20};
12
13 size_t cookie_size_from_format(mir::cookie::Format const& format)
14@@ -62,55 +59,19 @@
15
16 static mir::cookie::Secret get_random_data(unsigned size)
17 {
18+ int fd = open("/dev/urandom", O_RDONLY);
19+ if (fd < 0)
20+ BOOST_THROW_EXCEPTION(std::system_error(errno, std::system_category(),
21+ "open failed on urandom"));
22+
23 mir::cookie::Secret buffer(size);
24- int random_fd;
25- int retval;
26- fd_set rfds;
27-
28- struct timeval tv;
29- tv.tv_sec = wait_seconds;
30- tv.tv_usec = 0;
31-
32- if ((random_fd = open(random_device_path.c_str(), O_RDONLY)) == -1)
33- {
34- int error = errno;
35- BOOST_THROW_EXCEPTION(std::system_error(error, std::system_category(),
36- "open failed on device " + random_device_path));
37- }
38-
39- FD_ZERO(&rfds);
40- FD_SET(random_fd, &rfds);
41-
42- /* We want to block until *some* entropy exists on boot, then use urandom once we have some */
43- retval = select(random_fd + 1, &rfds, NULL, NULL, &tv);
44-
45- /* We are done with /dev/random at this point, and it is either an error or ready to be read */
46- if (close(random_fd) == -1)
47- {
48- int error = errno;
49- BOOST_THROW_EXCEPTION(std::system_error(error, std::system_category(),
50- "close failed on device " + random_device_path));
51- }
52-
53- if (retval == -1)
54- {
55- int error = errno;
56- BOOST_THROW_EXCEPTION(std::system_error(error, std::system_category(),
57- "select failed on file descriptor " + std::to_string(random_fd) +
58- " from device " + random_device_path));
59- }
60- else if (retval && FD_ISSET(random_fd, &rfds))
61- {
62- std::uniform_int_distribution<uint8_t> dist;
63- std::random_device rand_dev(urandom_device_path);
64-
65- std::generate(std::begin(buffer), std::end(buffer), [&]() { return dist(rand_dev); });
66- }
67- else
68- {
69- BOOST_THROW_EXCEPTION(std::runtime_error("Failed to read from device: " + random_device_path +
70- " after: " + std::to_string(wait_seconds) + " seconds"));
71- }
72+ auto got = read(fd, buffer.data(), size);
73+ int error = errno;
74+ close(fd);
75+
76+ if (got != size)
77+ BOOST_THROW_EXCEPTION(std::system_error(error, std::system_category(),
78+ "read failed on urandom"));
79
80 return buffer;
81 }
82
83=== modified file 'tests/acceptance-tests/test_server_startup.cpp'
84--- tests/acceptance-tests/test_server_startup.cpp 2016-02-26 03:37:46 +0000
85+++ tests/acceptance-tests/test_server_startup.cpp 2016-02-26 07:35:45 +0000
86@@ -68,7 +68,7 @@
87 });
88 }
89
90-TEST(ServerStartupReliability, DISABLED_can_start_with_low_entropy)
91+TEST(ServerStartupReliability, can_start_with_low_entropy)
92 { // Regression test for LP: #1536662 and LP: #1541188
93 using namespace ::testing;
94
95
96=== modified file 'tests/unit-tests/test_mir_cookie.cpp'
97--- tests/unit-tests/test_mir_cookie.cpp 2016-02-26 03:37:46 +0000
98+++ tests/unit-tests/test_mir_cookie.cpp 2016-02-26 07:35:45 +0000
99@@ -119,7 +119,7 @@
100 Ge(mir::cookie::Authority::minimum_secret_size));
101 }
102
103-TEST(MirCookieAuthority, DISABLED_given_low_entropy_does_not_hang_or_crash)
104+TEST(MirCookieAuthority, given_low_entropy_does_not_hang_or_crash)
105 { // Regression test for LP: #1536662 and LP: #1541188
106 using namespace testing;
107

Subscribers

People subscribed via source and target branches