1 /*
2  * Copyright (C) 2021 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 "VehicleBindingUtil.h"
18 
19 #include <android-base/logging.h>
20 #include <cutils/properties.h>  // for property_get
21 #include <logwrap/logwrap.h>
22 #include <utils/SystemClock.h>
23 
24 #include <IHalPropValue.h>
25 #include <VehicleHalTypes.h>
26 #include <fcntl.h>
27 #include <stdlib.h>
28 #include <sys/random.h>
29 #include <sys/stat.h>
30 #include <sys/types.h>
31 #include <unistd.h>
32 
33 #include <vector>
34 
35 namespace android {
36 namespace automotive {
37 namespace security {
38 
39 namespace {
40 
41 using ::aidl::android::hardware::automotive::vehicle::StatusCode;
42 using ::aidl::android::hardware::automotive::vehicle::VehicleArea;
43 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
44 using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
45 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyStatus;
46 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
47 using ::android::frameworks::automotive::vhal::IHalPropValue;
48 using ::android::frameworks::automotive::vhal::IVhalClient;
49 using ::android::frameworks::automotive::vhal::VhalClientResult;
50 
51 template <typename T>
52 using hidl_vec = android::hardware::hidl_vec<T>;
53 
isSeedVhalPropertySupported(std::shared_ptr<IVhalClient> vehicle)54 bool isSeedVhalPropertySupported(std::shared_ptr<IVhalClient> vehicle) {
55     auto result = vehicle->getPropConfigs(
56             {static_cast<int32_t>(VehicleProperty::STORAGE_ENCRYPTION_BINDING_SEED)});
57     return result.ok() && result.value().size() != 0;
58 }
59 
toHexString(const std::vector<uint8_t> & bytes)60 std::string toHexString(const std::vector<uint8_t>& bytes) {
61     const char lookup[] = "0123456789abcdef";
62     std::string out;
63     out.reserve(bytes.size() * 2);
64     for (auto b : bytes) {
65         out += lookup[b >> 4];
66         out += lookup[b & 0xf];
67     }
68     return out;
69 }
70 
setSeedVhalProperty(std::shared_ptr<IVhalClient> vehicle,const std::vector<uint8_t> & seed)71 BindingStatus setSeedVhalProperty(std::shared_ptr<IVhalClient> vehicle,
72                                   const std::vector<uint8_t>& seed) {
73     auto propValue =
74             vehicle->createHalPropValue(toInt(VehicleProperty::STORAGE_ENCRYPTION_BINDING_SEED),
75                                         toInt(VehicleArea::GLOBAL));
76     propValue->setByteValues(seed);
77 
78     if (auto result = vehicle->setValueSync(*propValue); !result.ok()) {
79         LOG(ERROR) << "Unable to set the VHAL property: error: " << result.error();
80         return BindingStatus::ERROR;
81     }
82 
83     return BindingStatus::OK;
84 }
85 
getSeedVhalProperty(std::shared_ptr<IVhalClient> vehicle,std::vector<uint8_t> * seed)86 BindingStatus getSeedVhalProperty(std::shared_ptr<IVhalClient> vehicle,
87                                   std::vector<uint8_t>* seed) {
88     auto desired_prop = vehicle->createHalPropValue(
89             static_cast<int32_t>(VehicleProperty::STORAGE_ENCRYPTION_BINDING_SEED));
90 
91     VhalClientResult<std::unique_ptr<IHalPropValue>> result = vehicle->getValueSync(*desired_prop);
92 
93     BindingStatus status = BindingStatus::ERROR;
94     if (!result.ok()) {
95         LOG(ERROR) << "Error reading vehicle property, error: " << result.error().message();
96         return status;
97     }
98     status = BindingStatus::OK;
99     *seed = result.value()->getByteValues();
100     return status;
101 }
102 
sendSeedToVold(const Executor & executor,const std::vector<uint8_t> & seed)103 BindingStatus sendSeedToVold(const Executor& executor, const std::vector<uint8_t>& seed) {
104     int status = 0;
105 
106     // we pass the seed value via environment variable in the forked process
107     setenv("SEED_VALUE", toHexString(seed).c_str(), 1);
108     int rc = executor.run({"/system/bin/vdc", "cryptfs", "bindkeys"}, &status);
109     unsetenv("SEED_VALUE");
110     LOG(INFO) << "rc: " << rc;
111     LOG(INFO) << "status: " << status;
112     if (rc != 0 || status != 0) {
113         LOG(ERROR) << "Error running vdc: " << rc << ", " << status;
114         return BindingStatus::ERROR;
115     }
116     return BindingStatus::OK;
117 }
118 
119 }  // namespace
120 
fill(void * buffer,size_t size) const121 bool DefaultCsrng::fill(void* buffer, size_t size) const {
122     int fd = TEMP_FAILURE_RETRY(open("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
123     if (fd == -1) {
124         LOG(ERROR) << "Error opening urandom: " << errno;
125         return false;
126     }
127 
128     ssize_t bytes_read;
129     uint8_t* bufptr = static_cast<uint8_t*>(buffer);
130     while ((bytes_read = TEMP_FAILURE_RETRY(read(fd, bufptr, size))) > 0) {
131         size -= bytes_read;
132         bufptr += bytes_read;
133     }
134 
135     close(fd);
136 
137     if (size != 0) {
138         LOG(ERROR) << "Unable to read " << size << " bytes from urandom";
139         return false;
140     }
141     return true;
142 }
143 
run(const std::vector<std::string> & cmd_args,int * exit_code) const144 int DefaultExecutor::run(const std::vector<std::string>& cmd_args, int* exit_code) const {
145     std::vector<const char*> argv;
146     argv.reserve(cmd_args.size());
147     for (auto& arg : cmd_args) {
148         argv.push_back(arg.c_str());
149     }
150     int status = 0;
151     return logwrap_fork_execvp(argv.size(), argv.data(), exit_code, false /*forward_signals*/,
152                                LOG_KLOG, true /*abbreviated*/, nullptr /*file_path*/);
153 }
154 
setVehicleBindingSeed(std::shared_ptr<IVhalClient> vehicle,const Executor & executor,const Csrng & csrng)155 BindingStatus setVehicleBindingSeed(std::shared_ptr<IVhalClient> vehicle, const Executor& executor,
156                                     const Csrng& csrng) {
157     if (!isSeedVhalPropertySupported(vehicle)) {
158         LOG(WARNING) << "Vehicle binding seed is not supported by the VHAL.";
159         return BindingStatus::NOT_SUPPORTED;
160     }
161 
162     std::vector<uint8_t> seed;
163     BindingStatus status = getSeedVhalProperty(vehicle, &seed);
164     if (status != BindingStatus::OK) {
165         LOG(ERROR) << "Unable to read the seed from the VHAL: " << static_cast<int>(status);
166         return status;
167     }
168 
169     if (seed.empty()) {
170         seed = std::vector<uint8_t>(SEED_BYTE_SIZE);
171         if (!csrng.fill(seed.data(), seed.size())) {
172             LOG(ERROR) << "Error getting random seed: " << static_cast<int>(status);
173             return BindingStatus::ERROR;
174         }
175 
176         status = setSeedVhalProperty(vehicle, seed);
177         if (status != BindingStatus::OK) {
178             LOG(ERROR) << "Error storing the seed in the VHAL: " << static_cast<int>(status);
179             return status;
180         }
181     }
182 
183     status = sendSeedToVold(executor, seed);
184     if (status == BindingStatus::OK) {
185         LOG(INFO) << "Successfully bound vehicle storage to seed.";
186     }
187     return status;
188 }
189 
190 }  // namespace security
191 }  // namespace automotive
192 }  // namespace android
193