• 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 <fruit/fruit.h>
20 #include <gflags/gflags.h>
21 #include <keymaster/android_keymaster.h>
22 #include <keymaster/contexts/pure_soft_keymaster_context.h>
23 #include <keymaster/soft_keymaster_logger.h>
24 #include <tss2/tss2_esys.h>
25 #include <tss2/tss2_rc.h>
26 
27 #include "common/libs/fs/shared_fd.h"
28 #include "common/libs/security/confui_sign.h"
29 #include "common/libs/security/gatekeeper_channel.h"
30 #include "common/libs/security/keymaster_channel.h"
31 #include "host/commands/kernel_log_monitor/kernel_log_server.h"
32 #include "host/commands/kernel_log_monitor/utils.h"
33 #include "host/commands/secure_env/confui_sign_server.h"
34 #include "host/commands/secure_env/device_tpm.h"
35 #include "host/commands/secure_env/fragile_tpm_storage.h"
36 #include "host/commands/secure_env/gatekeeper_responder.h"
37 #include "host/commands/secure_env/in_process_tpm.h"
38 #include "host/commands/secure_env/insecure_fallback_storage.h"
39 #include "host/commands/secure_env/keymaster_responder.h"
40 #include "host/commands/secure_env/proxy_keymaster_context.h"
41 #include "host/commands/secure_env/soft_gatekeeper.h"
42 #include "host/commands/secure_env/tpm_gatekeeper.h"
43 #include "host/commands/secure_env/tpm_keymaster_context.h"
44 #include "host/commands/secure_env/tpm_keymaster_enforcement.h"
45 #include "host/commands/secure_env/tpm_resource_manager.h"
46 #include "host/libs/config/logging.h"
47 
48 DEFINE_int32(confui_server_fd, -1, "A named socket to serve confirmation UI");
49 DEFINE_int32(keymaster_fd_in, -1, "A pipe for keymaster communication");
50 DEFINE_int32(keymaster_fd_out, -1, "A pipe for keymaster communication");
51 DEFINE_int32(gatekeeper_fd_in, -1, "A pipe for gatekeeper communication");
52 DEFINE_int32(gatekeeper_fd_out, -1, "A pipe for gatekeeper communication");
53 DEFINE_int32(kernel_events_fd, -1,
54              "A pipe for monitoring events based on "
55              "messages written to the kernel log. This "
56              "is used by secure_env to monitor for "
57              "device reboots.");
58 
59 DEFINE_string(tpm_impl,
60               "in_memory",
61               "The TPM implementation. \"in_memory\" or \"host_device\"");
62 
63 DEFINE_string(keymint_impl, "tpm",
64               "The keymaster implementation. \"tpm\" or \"software\"");
65 
66 DEFINE_string(gatekeeper_impl, "tpm",
67               "The gatekeeper implementation. \"tpm\" or \"software\"");
68 
69 namespace cuttlefish {
70 namespace {
71 
72 // Copied from AndroidKeymaster4Device
73 constexpr size_t kOperationTableSize = 16;
74 
75 // Dup a command line file descriptor into a SharedFD.
DupFdFlag(gflags::int32 fd)76 SharedFD DupFdFlag(gflags::int32 fd) {
77   CHECK(fd != -1);
78   SharedFD duped = SharedFD::Dup(fd);
79   CHECK(duped->IsOpen()) << "Could not dup output fd: " << duped->StrError();
80   // The original FD is intentionally kept open so that we can re-exec this
81   // process without having to do a bunch of argv book-keeping.
82   return duped;
83 }
84 
85 // Re-launch this process with all the same flags it was originallys started
86 // with.
ReExecSelf()87 [[noreturn]] void ReExecSelf() {
88   // Allocate +1 entry for terminating nullptr.
89   std::vector<char*> argv(gflags::GetArgvs().size() + 1, nullptr);
90   for (size_t i = 0; i < gflags::GetArgvs().size(); ++i) {
91     argv[i] = strdup(gflags::GetArgvs()[i].c_str());
92     CHECK(argv[i] != nullptr) << "OOM";
93   }
94   execv("/proc/self/exe", argv.data());
95   char buf[128];
96   LOG(FATAL) << "Exec failed, secure_env is out of sync with the guest: "
97              << errno << "(" << strerror_r(errno, buf, sizeof(buf)) << ")";
98   abort();  // LOG(FATAL) isn't marked as noreturn
99 }
100 
101 // Spin up a thread that monitors for a kernel loaded event, then re-execs
102 // this process. This way, secure_env's boot tracking matches up with the guest.
StartKernelEventMonitor(SharedFD kernel_events_fd)103 std::thread StartKernelEventMonitor(SharedFD kernel_events_fd) {
104   return std::thread([kernel_events_fd]() {
105     while (kernel_events_fd->IsOpen()) {
106       auto read_result = monitor::ReadEvent(kernel_events_fd);
107       CHECK(read_result.has_value()) << kernel_events_fd->StrError();
108       if (read_result->event == monitor::Event::BootloaderLoaded) {
109         LOG(DEBUG) << "secure_env detected guest reboot, restarting.";
110         ReExecSelf();
111       }
112     }
113   });
114 }
115 
116 fruit::Component<fruit::Required<gatekeeper::SoftGateKeeper, TpmGatekeeper,
117                                  TpmResourceManager>,
118                  gatekeeper::GateKeeper, keymaster::KeymasterEnforcement>
ChooseGatekeeperComponent()119 ChooseGatekeeperComponent() {
120   if (FLAGS_gatekeeper_impl == "software") {
121     return fruit::createComponent()
122         .bind<gatekeeper::GateKeeper, gatekeeper::SoftGateKeeper>()
123         .registerProvider([]() -> keymaster::KeymasterEnforcement* {
124           return new keymaster::SoftKeymasterEnforcement(64, 64);
125         });
126   } else if (FLAGS_gatekeeper_impl == "tpm") {
127     return fruit::createComponent()
128         .bind<gatekeeper::GateKeeper, TpmGatekeeper>()
129         .registerProvider(
130             [](TpmResourceManager& resource_manager,
131                TpmGatekeeper& gatekeeper) -> keymaster::KeymasterEnforcement* {
132               return new TpmKeymasterEnforcement(resource_manager, gatekeeper);
133             });
134   } else {
135     LOG(FATAL) << "Invalid gatekeeper implementation: "
136                << FLAGS_gatekeeper_impl;
137     abort();
138   }
139 }
140 
141 fruit::Component<TpmResourceManager, gatekeeper::GateKeeper,
142                  keymaster::KeymasterEnforcement>
SecureEnvComponent()143 SecureEnvComponent() {
144   return fruit::createComponent()
145       .registerProvider([]() -> Tpm* {  // fruit will take ownership
146         if (FLAGS_tpm_impl == "in_memory") {
147           return new InProcessTpm();
148         } else if (FLAGS_tpm_impl == "host_device") {
149           return new DeviceTpm("/dev/tpm0");
150         } else {
151           LOG(FATAL) << "Unknown TPM implementation: " << FLAGS_tpm_impl;
152           abort();
153         }
154       })
155       .registerProvider([](Tpm* tpm) {
156         if (tpm->TctiContext() == nullptr) {
157           LOG(FATAL) << "Unable to connect to TPM implementation.";
158         }
159         ESYS_CONTEXT* esys_ptr = nullptr;
160         std::unique_ptr<ESYS_CONTEXT, void (*)(ESYS_CONTEXT*)> esys(
161             nullptr, [](ESYS_CONTEXT* esys) { Esys_Finalize(&esys); });
162         auto rc = Esys_Initialize(&esys_ptr, tpm->TctiContext(), nullptr);
163         if (rc != TPM2_RC_SUCCESS) {
164           LOG(FATAL) << "Could not initialize esys: " << Tss2_RC_Decode(rc)
165                      << " (" << rc << ")";
166         }
167         esys.reset(esys_ptr);
168         return esys;
169       })
170       .registerProvider(
171           [](std::unique_ptr<ESYS_CONTEXT, void (*)(ESYS_CONTEXT*)>& esys) {
172             return new TpmResourceManager(
173                 esys.get());  // fruit will take ownership
174           })
175       .registerProvider([](TpmResourceManager& resource_manager) {
176         return new FragileTpmStorage(resource_manager, "gatekeeper_secure");
177       })
178       .registerProvider([](TpmResourceManager& resource_manager) {
179         return new InsecureFallbackStorage(resource_manager,
180                                            "gatekeeper_insecure");
181       })
182       .registerProvider([](TpmResourceManager& resource_manager,
183                            FragileTpmStorage& secure_storage,
184                            InsecureFallbackStorage& insecure_storage) {
185         return new TpmGatekeeper(resource_manager, secure_storage,
186                                  insecure_storage);
187       })
188       .registerProvider([]() { return new gatekeeper::SoftGateKeeper(); })
189       .install(ChooseGatekeeperComponent);
190 }
191 
192 }  // namespace
193 
SecureEnvMain(int argc,char ** argv)194 int SecureEnvMain(int argc, char** argv) {
195   DefaultSubprocessLogging(argv);
196   gflags::ParseCommandLineFlags(&argc, &argv, true);
197   keymaster::SoftKeymasterLogger km_logger;
198 
199   fruit::Injector<TpmResourceManager, gatekeeper::GateKeeper,
200                   keymaster::KeymasterEnforcement>
201       injector(SecureEnvComponent);
202   TpmResourceManager* resource_manager = injector.get<TpmResourceManager*>();
203   gatekeeper::GateKeeper* gatekeeper = injector.get<gatekeeper::GateKeeper*>();
204   keymaster::KeymasterEnforcement* keymaster_enforcement =
205       injector.get<keymaster::KeymasterEnforcement*>();
206 
207   std::unique_ptr<keymaster::KeymasterContext> keymaster_context;
208   if (FLAGS_keymint_impl == "software") {
209     // TODO: See if this is the right KM version.
210     keymaster_context.reset(new keymaster::PureSoftKeymasterContext(
211         keymaster::KmVersion::KEYMINT_2, KM_SECURITY_LEVEL_SOFTWARE));
212   } else if (FLAGS_keymint_impl == "tpm") {
213     keymaster_context.reset(
214         new TpmKeymasterContext(*resource_manager, *keymaster_enforcement));
215   } else {
216     LOG(FATAL) << "Unknown keymaster implementation " << FLAGS_keymint_impl;
217     return -1;
218   }
219   // keymaster::AndroidKeymaster puts the context pointer into a UniquePtr,
220   // taking ownership.
221   keymaster::AndroidKeymaster keymaster{
222       new ProxyKeymasterContext(*keymaster_context), kOperationTableSize,
223       keymaster::MessageVersion(keymaster::KmVersion::KEYMINT_2,
224                                 0 /* km_date */)};
225 
226   auto confui_server_fd = DupFdFlag(FLAGS_confui_server_fd);
227   auto keymaster_in = DupFdFlag(FLAGS_keymaster_fd_in);
228   auto keymaster_out = DupFdFlag(FLAGS_keymaster_fd_out);
229   auto gatekeeper_in = DupFdFlag(FLAGS_gatekeeper_fd_in);
230   auto gatekeeper_out = DupFdFlag(FLAGS_gatekeeper_fd_out);
231   auto kernel_events_fd = DupFdFlag(FLAGS_kernel_events_fd);
232 
233   std::vector<std::thread> threads;
234 
235   threads.emplace_back([keymaster_in, keymaster_out, &keymaster]() {
236     while (true) {
237       KeymasterChannel keymaster_channel(keymaster_in, keymaster_out);
238 
239       KeymasterResponder keymaster_responder(keymaster_channel, keymaster);
240 
241       while (keymaster_responder.ProcessMessage()) {
242       }
243     }
244   });
245 
246   threads.emplace_back([gatekeeper_in, gatekeeper_out, &gatekeeper]() {
247     while (true) {
248       GatekeeperChannel gatekeeper_channel(gatekeeper_in, gatekeeper_out);
249 
250       GatekeeperResponder gatekeeper_responder(gatekeeper_channel, *gatekeeper);
251 
252       while (gatekeeper_responder.ProcessMessage()) {
253       }
254     }
255   });
256 
257   threads.emplace_back([confui_server_fd, resource_manager]() {
258     ConfUiSignServer confui_sign_server(*resource_manager, confui_server_fd);
259     // no return, infinite loop
260     confui_sign_server.MainLoop();
261   });
262   threads.emplace_back(StartKernelEventMonitor(kernel_events_fd));
263 
264   for (auto& t : threads) {
265     t.join();
266   }
267 
268   return 0;
269 }
270 
271 }  // namespace cuttlefish
272 
main(int argc,char ** argv)273 int main(int argc, char** argv) {
274   return cuttlefish::SecureEnvMain(argc, argv);
275 }
276