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