Home | History | Annotate | Download | only in cmd
      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