1/* 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> 24#include <binder/IShellCallback.h> 25#include <binder/TextOutput.h> 26#include <utils/Condition.h> 27#include <utils/Mutex.h> 28#include <utils/Vector.h> 29 30#include <getopt.h> 31#include <stdlib.h> 32#include <stdio.h> 33#include <string.h> 34#include <unistd.h> 35#include <fcntl.h> 36#include <sys/time.h> 37#include <errno.h> 38 39#include "selinux/selinux.h" 40#include "selinux/android.h" 41 42#include <UniquePtr.h> 43 44#define DEBUG 0 45 46using namespace android; 47 48static int sort_func(const String16* lhs, const String16* rhs) 49{ 50 return lhs->compare(*rhs); 51} 52 53struct SecurityContext_Delete { 54 void operator()(security_context_t p) const { 55 freecon(p); 56 } 57}; 58typedef UniquePtr<char[], SecurityContext_Delete> Unique_SecurityContext; 59 60class MyShellCallback : public BnShellCallback 61{ 62public: 63 bool mActive = true; 64 65 virtual int openOutputFile(const String16& path, const String16& seLinuxContext) { 66 String8 path8(path); 67 char cwd[256]; 68 getcwd(cwd, 256); 69 String8 fullPath(cwd); 70 fullPath.appendPath(path8); 71 if (!mActive) { 72 aerr << "Open attempt after active for: " << fullPath << endl; 73 return -EPERM; 74 } 75 int fd = open(fullPath.string(), O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU|S_IRWXG); 76 if (fd < 0) { 77 return fd; 78 } 79 if (is_selinux_enabled() && seLinuxContext.size() > 0) { 80 String8 seLinuxContext8(seLinuxContext); 81 security_context_t tmp = NULL; 82 int ret = getfilecon(fullPath.string(), &tmp); 83 Unique_SecurityContext context(tmp); 84 int accessGranted = selinux_check_access(seLinuxContext8.string(), context.get(), 85 "file", "write", NULL); 86 if (accessGranted != 0) { 87 close(fd); 88 aerr << "System server has no access to file context " << context.get() 89 << " (from path " << fullPath.string() << ", context " 90 << seLinuxContext8.string() << ")" << endl; 91 return -EPERM; 92 } 93 } 94 return fd; 95 } 96}; 97 98class MyResultReceiver : public BnResultReceiver 99{ 100public: 101 Mutex mMutex; 102 Condition mCondition; 103 bool mHaveResult = false; 104 int32_t mResult = 0; 105 106 virtual void send(int32_t resultCode) { 107 AutoMutex _l(mMutex); 108 mResult = resultCode; 109 mHaveResult = true; 110 mCondition.signal(); 111 } 112 113 int32_t waitForResult() { 114 AutoMutex _l(mMutex); 115 while (!mHaveResult) { 116 mCondition.wait(mMutex); 117 } 118 return mResult; 119 } 120}; 121 122int main(int argc, char* const argv[]) 123{ 124 signal(SIGPIPE, SIG_IGN); 125 sp<ProcessState> proc = ProcessState::self(); 126 // setThreadPoolMaxThreadCount(0) actually tells the kernel it's 127 // not allowed to spawn any additional threads, but we still spawn 128 // a binder thread from userspace when we call startThreadPool(). 129 // This is safe because we only have 2 callbacks, neither of which 130 // block. 131 // See b/36066697 for rationale 132 proc->setThreadPoolMaxThreadCount(0); 133 proc->startThreadPool(); 134 135 sp<IServiceManager> sm = defaultServiceManager(); 136 fflush(stdout); 137 if (sm == NULL) { 138 ALOGW("Unable to get default service manager!"); 139 aerr << "cmd: Unable to get default service manager!" << endl; 140 return 20; 141 } 142 143 if (argc == 1) { 144 aerr << "cmd: No service specified; use -l to list all services" << endl; 145 return 20; 146 } 147 148 if ((argc == 2) && (strcmp(argv[1], "-l") == 0)) { 149 Vector<String16> services = sm->listServices(); 150 services.sort(sort_func); 151 aout << "Currently running services:" << endl; 152 153 for (size_t i=0; i<services.size(); i++) { 154 sp<IBinder> service = sm->checkService(services[i]); 155 if (service != NULL) { 156 aout << " " << services[i] << endl; 157 } 158 } 159 return 0; 160 } 161 162 Vector<String16> args; 163 for (int i=2; i<argc; i++) { 164 args.add(String16(argv[i])); 165 } 166 String16 cmd = String16(argv[1]); 167 sp<IBinder> service = sm->checkService(cmd); 168 if (service == NULL) { 169 ALOGW("Can't find service %s", argv[1]); 170 aerr << "cmd: Can't find service: " << argv[1] << endl; 171 return 20; 172 } 173 174 sp<MyShellCallback> cb = new MyShellCallback(); 175 sp<MyResultReceiver> result = new MyResultReceiver(); 176 177#if DEBUG 178 ALOGD("cmd: Invoking %s in=%d, out=%d, err=%d", argv[1], STDIN_FILENO, STDOUT_FILENO, 179 STDERR_FILENO); 180#endif 181 182 // TODO: block until a result is returned to MyResultReceiver. 183 status_t err = IBinder::shellCommand(service, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO, args, 184 cb, result); 185 if (err < 0) { 186 const char* errstr; 187 switch (err) { 188 case BAD_TYPE: errstr = "Bad type"; break; 189 case FAILED_TRANSACTION: errstr = "Failed transaction"; break; 190 case FDS_NOT_ALLOWED: errstr = "File descriptors not allowed"; break; 191 case UNEXPECTED_NULL: errstr = "Unexpected null"; break; 192 default: errstr = strerror(-err); break; 193 } 194 ALOGW("Failure calling service %s: %s (%d)", argv[1], errstr, -err); 195 aout << "cmd: Failure calling service " << argv[1] << ": " << errstr << " (" 196 << (-err) << ")" << endl; 197 return err; 198 } 199 200 cb->mActive = false; 201 status_t res = result->waitForResult(); 202#if DEBUG 203 ALOGD("result=%d", (int)res); 204#endif 205 return res; 206} 207