xref: /aosp_15_r20/system/core/libmodprobe/exthandler.cpp (revision 00c7fec1bb09f3284aad6a6f96d2f63dfc3650ad)
1*00c7fec1SAndroid Build Coastguard Worker /*
2*00c7fec1SAndroid Build Coastguard Worker  * Copyright (C) 2024 The Android Open Source Project
3*00c7fec1SAndroid Build Coastguard Worker  *
4*00c7fec1SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*00c7fec1SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*00c7fec1SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*00c7fec1SAndroid Build Coastguard Worker  *
8*00c7fec1SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*00c7fec1SAndroid Build Coastguard Worker  *
10*00c7fec1SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*00c7fec1SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*00c7fec1SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*00c7fec1SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*00c7fec1SAndroid Build Coastguard Worker  * limitations under the License.
15*00c7fec1SAndroid Build Coastguard Worker  */
16*00c7fec1SAndroid Build Coastguard Worker 
17*00c7fec1SAndroid Build Coastguard Worker #include <exthandler/exthandler.h>
18*00c7fec1SAndroid Build Coastguard Worker 
19*00c7fec1SAndroid Build Coastguard Worker #include <android-base/chrono_utils.h>
20*00c7fec1SAndroid Build Coastguard Worker #include <android-base/file.h>
21*00c7fec1SAndroid Build Coastguard Worker #include <android-base/logging.h>
22*00c7fec1SAndroid Build Coastguard Worker #include <android-base/parseint.h>
23*00c7fec1SAndroid Build Coastguard Worker #include <android-base/strings.h>
24*00c7fec1SAndroid Build Coastguard Worker #include <android-base/unique_fd.h>
25*00c7fec1SAndroid Build Coastguard Worker #include <fnmatch.h>
26*00c7fec1SAndroid Build Coastguard Worker #include <grp.h>
27*00c7fec1SAndroid Build Coastguard Worker #include <pwd.h>
28*00c7fec1SAndroid Build Coastguard Worker #include <sys/wait.h>
29*00c7fec1SAndroid Build Coastguard Worker 
30*00c7fec1SAndroid Build Coastguard Worker using android::base::ErrnoError;
31*00c7fec1SAndroid Build Coastguard Worker using android::base::Error;
32*00c7fec1SAndroid Build Coastguard Worker using android::base::ReadFdToString;
33*00c7fec1SAndroid Build Coastguard Worker using android::base::Result;
34*00c7fec1SAndroid Build Coastguard Worker using android::base::Split;
35*00c7fec1SAndroid Build Coastguard Worker using android::base::Trim;
36*00c7fec1SAndroid Build Coastguard Worker using android::base::unique_fd;
37*00c7fec1SAndroid Build Coastguard Worker 
RunExternalHandler(const std::string & handler,uid_t uid,gid_t gid,std::unordered_map<std::string,std::string> & envs_map)38*00c7fec1SAndroid Build Coastguard Worker Result<std::string> RunExternalHandler(const std::string& handler, uid_t uid, gid_t gid,
39*00c7fec1SAndroid Build Coastguard Worker                                        std::unordered_map<std::string, std::string>& envs_map) {
40*00c7fec1SAndroid Build Coastguard Worker     unique_fd child_stdout;
41*00c7fec1SAndroid Build Coastguard Worker     unique_fd parent_stdout;
42*00c7fec1SAndroid Build Coastguard Worker     if (!Socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, &child_stdout, &parent_stdout)) {
43*00c7fec1SAndroid Build Coastguard Worker         return ErrnoError() << "Socketpair() for stdout failed";
44*00c7fec1SAndroid Build Coastguard Worker     }
45*00c7fec1SAndroid Build Coastguard Worker 
46*00c7fec1SAndroid Build Coastguard Worker     unique_fd child_stderr;
47*00c7fec1SAndroid Build Coastguard Worker     unique_fd parent_stderr;
48*00c7fec1SAndroid Build Coastguard Worker     if (!Socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, &child_stderr, &parent_stderr)) {
49*00c7fec1SAndroid Build Coastguard Worker         return ErrnoError() << "Socketpair() for stderr failed";
50*00c7fec1SAndroid Build Coastguard Worker     }
51*00c7fec1SAndroid Build Coastguard Worker 
52*00c7fec1SAndroid Build Coastguard Worker     signal(SIGCHLD, SIG_DFL);
53*00c7fec1SAndroid Build Coastguard Worker 
54*00c7fec1SAndroid Build Coastguard Worker     auto pid = fork();
55*00c7fec1SAndroid Build Coastguard Worker     if (pid < 0) {
56*00c7fec1SAndroid Build Coastguard Worker         return ErrnoError() << "fork() failed";
57*00c7fec1SAndroid Build Coastguard Worker     }
58*00c7fec1SAndroid Build Coastguard Worker 
59*00c7fec1SAndroid Build Coastguard Worker     if (pid == 0) {
60*00c7fec1SAndroid Build Coastguard Worker         for (auto it = envs_map.begin(); it != envs_map.end(); ++it) {
61*00c7fec1SAndroid Build Coastguard Worker             setenv(it->first.c_str(), it->second.c_str(), 1);
62*00c7fec1SAndroid Build Coastguard Worker         }
63*00c7fec1SAndroid Build Coastguard Worker         parent_stdout.reset();
64*00c7fec1SAndroid Build Coastguard Worker         parent_stderr.reset();
65*00c7fec1SAndroid Build Coastguard Worker         close(STDOUT_FILENO);
66*00c7fec1SAndroid Build Coastguard Worker         close(STDERR_FILENO);
67*00c7fec1SAndroid Build Coastguard Worker         dup2(child_stdout.get(), STDOUT_FILENO);
68*00c7fec1SAndroid Build Coastguard Worker         dup2(child_stderr.get(), STDERR_FILENO);
69*00c7fec1SAndroid Build Coastguard Worker 
70*00c7fec1SAndroid Build Coastguard Worker         auto args = Split(handler, " ");
71*00c7fec1SAndroid Build Coastguard Worker         std::vector<char*> c_args;
72*00c7fec1SAndroid Build Coastguard Worker         for (auto& arg : args) {
73*00c7fec1SAndroid Build Coastguard Worker             c_args.emplace_back(arg.data());
74*00c7fec1SAndroid Build Coastguard Worker         }
75*00c7fec1SAndroid Build Coastguard Worker         c_args.emplace_back(nullptr);
76*00c7fec1SAndroid Build Coastguard Worker 
77*00c7fec1SAndroid Build Coastguard Worker         if (gid != 0) {
78*00c7fec1SAndroid Build Coastguard Worker             if (setgid(gid) != 0) {
79*00c7fec1SAndroid Build Coastguard Worker                 fprintf(stderr, "setgid() failed: %s", strerror(errno));
80*00c7fec1SAndroid Build Coastguard Worker                 _exit(EXIT_FAILURE);
81*00c7fec1SAndroid Build Coastguard Worker             }
82*00c7fec1SAndroid Build Coastguard Worker         }
83*00c7fec1SAndroid Build Coastguard Worker 
84*00c7fec1SAndroid Build Coastguard Worker         if (setuid(uid) != 0) {
85*00c7fec1SAndroid Build Coastguard Worker             fprintf(stderr, "setuid() failed: %s", strerror(errno));
86*00c7fec1SAndroid Build Coastguard Worker             _exit(EXIT_FAILURE);
87*00c7fec1SAndroid Build Coastguard Worker         }
88*00c7fec1SAndroid Build Coastguard Worker 
89*00c7fec1SAndroid Build Coastguard Worker         execv(c_args[0], c_args.data());
90*00c7fec1SAndroid Build Coastguard Worker         fprintf(stderr, "exec() failed: %s", strerror(errno));
91*00c7fec1SAndroid Build Coastguard Worker         _exit(EXIT_FAILURE);
92*00c7fec1SAndroid Build Coastguard Worker     }
93*00c7fec1SAndroid Build Coastguard Worker 
94*00c7fec1SAndroid Build Coastguard Worker     child_stdout.reset();
95*00c7fec1SAndroid Build Coastguard Worker     child_stderr.reset();
96*00c7fec1SAndroid Build Coastguard Worker 
97*00c7fec1SAndroid Build Coastguard Worker     int status;
98*00c7fec1SAndroid Build Coastguard Worker     pid_t waited_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
99*00c7fec1SAndroid Build Coastguard Worker     if (waited_pid == -1) {
100*00c7fec1SAndroid Build Coastguard Worker         return ErrnoError() << "waitpid() failed";
101*00c7fec1SAndroid Build Coastguard Worker     }
102*00c7fec1SAndroid Build Coastguard Worker 
103*00c7fec1SAndroid Build Coastguard Worker     std::string stdout_content;
104*00c7fec1SAndroid Build Coastguard Worker     if (!ReadFdToString(parent_stdout.get(), &stdout_content)) {
105*00c7fec1SAndroid Build Coastguard Worker         return ErrnoError() << "ReadFdToString() for stdout failed";
106*00c7fec1SAndroid Build Coastguard Worker     }
107*00c7fec1SAndroid Build Coastguard Worker 
108*00c7fec1SAndroid Build Coastguard Worker     std::string stderr_content;
109*00c7fec1SAndroid Build Coastguard Worker     if (ReadFdToString(parent_stderr.get(), &stderr_content)) {
110*00c7fec1SAndroid Build Coastguard Worker         auto messages = Split(stderr_content, "\n");
111*00c7fec1SAndroid Build Coastguard Worker         for (const auto& message : messages) {
112*00c7fec1SAndroid Build Coastguard Worker             if (!message.empty()) {
113*00c7fec1SAndroid Build Coastguard Worker                 LOG(ERROR) << "External Handler: " << message;
114*00c7fec1SAndroid Build Coastguard Worker             }
115*00c7fec1SAndroid Build Coastguard Worker         }
116*00c7fec1SAndroid Build Coastguard Worker     } else {
117*00c7fec1SAndroid Build Coastguard Worker         LOG(ERROR) << "ReadFdToString() for stderr failed";
118*00c7fec1SAndroid Build Coastguard Worker     }
119*00c7fec1SAndroid Build Coastguard Worker 
120*00c7fec1SAndroid Build Coastguard Worker     if (WIFEXITED(status)) {
121*00c7fec1SAndroid Build Coastguard Worker         if (WEXITSTATUS(status) == EXIT_SUCCESS) {
122*00c7fec1SAndroid Build Coastguard Worker             return Trim(stdout_content);
123*00c7fec1SAndroid Build Coastguard Worker         } else {
124*00c7fec1SAndroid Build Coastguard Worker             return Error() << "exited with status " << WEXITSTATUS(status);
125*00c7fec1SAndroid Build Coastguard Worker         }
126*00c7fec1SAndroid Build Coastguard Worker     } else if (WIFSIGNALED(status)) {
127*00c7fec1SAndroid Build Coastguard Worker         return Error() << "killed by signal " << WTERMSIG(status);
128*00c7fec1SAndroid Build Coastguard Worker     }
129*00c7fec1SAndroid Build Coastguard Worker 
130*00c7fec1SAndroid Build Coastguard Worker     return Error() << "unexpected exit status " << status;
131*00c7fec1SAndroid Build Coastguard Worker }
132