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 
17 #include <stdio.h>
18 
19 #include <android-base/endian.h>
20 #include <gflags/gflags.h>
21 #include <android-base/logging.h>
22 
23 #include "host/libs/config/cuttlefish_config.h"
24 #include "host/libs/config/logging.h"
25 #include "common/libs/fs/shared_buf.h"
26 #include "common/libs/fs/shared_fd.h"
27 #include "common/libs/utils/subprocess.h"
28 
29 DEFINE_int32(port, 0, "The port to run the TPM simulator on. Consumes the next "
30                       "port as well for platform commands.");
31 
32 namespace {
33 
HasSubstrings(const std::string & string,const std::vector<std::string> & substrings)34 bool HasSubstrings(const std::string& string, const std::vector<std::string>& substrings) {
35   for (const auto& substr : substrings) {
36     if (string.find(substr) == std::string::npos) {
37       return false;
38     }
39   }
40   return true;
41 }
42 
43 } // namespace
44 
main(int argc,char ** argv)45 int main(int argc, char** argv) {
46   cuttlefish::DefaultSubprocessLogging(argv);
47   google::ParseCommandLineFlags(&argc, &argv, true);
48 
49   CHECK(FLAGS_port > 0) << "A port must be set";
50   auto config = cuttlefish::CuttlefishConfig::Get();
51   CHECK(config) << "Unable to get config object";
52 
53   // Assumes linked on the host with glibc
54   cuttlefish::Command simulator_cmd("/usr/bin/stdbuf");
55   simulator_cmd.AddParameter("-oL");
56   simulator_cmd.AddParameter(config->tpm_binary());
57   simulator_cmd.AddParameter(FLAGS_port);
58 
59   cuttlefish::SharedFD sim_stdout_in, sim_stdout_out;
60   CHECK(cuttlefish::SharedFD::Pipe(&sim_stdout_out, &sim_stdout_in))
61       << "Unable to open pipe for stdout: " << strerror(errno);
62   simulator_cmd.RedirectStdIO(cuttlefish::Subprocess::StdIOChannel::kStdOut, sim_stdout_in);
63 
64   auto tpm_subprocess = simulator_cmd.Start();
65 
66   sim_stdout_in->Close();
67 
68   std::unique_ptr<FILE, int(*)(FILE*)> stdout_file(
69       fdopen(sim_stdout_out->UNMANAGED_Dup(), "r"), &fclose);
70   sim_stdout_out->Close();
71 
72   bool command_server = false;
73   bool platform_server = false;
74   bool sent_init = false;
75 
76   cuttlefish::SharedFD client; // Hold this connection open for the process lifetime.
77 
78   char* lineptr = nullptr;
79   size_t size = 0;
80   while (getline(&lineptr, &size, stdout_file.get()) >= 0) {
81     std::string line(lineptr);
82     line = line.substr(0, line.size() - 1);
83     if (HasSubstrings(line, {"TPM", "command", "server", "listening", "on", "port"})) {
84       command_server = true;
85     }
86     if (HasSubstrings(line, {"Platform", "server", "listening", "on", "port"})) {
87       platform_server = true;
88     }
89     if (command_server && platform_server && !sent_init) {
90       client = cuttlefish::SharedFD::SocketLocalClient(FLAGS_port + 1, SOCK_STREAM);
91       std::uint32_t command = htobe32(1); // TPM_SIGNAL_POWER_ON
92       CHECK(cuttlefish::WriteAllBinary(client, &command) == 4)
93           << "Could not send TPM_SIGNAL_POWER_ON";
94       std::uint32_t response;
95       CHECK(cuttlefish::ReadExactBinary(client, &response) == 4)
96           << "Could not read parity response";
97 
98       command = htobe32(11); // TPM_SIGNAL_NV_ON
99       CHECK(cuttlefish::WriteAllBinary(client, &command) == 4)
100           << "Could not send TPM_SIGNAL_NV_ON";
101       CHECK(cuttlefish::ReadExactBinary(client, &response) == 4)
102           << "Could not read parity response";
103 
104       sent_init = true;
105     }
106     LOG(INFO) << "TPM2SIM: " << line;
107   }
108   free(lineptr);
109 
110   return tpm_subprocess.Wait() ? 0 : 1;
111 }
112