blob: 9695e07753ebab14ad7b5eb332ad81b2cd4bb054 [file] [log] [blame]
Dianne Hackborn23eb1e22015-10-07 17:35:27 -07001/*
2 * Copyright (C) 2015 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#define LOG_TAG "cmd"
18
19#include <utils/Log.h>
20#include <binder/Parcel.h>
21#include <binder/ProcessState.h>
22#include <binder/IResultReceiver.h>
23#include <binder/IServiceManager.h>
Dianne Hackborn1941a402016-08-29 12:30:43 -070024#include <binder/IShellCallback.h>
Dianne Hackborn23eb1e22015-10-07 17:35:27 -070025#include <binder/TextOutput.h>
Dianne Hackborn3d9eb952016-10-17 17:40:47 -070026#include <utils/Condition.h>
27#include <utils/Mutex.h>
Dianne Hackborn23eb1e22015-10-07 17:35:27 -070028#include <utils/Vector.h>
29
Tomasz Wasilczyk09f0cc62023-08-22 17:40:55 +000030#include <filesystem>
Dianne Hackborn23eb1e22015-10-07 17:35:27 -070031#include <getopt.h>
32#include <stdlib.h>
33#include <stdio.h>
34#include <string.h>
35#include <unistd.h>
Dianne Hackborn1941a402016-08-29 12:30:43 -070036#include <fcntl.h>
Dianne Hackborn23eb1e22015-10-07 17:35:27 -070037#include <sys/time.h>
Dianne Hackborn1941a402016-08-29 12:30:43 -070038#include <errno.h>
Jiyong Park4e7d18a2017-08-07 20:48:32 +090039#include <memory>
Dianne Hackborn1941a402016-08-29 12:30:43 -070040
41#include "selinux/selinux.h"
42#include "selinux/android.h"
43
Alex Buynytskyya39d87a2018-12-12 17:40:52 -080044#include "cmd.h"
45
Dianne Hackborn3d9eb952016-10-17 17:40:47 -070046#define DEBUG 0
47
Dianne Hackborn23eb1e22015-10-07 17:35:27 -070048using namespace android;
49
50static int sort_func(const String16* lhs, const String16* rhs)
51{
52 return lhs->compare(*rhs);
53}
54
Dianne Hackborn1941a402016-08-29 12:30:43 -070055struct SecurityContext_Delete {
ThiƩbaud Weksteen146ed6e2021-09-15 20:06:13 +020056 void operator()(char* p) const {
Dianne Hackborn1941a402016-08-29 12:30:43 -070057 freecon(p);
58 }
59};
Jiyong Park4e7d18a2017-08-07 20:48:32 +090060typedef std::unique_ptr<char[], SecurityContext_Delete> Unique_SecurityContext;
Dianne Hackborn1941a402016-08-29 12:30:43 -070061
62class MyShellCallback : public BnShellCallback
63{
64public:
Alex Buynytskyya39d87a2018-12-12 17:40:52 -080065 TextOutput& mErrorLog;
Dianne Hackborne5ed1992016-10-10 16:35:45 -070066 bool mActive = true;
67
Alex Buynytskyya39d87a2018-12-12 17:40:52 -080068 MyShellCallback(TextOutput& errorLog) : mErrorLog(errorLog) {}
69
Dianne Hackborn4217f8e2017-10-30 14:31:41 -070070 virtual int openFile(const String16& path, const String16& seLinuxContext,
71 const String16& mode) {
Dianne Hackborn1941a402016-08-29 12:30:43 -070072 String8 path8(path);
Tomasz Wasilczyk09f0cc62023-08-22 17:40:55 +000073 auto fullPath = std::filesystem::current_path();
74 fullPath /= path8.c_str();
Dianne Hackborne5ed1992016-10-10 16:35:45 -070075 if (!mActive) {
Alex Buynytskyya39d87a2018-12-12 17:40:52 -080076 mErrorLog << "Open attempt after active for: " << fullPath << endl;
Dianne Hackborne5ed1992016-10-10 16:35:45 -070077 return -EPERM;
78 }
Dianne Hackborn228f2f62017-11-14 11:18:08 -080079#if DEBUG
Tomasz Wasilczyk95000d02023-08-23 18:40:27 +000080 ALOGD("openFile: %s, full=%s", path8.c_str(), fullPath.c_str());
Dianne Hackborn228f2f62017-11-14 11:18:08 -080081#endif
Dianne Hackborn4217f8e2017-10-30 14:31:41 -070082 int flags = 0;
83 bool checkRead = false;
84 bool checkWrite = false;
Alex Buynytskyya39d87a2018-12-12 17:40:52 -080085 if (mode == u"w") {
Dianne Hackborn4217f8e2017-10-30 14:31:41 -070086 flags = O_WRONLY|O_CREAT|O_TRUNC;
87 checkWrite = true;
Alex Buynytskyya39d87a2018-12-12 17:40:52 -080088 } else if (mode == u"w+") {
Dianne Hackborn4217f8e2017-10-30 14:31:41 -070089 flags = O_RDWR|O_CREAT|O_TRUNC;
90 checkRead = checkWrite = true;
Alex Buynytskyya39d87a2018-12-12 17:40:52 -080091 } else if (mode == u"r") {
Dianne Hackborn4217f8e2017-10-30 14:31:41 -070092 flags = O_RDONLY;
93 checkRead = true;
Alex Buynytskyya39d87a2018-12-12 17:40:52 -080094 } else if (mode == u"r+") {
Dianne Hackborn4217f8e2017-10-30 14:31:41 -070095 flags = O_RDWR;
96 checkRead = checkWrite = true;
97 } else {
Ryan Pricharda0cf4ad2024-01-05 18:41:07 -080098 mErrorLog << "Invalid mode requested: " << mode << endl;
Dianne Hackborn4217f8e2017-10-30 14:31:41 -070099 return -EINVAL;
100 }
Tomasz Wasilczyk95000d02023-08-23 18:40:27 +0000101 int fd = open(fullPath.c_str(), flags, S_IRWXU|S_IRWXG);
Dianne Hackborn228f2f62017-11-14 11:18:08 -0800102#if DEBUG
103 ALOGD("openFile: fd=%d", fd);
104#endif
Dianne Hackborn1941a402016-08-29 12:30:43 -0700105 if (fd < 0) {
106 return fd;
107 }
108 if (is_selinux_enabled() && seLinuxContext.size() > 0) {
109 String8 seLinuxContext8(seLinuxContext);
ThiƩbaud Weksteen146ed6e2021-09-15 20:06:13 +0200110 char* tmp = nullptr;
Tomasz Wasilczyk95000d02023-08-23 18:40:27 +0000111 getfilecon(fullPath.c_str(), &tmp);
Dianne Hackborn1941a402016-08-29 12:30:43 -0700112 Unique_SecurityContext context(tmp);
Dianne Hackborn4217f8e2017-10-30 14:31:41 -0700113 if (checkWrite) {
Tomasz Wasilczyk95000d02023-08-23 18:40:27 +0000114 int accessGranted = selinux_check_access(seLinuxContext8.c_str(), context.get(),
Alex Buynytskyy4ad5b4b2018-12-19 08:21:24 -0800115 "file", "write", nullptr);
Dianne Hackborn4217f8e2017-10-30 14:31:41 -0700116 if (accessGranted != 0) {
Dianne Hackborn228f2f62017-11-14 11:18:08 -0800117#if DEBUG
118 ALOGD("openFile: failed selinux write check!");
119#endif
Dianne Hackborn4217f8e2017-10-30 14:31:41 -0700120 close(fd);
Tomasz Wasilczyk95000d02023-08-23 18:40:27 +0000121 mErrorLog << "System server has no access to write file context " << context.get() << " (from path " << fullPath.c_str() << ", context " << seLinuxContext8.c_str() << ")" << endl;
Dianne Hackborn4217f8e2017-10-30 14:31:41 -0700122 return -EPERM;
123 }
124 }
125 if (checkRead) {
Tomasz Wasilczyk95000d02023-08-23 18:40:27 +0000126 int accessGranted = selinux_check_access(seLinuxContext8.c_str(), context.get(),
Alex Buynytskyy4ad5b4b2018-12-19 08:21:24 -0800127 "file", "read", nullptr);
Dianne Hackborn4217f8e2017-10-30 14:31:41 -0700128 if (accessGranted != 0) {
Dianne Hackborn228f2f62017-11-14 11:18:08 -0800129#if DEBUG
130 ALOGD("openFile: failed selinux read check!");
131#endif
Dianne Hackborn4217f8e2017-10-30 14:31:41 -0700132 close(fd);
Tomasz Wasilczyk95000d02023-08-23 18:40:27 +0000133 mErrorLog << "System server has no access to read file context " << context.get() << " (from path " << fullPath.c_str() << ", context " << seLinuxContext8.c_str() << ")" << endl;
Dianne Hackborn4217f8e2017-10-30 14:31:41 -0700134 return -EPERM;
135 }
Dianne Hackborn1941a402016-08-29 12:30:43 -0700136 }
137 }
138 return fd;
139 }
140};
141
Dianne Hackborn23eb1e22015-10-07 17:35:27 -0700142class MyResultReceiver : public BnResultReceiver
143{
144public:
Dianne Hackborn3d9eb952016-10-17 17:40:47 -0700145 Mutex mMutex;
146 Condition mCondition;
147 bool mHaveResult = false;
148 int32_t mResult = 0;
149
150 virtual void send(int32_t resultCode) {
151 AutoMutex _l(mMutex);
152 mResult = resultCode;
153 mHaveResult = true;
154 mCondition.signal();
155 }
156
157 int32_t waitForResult() {
158 AutoMutex _l(mMutex);
159 while (!mHaveResult) {
160 mCondition.wait(mMutex);
161 }
162 return mResult;
Dianne Hackborn23eb1e22015-10-07 17:35:27 -0700163 }
164};
165
Alex Buynytskyya39d87a2018-12-12 17:40:52 -0800166int cmdMain(const std::vector<std::string_view>& argv, TextOutput& outputLog, TextOutput& errorLog,
167 int in, int out, int err, RunMode runMode) {
Dianne Hackborn23eb1e22015-10-07 17:35:27 -0700168 sp<ProcessState> proc = ProcessState::self();
169 proc->startThreadPool();
170
Dianne Hackborn228f2f62017-11-14 11:18:08 -0800171#if DEBUG
172 ALOGD("cmd: starting");
173#endif
Dianne Hackborn23eb1e22015-10-07 17:35:27 -0700174 sp<IServiceManager> sm = defaultServiceManager();
Alex Buynytskyya39d87a2018-12-12 17:40:52 -0800175 if (runMode == RunMode::kStandalone) {
176 fflush(stdout);
177 }
Alex Buynytskyy4ad5b4b2018-12-19 08:21:24 -0800178 if (sm == nullptr) {
Dianne Hackborn3d9eb952016-10-17 17:40:47 -0700179 ALOGW("Unable to get default service manager!");
Alex Buynytskyya39d87a2018-12-12 17:40:52 -0800180 errorLog << "cmd: Unable to get default service manager!" << endl;
Dianne Hackborn23eb1e22015-10-07 17:35:27 -0700181 return 20;
182 }
183
Alex Buynytskyya39d87a2018-12-12 17:40:52 -0800184 int argc = argv.size();
185
186 if (argc == 0) {
Jon Spivacke82eaa82020-02-13 18:10:45 -0800187 errorLog << "cmd: No service specified; use -l to list all running services. Use -w to start and wait for a service." << endl;
Dianne Hackborn23eb1e22015-10-07 17:35:27 -0700188 return 20;
189 }
190
Alex Buynytskyya39d87a2018-12-12 17:40:52 -0800191 if ((argc == 1) && (argv[0] == "-l")) {
Dianne Hackborn23eb1e22015-10-07 17:35:27 -0700192 Vector<String16> services = sm->listServices();
193 services.sort(sort_func);
Alex Buynytskyya39d87a2018-12-12 17:40:52 -0800194 outputLog << "Currently running services:" << endl;
Dianne Hackborn23eb1e22015-10-07 17:35:27 -0700195
196 for (size_t i=0; i<services.size(); i++) {
197 sp<IBinder> service = sm->checkService(services[i]);
Alex Buynytskyy4ad5b4b2018-12-19 08:21:24 -0800198 if (service != nullptr) {
Alex Buynytskyya39d87a2018-12-12 17:40:52 -0800199 outputLog << " " << services[i] << endl;
Dianne Hackborn23eb1e22015-10-07 17:35:27 -0700200 }
201 }
202 return 0;
203 }
204
Jon Spivacke82eaa82020-02-13 18:10:45 -0800205 bool waitForService = ((argc > 1) && (argv[0] == "-w"));
206 int serviceIdx = (waitForService) ? 1 : 0;
207 const auto cmd = argv[serviceIdx];
Alex Buynytskyya39d87a2018-12-12 17:40:52 -0800208
Dianne Hackborn23eb1e22015-10-07 17:35:27 -0700209 Vector<String16> args;
Alex Buynytskyya39d87a2018-12-12 17:40:52 -0800210 String16 serviceName = String16(cmd.data(), cmd.size());
Jon Spivacke82eaa82020-02-13 18:10:45 -0800211 for (int i = serviceIdx + 1; i < argc; i++) {
Alex Buynytskyya39d87a2018-12-12 17:40:52 -0800212 args.add(String16(argv[i].data(), argv[i].size()));
Dianne Hackborn23eb1e22015-10-07 17:35:27 -0700213 }
Jon Spivacke82eaa82020-02-13 18:10:45 -0800214 sp<IBinder> service;
215 if(waitForService) {
216 service = sm->waitForService(serviceName);
217 } else {
218 service = sm->checkService(serviceName);
219 }
220
Alex Buynytskyy4ad5b4b2018-12-19 08:21:24 -0800221 if (service == nullptr) {
Alex Buynytskyya39d87a2018-12-12 17:40:52 -0800222 if (runMode == RunMode::kStandalone) {
223 ALOGW("Can't find service %.*s", static_cast<int>(cmd.size()), cmd.data());
224 }
225 errorLog << "cmd: Can't find service: " << cmd << endl;
Dianne Hackborn23eb1e22015-10-07 17:35:27 -0700226 return 20;
227 }
228
Alex Buynytskyya39d87a2018-12-12 17:40:52 -0800229 sp<MyShellCallback> cb = new MyShellCallback(errorLog);
Dianne Hackborn3d9eb952016-10-17 17:40:47 -0700230 sp<MyResultReceiver> result = new MyResultReceiver();
231
232#if DEBUG
Dominic Lemire3abc51c2020-01-23 12:24:36 -0800233 ALOGD("cmd: Invoking %.*s in=%d, out=%d, err=%d",
234 static_cast<int>(cmd.size()), cmd.data(), in, out, err);
Dianne Hackborn3d9eb952016-10-17 17:40:47 -0700235#endif
Dianne Hackborne5ed1992016-10-10 16:35:45 -0700236
Dianne Hackborn23eb1e22015-10-07 17:35:27 -0700237 // TODO: block until a result is returned to MyResultReceiver.
Alex Buynytskyya39d87a2018-12-12 17:40:52 -0800238 status_t error = IBinder::shellCommand(service, in, out, err, args, cb, result);
239 if (error < 0) {
Dianne Hackborn3d9eb952016-10-17 17:40:47 -0700240 const char* errstr;
Alex Buynytskyya39d87a2018-12-12 17:40:52 -0800241 switch (error) {
Dianne Hackborn3d9eb952016-10-17 17:40:47 -0700242 case BAD_TYPE: errstr = "Bad type"; break;
243 case FAILED_TRANSACTION: errstr = "Failed transaction"; break;
244 case FDS_NOT_ALLOWED: errstr = "File descriptors not allowed"; break;
245 case UNEXPECTED_NULL: errstr = "Unexpected null"; break;
Alex Buynytskyya39d87a2018-12-12 17:40:52 -0800246 default: errstr = strerror(-error); break;
Dianne Hackborn3d9eb952016-10-17 17:40:47 -0700247 }
Alex Buynytskyya39d87a2018-12-12 17:40:52 -0800248 if (runMode == RunMode::kStandalone) {
249 ALOGW("Failure calling service %.*s: %s (%d)", static_cast<int>(cmd.size()), cmd.data(),
250 errstr, -error);
251 }
252 outputLog << "cmd: Failure calling service " << cmd << ": " << errstr << " (" << (-error)
253 << ")" << endl;
254 return error;
Dianne Hackborn3d9eb952016-10-17 17:40:47 -0700255 }
Dianne Hackborne5ed1992016-10-10 16:35:45 -0700256
257 cb->mActive = false;
Dianne Hackborn3d9eb952016-10-17 17:40:47 -0700258 status_t res = result->waitForResult();
259#if DEBUG
260 ALOGD("result=%d", (int)res);
261#endif
262 return res;
Dianne Hackborn23eb1e22015-10-07 17:35:27 -0700263}