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