1//
2// Copyright (C) 2014 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//      http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#include "update_engine/update_manager/real_random_provider.h"
18
19#include <stdio.h>
20#include <unistd.h>
21
22#include <string>
23
24#include <base/files/file_path.h>
25#include <base/files/scoped_file.h>
26#include <base/strings/stringprintf.h>
27
28#include "update_engine/update_manager/variable.h"
29
30using std::string;
31
32namespace {
33
34// The device providing randomness.
35const char* kRandomDevice = "/dev/urandom";
36
37}  // namespace
38
39namespace chromeos_update_manager {
40
41// A random seed variable.
42class RandomSeedVariable : public Variable<uint64_t> {
43 public:
44  // RandomSeedVariable is initialized as kVariableModeConst to let the
45  // EvaluationContext cache the value between different evaluations of the same
46  // policy request.
47  RandomSeedVariable(const string& name, FILE* fp)
48      : Variable<uint64_t>(name, kVariableModeConst), fp_(fp) {}
49  ~RandomSeedVariable() override {}
50
51 protected:
52  const uint64_t* GetValue(base::TimeDelta /* timeout */,
53                           string* errmsg) override {
54    uint64_t result;
55    // Aliasing via char pointer abides by the C/C++ strict-aliasing rules.
56    char* const buf = reinterpret_cast<char*>(&result);
57    unsigned int buf_rd = 0;
58
59    while (buf_rd < sizeof(result)) {
60      int rd = fread(buf + buf_rd, 1, sizeof(result) - buf_rd, fp_.get());
61      if (rd == 0 || ferror(fp_.get())) {
62        // Either EOF on fp or read failed.
63        if (errmsg) {
64          *errmsg = base::StringPrintf(
65              "Error reading from the random device: %s", kRandomDevice);
66        }
67        return nullptr;
68      }
69      buf_rd += rd;
70    }
71
72    return new uint64_t(result);
73  }
74
75 private:
76  base::ScopedFILE fp_;
77
78  DISALLOW_COPY_AND_ASSIGN(RandomSeedVariable);
79};
80
81bool RealRandomProvider::Init(void) {
82  FILE* fp = fopen(kRandomDevice, "r");
83  if (!fp)
84    return false;
85  var_seed_.reset(new RandomSeedVariable("seed", fp));
86  return true;
87}
88
89}  // namespace chromeos_update_manager
90