real_random_provider.cc revision 35866ed08bcefa9d8bffab9ca64cf994ad0f4290
1// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "update_engine/update_manager/real_random_provider.h"
6
7#include <stdio.h>
8#include <unistd.h>
9
10#include <string>
11
12#include <base/files/file_path.h>
13#include <base/files/scoped_file.h>
14#include <base/strings/stringprintf.h>
15
16#include "update_engine/update_manager/variable.h"
17
18using std::string;
19
20namespace {
21
22// The device providing randomness.
23const char* kRandomDevice = "/dev/urandom";
24
25}  // namespace
26
27namespace chromeos_update_manager {
28
29// A random seed variable.
30class RandomSeedVariable : public Variable<uint64_t> {
31 public:
32  // RandomSeedVariable is initialized as kVariableModeConst to let the
33  // EvaluationContext cache the value between different evaluations of the same
34  // policy request.
35  RandomSeedVariable(const string& name, FILE* fp)
36      : Variable<uint64_t>(name, kVariableModeConst), fp_(fp) {}
37  ~RandomSeedVariable() override {}
38
39 protected:
40  const uint64_t* GetValue(base::TimeDelta /* timeout */,
41                           string* errmsg) override {
42    uint64_t result;
43    // Aliasing via char pointer abides by the C/C++ strict-aliasing rules.
44    char* const buf = reinterpret_cast<char*>(&result);
45    unsigned int buf_rd = 0;
46
47    while (buf_rd < sizeof(result)) {
48      int rd = fread(buf + buf_rd, 1, sizeof(result) - buf_rd, fp_.get());
49      if (rd == 0 || ferror(fp_.get())) {
50        // Either EOF on fp or read failed.
51        if (errmsg) {
52          *errmsg = base::StringPrintf(
53              "Error reading from the random device: %s", kRandomDevice);
54        }
55        return nullptr;
56      }
57      buf_rd += rd;
58    }
59
60    return new uint64_t(result);
61  }
62
63 private:
64  base::ScopedFILE fp_;
65
66  DISALLOW_COPY_AND_ASSIGN(RandomSeedVariable);
67};
68
69bool RealRandomProvider::Init(void) {
70  FILE* fp = fopen(kRandomDevice, "r");
71  if (!fp)
72    return false;
73  var_seed_.reset(new RandomSeedVariable("seed", fp));
74  return true;
75}
76
77}  // namespace chromeos_update_manager
78