• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright (C) 2020 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 #include <thread>
17 
18 #include <android-base/logging.h>
19 #include <android-base/strings.h>
20 #include <fruit/fruit.h>
21 #include <gflags/gflags.h>
22 #include <keymaster/android_keymaster.h>
23 #include <keymaster/contexts/pure_soft_keymaster_context.h>
24 #include <keymaster/soft_keymaster_logger.h>
25 #include <tss2/tss2_esys.h>
26 #include <tss2/tss2_rc.h>
27 
28 #include "common/libs/fs/shared_fd.h"
29 #include "common/libs/security/channel_sharedfd.h"
30 #include "common/libs/security/confui_sign.h"
31 #include "common/libs/security/gatekeeper_channel_sharedfd.h"
32 #include "common/libs/security/keymaster_channel_sharedfd.h"
33 #include "host/commands/kernel_log_monitor/kernel_log_server.h"
34 #include "host/commands/kernel_log_monitor/utils.h"
35 #include "host/commands/secure_env/confui_sign_server.h"
36 #include "host/commands/secure_env/device_tpm.h"
37 #include "host/commands/secure_env/fragile_tpm_storage.h"
38 #include "host/commands/secure_env/gatekeeper_responder.h"
39 #include "host/commands/secure_env/in_process_tpm.h"
40 #include "host/commands/secure_env/insecure_fallback_storage.h"
41 #include "host/commands/secure_env/keymaster_responder.h"
42 #include "host/commands/secure_env/oemlock_responder.h"
43 #include "host/commands/secure_env/oemlock.h"
44 #include "host/commands/secure_env/proxy_keymaster_context.h"
45 #include "host/commands/secure_env/rust/kmr_ta.h"
46 #include "host/commands/secure_env/soft_gatekeeper.h"
47 #include "host/commands/secure_env/soft_oemlock.h"
48 #include "host/commands/secure_env/tpm_gatekeeper.h"
49 #include "host/commands/secure_env/tpm_keymaster_context.h"
50 #include "host/commands/secure_env/tpm_keymaster_enforcement.h"
51 #include "host/commands/secure_env/tpm_resource_manager.h"
52 #include "host/libs/config/logging.h"
53 
54 DEFINE_int32(confui_server_fd, -1, "A named socket to serve confirmation UI");
55 DEFINE_int32(keymaster_fd_in, -1, "A pipe for keymaster communication");
56 DEFINE_int32(keymaster_fd_out, -1, "A pipe for keymaster communication");
57 DEFINE_int32(keymint_fd_in, -1, "A pipe for keymint communication");
58 DEFINE_int32(keymint_fd_out, -1, "A pipe for keymint communication");
59 DEFINE_int32(gatekeeper_fd_in, -1, "A pipe for gatekeeper communication");
60 DEFINE_int32(gatekeeper_fd_out, -1, "A pipe for gatekeeper communication");
61 DEFINE_int32(oemlock_fd_in, -1, "A pipe for oemlock communication");
62 DEFINE_int32(oemlock_fd_out, -1, "A pipe for oemlock communication");
63 DEFINE_int32(kernel_events_fd, -1,
64              "A pipe for monitoring events based on "
65              "messages written to the kernel log. This "
66              "is used by secure_env to monitor for "
67              "device reboots.");
68 
69 DEFINE_string(tpm_impl, "in_memory",
70               "The TPM implementation. \"in_memory\" or \"host_device\"");
71 
72 DEFINE_string(keymint_impl, "tpm",
73               "The KeyMint implementation. \"tpm\" or \"software\"");
74 
75 DEFINE_string(gatekeeper_impl, "tpm",
76               "The gatekeeper implementation. \"tpm\" or \"software\"");
77 
78 DEFINE_string(oemlock_impl, "software",
79               "The oemlock implementation. \"tpm\" or \"software\"");
80 
81 namespace cuttlefish {
82 namespace {
83 
84 // Copied from AndroidKeymaster4Device
85 constexpr size_t kOperationTableSize = 16;
86 
87 // Dup a command line file descriptor into a SharedFD.
DupFdFlag(gflags::int32 fd)88 SharedFD DupFdFlag(gflags::int32 fd) {
89   CHECK(fd != -1);
90   SharedFD duped = SharedFD::Dup(fd);
91   CHECK(duped->IsOpen()) << "Could not dup output fd: " << duped->StrError();
92   // The original FD is intentionally kept open so that we can re-exec this
93   // process without having to do a bunch of argv book-keeping.
94   return duped;
95 }
96 
97 // Re-launch this process with all the same flags it was originallys started
98 // with.
ReExecSelf()99 [[noreturn]] void ReExecSelf() {
100   // Allocate +1 entry for terminating nullptr.
101   std::vector<char*> argv(gflags::GetArgvs().size() + 1, nullptr);
102   for (size_t i = 0; i < gflags::GetArgvs().size(); ++i) {
103     argv[i] = strdup(gflags::GetArgvs()[i].c_str());
104     CHECK(argv[i] != nullptr) << "OOM";
105   }
106   execv("/proc/self/exe", argv.data());
107   char buf[128];
108   LOG(FATAL) << "Exec failed, secure_env is out of sync with the guest: "
109              << errno << "(" << strerror_r(errno, buf, sizeof(buf)) << ")";
110   abort();  // LOG(FATAL) isn't marked as noreturn
111 }
112 
113 // Spin up a thread that monitors for a kernel loaded event, then re-execs
114 // this process. This way, secure_env's boot tracking matches up with the guest.
StartKernelEventMonitor(SharedFD kernel_events_fd)115 std::thread StartKernelEventMonitor(SharedFD kernel_events_fd) {
116   return std::thread([kernel_events_fd]() {
117     while (kernel_events_fd->IsOpen()) {
118       auto read_result = monitor::ReadEvent(kernel_events_fd);
119       CHECK(read_result.has_value()) << kernel_events_fd->StrError();
120       if (read_result->event == monitor::Event::BootloaderLoaded) {
121         LOG(DEBUG) << "secure_env detected guest reboot, restarting.";
122         ReExecSelf();
123       }
124     }
125   });
126 }
127 
128 fruit::Component<fruit::Required<gatekeeper::SoftGateKeeper, TpmGatekeeper,
129                                  TpmResourceManager>,
130                  gatekeeper::GateKeeper, keymaster::KeymasterEnforcement>
ChooseGatekeeperComponent()131 ChooseGatekeeperComponent() {
132   if (FLAGS_gatekeeper_impl == "software") {
133     return fruit::createComponent()
134         .bind<gatekeeper::GateKeeper, gatekeeper::SoftGateKeeper>()
135         .registerProvider([]() -> keymaster::KeymasterEnforcement* {
136           return new keymaster::SoftKeymasterEnforcement(64, 64);
137         });
138   } else if (FLAGS_gatekeeper_impl == "tpm") {
139     return fruit::createComponent()
140         .bind<gatekeeper::GateKeeper, TpmGatekeeper>()
141         .registerProvider(
142             [](TpmResourceManager& resource_manager,
143                TpmGatekeeper& gatekeeper) -> keymaster::KeymasterEnforcement* {
144               return new TpmKeymasterEnforcement(resource_manager, gatekeeper);
145             });
146   } else {
147     LOG(FATAL) << "Invalid gatekeeper implementation: "
148                << FLAGS_gatekeeper_impl;
149     abort();
150   }
151 }
152 
ChooseOemlockComponent()153 fruit::Component<oemlock::OemLock> ChooseOemlockComponent() {
154   if (FLAGS_oemlock_impl == "software") {
155     return fruit::createComponent()
156         .bind<oemlock::OemLock, oemlock::SoftOemLock>();
157   } else if (FLAGS_oemlock_impl == "tpm") {
158     LOG(FATAL) << "Oemlock doesn't support TPM implementation";
159     abort();
160   } else {
161     LOG(FATAL) << "Invalid oemlock implementation: "
162                << FLAGS_oemlock_impl;
163     abort();
164   }
165 }
166 
167 fruit::Component<TpmResourceManager, gatekeeper::GateKeeper,
168                  oemlock::OemLock, keymaster::KeymasterEnforcement>
SecureEnvComponent()169 SecureEnvComponent() {
170   return fruit::createComponent()
171       .registerProvider([]() -> Tpm* {  // fruit will take ownership
172         if (FLAGS_tpm_impl == "in_memory") {
173           return new InProcessTpm();
174         } else if (FLAGS_tpm_impl == "host_device") {
175           return new DeviceTpm("/dev/tpm0");
176         } else {
177           LOG(FATAL) << "Unknown TPM implementation: " << FLAGS_tpm_impl;
178           abort();
179         }
180       })
181       .registerProvider([](Tpm* tpm) {
182         if (tpm->TctiContext() == nullptr) {
183           LOG(FATAL) << "Unable to connect to TPM implementation.";
184         }
185         ESYS_CONTEXT* esys_ptr = nullptr;
186         std::unique_ptr<ESYS_CONTEXT, void (*)(ESYS_CONTEXT*)> esys(
187             nullptr, [](ESYS_CONTEXT* esys) { Esys_Finalize(&esys); });
188         auto rc = Esys_Initialize(&esys_ptr, tpm->TctiContext(), nullptr);
189         if (rc != TPM2_RC_SUCCESS) {
190           LOG(FATAL) << "Could not initialize esys: " << Tss2_RC_Decode(rc)
191                      << " (" << rc << ")";
192         }
193         esys.reset(esys_ptr);
194         return esys;
195       })
196       .registerProvider(
197           [](std::unique_ptr<ESYS_CONTEXT, void (*)(ESYS_CONTEXT*)>& esys) {
198             return new TpmResourceManager(
199                 esys.get());  // fruit will take ownership
200           })
201       .registerProvider([](TpmResourceManager& resource_manager) {
202         return new FragileTpmStorage(resource_manager, "gatekeeper_secure");
203       })
204       .registerProvider([](TpmResourceManager& resource_manager) {
205         return new InsecureFallbackStorage(resource_manager,
206                                            "gatekeeper_insecure");
207       })
208       .registerProvider([](TpmResourceManager& resource_manager,
209                            FragileTpmStorage& secure_storage,
210                            InsecureFallbackStorage& insecure_storage) {
211         return new TpmGatekeeper(resource_manager, secure_storage,
212                                  insecure_storage);
213       })
214       .registerProvider([]() { return new gatekeeper::SoftGateKeeper(); })
215       .install(ChooseGatekeeperComponent)
216       .install(ChooseOemlockComponent);
217 }
218 
219 }  // namespace
220 
SecureEnvMain(int argc,char ** argv)221 int SecureEnvMain(int argc, char** argv) {
222   DefaultSubprocessLogging(argv);
223   gflags::ParseCommandLineFlags(&argc, &argv, true);
224   keymaster::SoftKeymasterLogger km_logger;
225 
226   fruit::Injector<TpmResourceManager, gatekeeper::GateKeeper,
227                   oemlock::OemLock, keymaster::KeymasterEnforcement>
228       injector(SecureEnvComponent);
229   TpmResourceManager* resource_manager = injector.get<TpmResourceManager*>();
230   gatekeeper::GateKeeper* gatekeeper = injector.get<gatekeeper::GateKeeper*>();
231   oemlock::OemLock* oemlock = injector.get<oemlock::OemLock*>();
232   keymaster::KeymasterEnforcement* keymaster_enforcement =
233       injector.get<keymaster::KeymasterEnforcement*>();
234   std::unique_ptr<keymaster::KeymasterContext> keymaster_context;
235   std::unique_ptr<keymaster::AndroidKeymaster> keymaster;
236 
237   std::vector<std::thread> threads;
238 
239   int security_level;
240   if (FLAGS_keymint_impl == "software") {
241     security_level = KM_SECURITY_LEVEL_SOFTWARE;
242   } else if (FLAGS_keymint_impl == "tpm") {
243     security_level = KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT;
244   } else {
245     LOG(FATAL) << "Unknown keymint implementation " << FLAGS_keymint_impl;
246     return -1;
247   }
248 
249   // The guest image may have either the C++ implementation of
250   // KeyMint/Keymaster, xor the Rust implementation of KeyMint.  Those different
251   // implementations each need to have a matching TA implementation in
252   // secure_env, but they use distincts ports (/dev/hvc3 for C++, /dev/hvc11 for
253   // Rust) so start threads for *both* TA implementations -- only one of them
254   // will receive any traffic from the guest.
255 
256   // Start the Rust reference implementation of KeyMint.
257   LOG(INFO) << "starting Rust KeyMint TA implementation in a thread";
258 
259   int keymint_in = FLAGS_keymint_fd_in;
260   int keymint_out = FLAGS_keymint_fd_out;
261   TpmResourceManager* rm = resource_manager;
262   threads.emplace_back([rm, keymint_in, keymint_out, security_level]() {
263     kmr_ta_main(keymint_in, keymint_out, security_level, rm);
264   });
265 
266   // Start the C++ reference implementation of KeyMint.
267   LOG(INFO) << "starting C++ KeyMint implementation in a thread with FDs in="
268             << FLAGS_keymaster_fd_in << ", out=" << FLAGS_keymaster_fd_out;
269   if (security_level == KM_SECURITY_LEVEL_SOFTWARE) {
270     keymaster_context.reset(new keymaster::PureSoftKeymasterContext(
271         keymaster::KmVersion::KEYMINT_3, KM_SECURITY_LEVEL_SOFTWARE));
272   } else if (security_level == KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT) {
273     keymaster_context.reset(
274         new TpmKeymasterContext(*resource_manager, *keymaster_enforcement));
275   } else {
276     LOG(FATAL) << "Unknown keymaster security level " << security_level
277                << " for " << FLAGS_keymint_impl;
278     return -1;
279   }
280   // keymaster::AndroidKeymaster puts the context pointer into a UniquePtr,
281   // taking ownership.
282   keymaster.reset(new keymaster::AndroidKeymaster(
283       new ProxyKeymasterContext(*keymaster_context), kOperationTableSize,
284       keymaster::MessageVersion(keymaster::KmVersion::KEYMINT_3,
285                                 0 /* km_date */)));
286 
287   auto keymaster_in = DupFdFlag(FLAGS_keymaster_fd_in);
288   auto keymaster_out = DupFdFlag(FLAGS_keymaster_fd_out);
289   keymaster::AndroidKeymaster* borrowed_km = keymaster.get();
290   threads.emplace_back([keymaster_in, keymaster_out, borrowed_km]() {
291     while (true) {
292       SharedFdKeymasterChannel keymaster_channel(keymaster_in, keymaster_out);
293 
294       KeymasterResponder keymaster_responder(keymaster_channel, *borrowed_km);
295 
296       while (keymaster_responder.ProcessMessage()) {
297       }
298     }
299   });
300 
301   auto gatekeeper_in = DupFdFlag(FLAGS_gatekeeper_fd_in);
302   auto gatekeeper_out = DupFdFlag(FLAGS_gatekeeper_fd_out);
303   threads.emplace_back([gatekeeper_in, gatekeeper_out, &gatekeeper]() {
304     while (true) {
305       SharedFdGatekeeperChannel gatekeeper_channel(gatekeeper_in,
306                                                    gatekeeper_out);
307 
308       GatekeeperResponder gatekeeper_responder(gatekeeper_channel, *gatekeeper);
309 
310       while (gatekeeper_responder.ProcessMessage()) {
311       }
312     }
313   });
314 
315   auto oemlock_in = DupFdFlag(FLAGS_oemlock_fd_in);
316   auto oemlock_out = DupFdFlag(FLAGS_oemlock_fd_out);
317   threads.emplace_back([oemlock_in, oemlock_out, &oemlock]() {
318     while (true) {
319       secure_env::SharedFdChannel channel(oemlock_in, oemlock_out);
320       oemlock::OemLockResponder responder(channel, *oemlock);
321       while (responder.ProcessMessage().ok()) {
322       }
323     }
324   });
325 
326   auto confui_server_fd = DupFdFlag(FLAGS_confui_server_fd);
327   threads.emplace_back([confui_server_fd, resource_manager]() {
328     ConfUiSignServer confui_sign_server(*resource_manager, confui_server_fd);
329     // no return, infinite loop
330     confui_sign_server.MainLoop();
331   });
332 
333   auto kernel_events_fd = DupFdFlag(FLAGS_kernel_events_fd);
334   threads.emplace_back(StartKernelEventMonitor(kernel_events_fd));
335 
336   for (auto& t : threads) {
337     t.join();
338   }
339 
340   return 0;
341 }
342 
343 }  // namespace cuttlefish
344 
main(int argc,char ** argv)345 int main(int argc, char** argv) {
346   return cuttlefish::SecureEnvMain(argc, argv);
347 }
348