1 #include "config.h"
2 
3 #include "utils.hpp"
4 
5 #include <phosphor-logging/lg2.hpp>
6 
7 #include <filesystem>
8 #include <fstream>
9 #include <string>
10 
11 PHOSPHOR_LOG2_USING;
12 
13 constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties";
14 
15 // Check if the TPM measurement file exists and has a valid value.
16 // If the TPM measurement is invalid, it logs an error message.
17 void checkTpmMeasurement()
18 {
19     bool tpmError = false;
20     std::string errorMsg;
21     if (!std::filesystem::exists(std::string(SYSFS_TPM_MEASUREMENT_PATH)))
22     {
23         tpmError = true;
24         errorMsg = "TPM measurement file does not exist: " +
25                    std::string(SYSFS_TPM_MEASUREMENT_PATH);
26     }
27     else
28     {
29         std::string tpmValueStr;
30         std::ifstream tpmFile(std::string(SYSFS_TPM_MEASUREMENT_PATH));
31 
32         tpmFile >> tpmValueStr;
33         if (tpmValueStr.empty())
34         {
35             tpmError = true;
36             errorMsg = "TPM measurement value is empty: " +
37                        std::string(SYSFS_TPM_MEASUREMENT_PATH);
38         }
39         else if (tpmValueStr == "0")
40         {
41             tpmError = true;
42             errorMsg = "TPM measurement value is 0: " +
43                        std::string(SYSFS_TPM_MEASUREMENT_PATH);
44         }
45         tpmFile.close();
46     }
47 
48     if (tpmError)
49     {
50         // Doesn't have valid TPM measurement, log an error message
51         std::map<std::string, std::string> additionalData;
52         error("{ERROR}", "ERROR", errorMsg);
53         additionalData.emplace("ERROR", errorMsg);
54         auto bus = sdbusplus::bus::new_default();
55         phosphor::state::manager::utils::createError(
56             bus, "xyz.openbmc_project.State.Error.TpmMeasurementFail",
57             sdbusplus::server::xyz::openbmc_project::logging::Entry::Level::
58                 Error,
59             additionalData);
60     }
61     return;
62 }
63 
64 // Utilize the QuiesceOnHwError setting as an indication that the system
65 // is operating in an environment where the user should be notified of
66 // security settings (i.e. "Manufacturing")
67 bool isMfgModeEnabled()
68 {
69     auto bus = sdbusplus::bus::new_default();
70     std::string path = "/xyz/openbmc_project/logging/settings";
71     std::string interface = "xyz.openbmc_project.Logging.Settings";
72     std::string propertyName = "QuiesceOnHwError";
73     std::variant<bool> mfgModeEnabled;
74 
75     std::string service =
76         phosphor::state::manager::utils::getService(bus, path, interface);
77 
78     auto method = bus.new_method_call(service.c_str(), path.c_str(),
79                                       PROPERTY_INTERFACE, "Get");
80 
81     method.append(interface, propertyName);
82 
83     try
84     {
85         auto reply = bus.call(method);
86         reply.read(mfgModeEnabled);
87     }
88     catch (const sdbusplus::exception_t& e)
89     {
90         error("Error in property Get, error {ERROR}, property {PROPERTY}",
91               "ERROR", e, "PROPERTY", propertyName);
92         throw;
93     }
94 
95     return std::get<bool>(mfgModeEnabled);
96 }
97 
98 int main()
99 {
100     // Read the secure boot gpio
101     auto secureBootGpio =
102         phosphor::state::manager::utils::getGpioValue("bmc-secure-boot");
103     if (secureBootGpio == -1)
104     {
105         debug("bmc-secure-boot gpio not present or can not be read");
106     }
107     else if (secureBootGpio == 0)
108     {
109         info("bmc-secure-boot gpio found and indicates it is NOT enabled");
110     }
111     else
112     {
113         info("bmc-secure-boot found and indicates it is enabled");
114     }
115 
116     // Now read the /sys/kernel/debug/aspeed/ files
117     std::string dbgVal;
118     std::ifstream dbgFile;
119     int secureBootVal = -1;
120     int abrImage = -1;
121 
122     dbgFile.exceptions(std::ifstream::failbit | std::ifstream::badbit |
123                        std::ifstream::eofbit);
124 
125     if (std::filesystem::exists(SYSFS_SECURE_BOOT_PATH))
126     {
127         try
128         {
129             dbgFile.open(SYSFS_SECURE_BOOT_PATH);
130             dbgFile >> dbgVal;
131             dbgFile.close();
132             info("Read {SECURE_BOOT_VAL} from secure_boot", "SECURE_BOOT_VAL",
133                  dbgVal);
134             secureBootVal = std::stoi(dbgVal);
135         }
136         catch (std::exception& e)
137         {
138             error("Failed to read secure boot sysfs file: {ERROR}", "ERROR", e);
139             // just continue and error will be logged at end if in mfg mode
140         }
141     }
142     else
143     {
144         info("sysfs file secure_boot not present");
145     }
146 
147     if (std::filesystem::exists(SYSFS_ABR_IMAGE_PATH))
148     {
149         try
150         {
151             dbgFile.open(SYSFS_ABR_IMAGE_PATH);
152             dbgFile >> dbgVal;
153             dbgFile.close();
154             info("Read {ABR_IMAGE_VAL} from abr_image", "ABR_IMAGE_VAL",
155                  dbgVal);
156             abrImage = std::stoi(dbgVal);
157         }
158         catch (std::exception& e)
159         {
160             error("Failed to read abr image sysfs file: {ERROR}", "ERROR", e);
161             // just continue and error will be logged at end if in mfg mode
162         }
163     }
164     else
165     {
166         info("sysfs file abr_image not present");
167     }
168 
169     if (isMfgModeEnabled())
170     {
171         if ((secureBootGpio != 1) || (secureBootVal != 1) || (abrImage != 0))
172         {
173             error("The system is not secure");
174             std::map<std::string, std::string> additionalData;
175             additionalData.emplace("SECURE_BOOT_GPIO",
176                                    std::to_string(secureBootGpio));
177             additionalData.emplace("SYSFS_SECURE_BOOT_VAL",
178                                    std::to_string(secureBootVal));
179             additionalData.emplace("SYSFS_ABR_IMAGE_VAL",
180                                    std::to_string(abrImage));
181 
182             auto bus = sdbusplus::bus::new_default();
183             phosphor::state::manager::utils::createError(
184                 bus, "xyz.openbmc_project.State.Error.SecurityCheckFail",
185                 sdbusplus::server::xyz::openbmc_project::logging::Entry::Level::
186                     Warning,
187                 additionalData);
188         }
189     }
190 
191     // Check the TPM measurement if TPM is enabled
192     if (std::filesystem::exists(std::string(SYSFS_TPM_DEVICE_PATH)))
193     {
194         checkTpmMeasurement();
195     }
196 
197     return 0;
198 }
199