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 
30 using std::string;
31 
32 namespace {
33 
34 // The device providing randomness.
35 const char* kRandomDevice = "/dev/urandom";
36 
37 }  // namespace
38 
39 namespace chromeos_update_manager {
40 
41 // A random seed variable.
42 class 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.
RandomSeedVariable(const string & name,FILE * fp)47   RandomSeedVariable(const string& name, FILE* fp)
48       : Variable<uint64_t>(name, kVariableModeConst), fp_(fp) {}
~RandomSeedVariable()49   ~RandomSeedVariable() override {}
50 
51  protected:
GetValue(base::TimeDelta,string * errmsg)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 
Init(void)81 bool 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