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