1 /*
2  * Copyright (C) 2017 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 "firmware_handler.h"
18 
19 #include <fcntl.h>
20 #include <pwd.h>
21 #include <signal.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/sendfile.h>
25 #include <sys/wait.h>
26 #include <unistd.h>
27 
28 #include <thread>
29 
30 #include <android-base/chrono_utils.h>
31 #include <android-base/file.h>
32 #include <android-base/logging.h>
33 #include <android-base/strings.h>
34 #include <android-base/unique_fd.h>
35 
36 using android::base::ReadFdToString;
37 using android::base::Socketpair;
38 using android::base::Split;
39 using android::base::Timer;
40 using android::base::Trim;
41 using android::base::unique_fd;
42 using android::base::WriteFully;
43 
44 namespace android {
45 namespace init {
46 
LoadFirmware(const std::string & firmware,const std::string & root,int fw_fd,size_t fw_size,int loading_fd,int data_fd)47 static void LoadFirmware(const std::string& firmware, const std::string& root, int fw_fd,
48                          size_t fw_size, int loading_fd, int data_fd) {
49     // Start transfer.
50     WriteFully(loading_fd, "1", 1);
51 
52     // Copy the firmware.
53     int rc = sendfile(data_fd, fw_fd, nullptr, fw_size);
54     if (rc == -1) {
55         PLOG(ERROR) << "firmware: sendfile failed { '" << root << "', '" << firmware << "' }";
56     }
57 
58     // Tell the firmware whether to abort or commit.
59     const char* response = (rc != -1) ? "0" : "-1";
60     WriteFully(loading_fd, response, strlen(response));
61 }
62 
IsBooting()63 static bool IsBooting() {
64     return access("/dev/.booting", F_OK) == 0;
65 }
66 
FirmwareHandler(std::vector<std::string> firmware_directories,std::vector<ExternalFirmwareHandler> external_firmware_handlers)67 FirmwareHandler::FirmwareHandler(std::vector<std::string> firmware_directories,
68                                  std::vector<ExternalFirmwareHandler> external_firmware_handlers)
69     : firmware_directories_(std::move(firmware_directories)),
70       external_firmware_handlers_(std::move(external_firmware_handlers)) {}
71 
RunExternalHandler(const std::string & handler,uid_t uid,const Uevent & uevent) const72 Result<std::string> FirmwareHandler::RunExternalHandler(const std::string& handler, uid_t uid,
73                                                         const Uevent& uevent) const {
74     unique_fd child_stdout;
75     unique_fd parent_stdout;
76     if (!Socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, &child_stdout, &parent_stdout)) {
77         return ErrnoError() << "Socketpair() for stdout failed";
78     }
79 
80     unique_fd child_stderr;
81     unique_fd parent_stderr;
82     if (!Socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, &child_stderr, &parent_stderr)) {
83         return ErrnoError() << "Socketpair() for stderr failed";
84     }
85 
86     signal(SIGCHLD, SIG_DFL);
87 
88     auto pid = fork();
89     if (pid < 0) {
90         return ErrnoError() << "fork() failed";
91     }
92 
93     if (pid == 0) {
94         setenv("FIRMWARE", uevent.firmware.c_str(), 1);
95         setenv("DEVPATH", uevent.path.c_str(), 1);
96         parent_stdout.reset();
97         parent_stderr.reset();
98         close(STDOUT_FILENO);
99         close(STDERR_FILENO);
100         dup2(child_stdout.get(), STDOUT_FILENO);
101         dup2(child_stderr.get(), STDERR_FILENO);
102 
103         auto args = Split(handler, " ");
104         std::vector<char*> c_args;
105         for (auto& arg : args) {
106             c_args.emplace_back(arg.data());
107         }
108         c_args.emplace_back(nullptr);
109 
110         if (setuid(uid) != 0) {
111             fprintf(stderr, "setuid() failed: %s", strerror(errno));
112             _exit(EXIT_FAILURE);
113         }
114 
115         execv(c_args[0], c_args.data());
116         fprintf(stderr, "exec() failed: %s", strerror(errno));
117         _exit(EXIT_FAILURE);
118     }
119 
120     child_stdout.reset();
121     child_stderr.reset();
122 
123     int status;
124     pid_t waited_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
125     if (waited_pid == -1) {
126         return ErrnoError() << "waitpid() failed";
127     }
128 
129     std::string stdout_content;
130     if (!ReadFdToString(parent_stdout.get(), &stdout_content)) {
131         return ErrnoError() << "ReadFdToString() for stdout failed";
132     }
133 
134     std::string stderr_content;
135     if (ReadFdToString(parent_stderr.get(), &stderr_content)) {
136         auto messages = Split(stderr_content, "\n");
137         for (const auto& message : messages) {
138             if (!message.empty()) {
139                 LOG(ERROR) << "External Firmware Handler: " << message;
140             }
141         }
142     } else {
143         LOG(ERROR) << "ReadFdToString() for stderr failed";
144     }
145 
146     if (WIFEXITED(status)) {
147         if (WEXITSTATUS(status) == EXIT_SUCCESS) {
148             return Trim(stdout_content);
149         } else {
150             return Error() << "exited with status " << WEXITSTATUS(status);
151         }
152     } else if (WIFSIGNALED(status)) {
153         return Error() << "killed by signal " << WTERMSIG(status);
154     }
155 
156     return Error() << "unexpected exit status " << status;
157 }
158 
GetFirmwarePath(const Uevent & uevent) const159 std::string FirmwareHandler::GetFirmwarePath(const Uevent& uevent) const {
160     for (const auto& external_handler : external_firmware_handlers_) {
161         if (external_handler.devpath == uevent.path) {
162             LOG(INFO) << "Launching external firmware handler '" << external_handler.handler_path
163                       << "' for devpath: '" << uevent.path << "' firmware: '" << uevent.firmware
164                       << "'";
165 
166             auto result =
167                     RunExternalHandler(external_handler.handler_path, external_handler.uid, uevent);
168             if (!result.ok()) {
169                 LOG(ERROR) << "Using default firmware; External firmware handler failed: "
170                            << result.error();
171                 return uevent.firmware;
172             }
173             if (result->find("..") != std::string::npos) {
174                 LOG(ERROR) << "Using default firmware; External firmware handler provided an "
175                               "invalid path, '"
176                            << *result << "'";
177                 return uevent.firmware;
178             }
179             LOG(INFO) << "Loading firmware '" << *result << "' in place of '" << uevent.firmware
180                       << "'";
181             return *result;
182         }
183     }
184     LOG(INFO) << "firmware: loading '" << uevent.firmware << "' for '" << uevent.path << "'";
185     return uevent.firmware;
186 }
187 
ProcessFirmwareEvent(const std::string & root,const std::string & firmware) const188 void FirmwareHandler::ProcessFirmwareEvent(const std::string& root,
189                                            const std::string& firmware) const {
190     std::string loading = root + "/loading";
191     std::string data = root + "/data";
192 
193     unique_fd loading_fd(open(loading.c_str(), O_WRONLY | O_CLOEXEC));
194     if (loading_fd == -1) {
195         PLOG(ERROR) << "couldn't open firmware loading fd for " << firmware;
196         return;
197     }
198 
199     unique_fd data_fd(open(data.c_str(), O_WRONLY | O_CLOEXEC));
200     if (data_fd == -1) {
201         PLOG(ERROR) << "couldn't open firmware data fd for " << firmware;
202         return;
203     }
204 
205     std::vector<std::string> attempted_paths_and_errors;
206 
207     int booting = IsBooting();
208 try_loading_again:
209     attempted_paths_and_errors.clear();
210     for (const auto& firmware_directory : firmware_directories_) {
211         std::string file = firmware_directory + firmware;
212         unique_fd fw_fd(open(file.c_str(), O_RDONLY | O_CLOEXEC));
213         if (fw_fd == -1) {
214             attempted_paths_and_errors.emplace_back("firmware: attempted " + file +
215                                                     ", open failed: " + strerror(errno));
216             continue;
217         }
218         struct stat sb;
219         if (fstat(fw_fd, &sb) == -1) {
220             attempted_paths_and_errors.emplace_back("firmware: attempted " + file +
221                                                     ", fstat failed: " + strerror(errno));
222             continue;
223         }
224         LoadFirmware(firmware, root, fw_fd, sb.st_size, loading_fd, data_fd);
225         return;
226     }
227 
228     if (booting) {
229         // If we're not fully booted, we may be missing
230         // filesystems needed for firmware, wait and retry.
231         std::this_thread::sleep_for(100ms);
232         booting = IsBooting();
233         goto try_loading_again;
234     }
235 
236     LOG(ERROR) << "firmware: could not find firmware for " << firmware;
237     for (const auto& message : attempted_paths_and_errors) {
238         LOG(ERROR) << message;
239     }
240 
241     // Write "-1" as our response to the kernel's firmware request, since we have nothing for it.
242     write(loading_fd, "-1", 2);
243 }
244 
HandleUevent(const Uevent & uevent)245 void FirmwareHandler::HandleUevent(const Uevent& uevent) {
246     if (uevent.subsystem != "firmware" || uevent.action != "add") return;
247 
248     // Loading the firmware in a child means we can do that in parallel...
249     auto pid = fork();
250     if (pid == -1) {
251         PLOG(ERROR) << "could not fork to process firmware event for " << uevent.firmware;
252     }
253     if (pid == 0) {
254         Timer t;
255         auto firmware = GetFirmwarePath(uevent);
256         ProcessFirmwareEvent("/sys" + uevent.path, firmware);
257         LOG(INFO) << "loading " << uevent.path << " took " << t;
258         _exit(EXIT_SUCCESS);
259     }
260 }
261 
262 }  // namespace init
263 }  // namespace android
264