service_manager.c revision 1244edcb85811e9e58d9d40fd05f10dd22e497ca
1/* Copyright 2008 The Android Open Source Project
2 */
3
4#include <stdio.h>
5#include <stdlib.h>
6#include <errno.h>
7#include <fcntl.h>
8
9#include <private/android_filesystem_config.h>
10
11#include <selinux/android.h>
12
13#include "binder.h"
14
15#if 0
16#define ALOGI(x...) fprintf(stderr, "svcmgr: " x)
17#define ALOGE(x...) fprintf(stderr, "svcmgr: " x)
18#else
19#define LOG_TAG "ServiceManager"
20#include <cutils/log.h>
21#endif
22
23uint32_t svcmgr_handle;
24
25const char *str8(const uint16_t *x)
26{
27    static char buf[128];
28    unsigned max = 127;
29    char *p = buf;
30
31    if (x) {
32        while (*x && max--) {
33            *p++ = *x++;
34        }
35    }
36    *p++ = 0;
37    return buf;
38}
39
40int str16eq(const uint16_t *a, const char *b)
41{
42    while (*a && *b)
43        if (*a++ != *b++) return 0;
44    if (*a || *b)
45        return 0;
46    return 1;
47}
48
49static struct selabel_handle* sehandle;
50
51static bool check_mac_perms(const char *name, pid_t spid)
52{
53    if (is_selinux_enabled() <= 0) {
54        return true;
55    }
56
57    bool allowed = false;
58
59    const char *class = "service_manager";
60    const char *perm = "add";
61
62    char *tctx = NULL;
63    char *sctx = NULL;
64
65    if (!sehandle) {
66        ALOGE("SELinux: Failed to find sehandle %s.\n", name);
67        return false;
68    }
69
70    if (getpidcon(spid, &sctx) < 0) {
71        ALOGE("SELinux: getpidcon failed to retrieve pid context.\n");
72        return false;
73    }
74
75    if (!sctx) {
76        ALOGE("SELinux: Failed to find sctx for %s.\n", name);
77        return false;
78    }
79
80    if (selabel_lookup(sehandle, &tctx, name, 1) != 0) {
81        ALOGE("SELinux: selabel_lookup failed to set tctx for %s.\n", name);
82        freecon(sctx);
83        return false;
84    }
85
86    if (!tctx) {
87        ALOGE("SELinux: Failed to find tctx for %s.\n", name);
88        freecon(sctx);
89        return false;
90    }
91
92    int result = selinux_check_access(sctx, tctx, class, perm, (void *) name);
93    allowed = (result == 0);
94
95    freecon(sctx);
96    freecon(tctx);
97    return allowed;
98}
99
100static int svc_can_register(uid_t uid, const uint16_t *name, pid_t spid)
101{
102    return check_mac_perms(str8(name), spid) ? 1 : 0;
103}
104
105struct svcinfo
106{
107    struct svcinfo *next;
108    uint32_t handle;
109    struct binder_death death;
110    int allow_isolated;
111    size_t len;
112    uint16_t name[0];
113};
114
115struct svcinfo *svclist = NULL;
116
117struct svcinfo *find_svc(const uint16_t *s16, size_t len)
118{
119    struct svcinfo *si;
120
121    for (si = svclist; si; si = si->next) {
122        if ((len == si->len) &&
123            !memcmp(s16, si->name, len * sizeof(uint16_t))) {
124            return si;
125        }
126    }
127    return NULL;
128}
129
130void svcinfo_death(struct binder_state *bs, void *ptr)
131{
132    struct svcinfo *si = (struct svcinfo* ) ptr;
133
134    ALOGI("service '%s' died\n", str8(si->name));
135    if (si->handle) {
136        binder_release(bs, si->handle);
137        si->handle = 0;
138    }
139}
140
141uint16_t svcmgr_id[] = {
142    'a','n','d','r','o','i','d','.','o','s','.',
143    'I','S','e','r','v','i','c','e','M','a','n','a','g','e','r'
144};
145
146
147uint32_t do_find_service(struct binder_state *bs, const uint16_t *s, size_t len, uid_t uid)
148{
149    struct svcinfo *si;
150
151    si = find_svc(s, len);
152    //ALOGI("check_service('%s') handle = %x\n", str8(s), si ? si->handle : 0);
153    if (si && si->handle) {
154        if (!si->allow_isolated) {
155            // If this service doesn't allow access from isolated processes,
156            // then check the uid to see if it is isolated.
157            uid_t appid = uid % AID_USER;
158            if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) {
159                return 0;
160            }
161        }
162        return si->handle;
163    } else {
164        return 0;
165    }
166}
167
168int do_add_service(struct binder_state *bs,
169                   const uint16_t *s, size_t len,
170                   uint32_t handle, uid_t uid, int allow_isolated,
171                   pid_t spid)
172{
173    struct svcinfo *si;
174
175    //ALOGI("add_service('%s',%x,%s) uid=%d\n", str8(s), handle,
176    //        allow_isolated ? "allow_isolated" : "!allow_isolated", uid);
177
178    if (!handle || (len == 0) || (len > 127))
179        return -1;
180
181    if (!svc_can_register(uid, s, spid)) {
182        ALOGE("add_service('%s',%x) uid=%d - PERMISSION DENIED\n",
183             str8(s), handle, uid);
184        return -1;
185    }
186
187    si = find_svc(s, len);
188    if (si) {
189        if (si->handle) {
190            ALOGE("add_service('%s',%x) uid=%d - ALREADY REGISTERED, OVERRIDE\n",
191                 str8(s), handle, uid);
192            svcinfo_death(bs, si);
193        }
194        si->handle = handle;
195    } else {
196        si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));
197        if (!si) {
198            ALOGE("add_service('%s',%x) uid=%d - OUT OF MEMORY\n",
199                 str8(s), handle, uid);
200            return -1;
201        }
202        si->handle = handle;
203        si->len = len;
204        memcpy(si->name, s, (len + 1) * sizeof(uint16_t));
205        si->name[len] = '\0';
206        si->death.func = (void*) svcinfo_death;
207        si->death.ptr = si;
208        si->allow_isolated = allow_isolated;
209        si->next = svclist;
210        svclist = si;
211    }
212
213    binder_acquire(bs, handle);
214    binder_link_to_death(bs, handle, &si->death);
215    return 0;
216}
217
218int svcmgr_handler(struct binder_state *bs,
219                   struct binder_transaction_data *txn,
220                   struct binder_io *msg,
221                   struct binder_io *reply)
222{
223    struct svcinfo *si;
224    uint16_t *s;
225    size_t len;
226    uint32_t handle;
227    uint32_t strict_policy;
228    int allow_isolated;
229
230    //ALOGI("target=%x code=%d pid=%d uid=%d\n",
231    //  txn->target.handle, txn->code, txn->sender_pid, txn->sender_euid);
232
233    if (txn->target.handle != svcmgr_handle)
234        return -1;
235
236    if (txn->code == PING_TRANSACTION)
237        return 0;
238
239    // Equivalent to Parcel::enforceInterface(), reading the RPC
240    // header with the strict mode policy mask and the interface name.
241    // Note that we ignore the strict_policy and don't propagate it
242    // further (since we do no outbound RPCs anyway).
243    strict_policy = bio_get_uint32(msg);
244    s = bio_get_string16(msg, &len);
245    if ((len != (sizeof(svcmgr_id) / 2)) ||
246        memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {
247        fprintf(stderr,"invalid id %s\n", str8(s));
248        return -1;
249    }
250
251    if (sehandle && selinux_status_updated() > 0) {
252        struct selabel_handle *tmp_sehandle = selinux_android_service_context_handle();
253        if (tmp_sehandle) {
254            selabel_close(sehandle);
255            sehandle = tmp_sehandle;
256        }
257    }
258
259    switch(txn->code) {
260    case SVC_MGR_GET_SERVICE:
261    case SVC_MGR_CHECK_SERVICE:
262        s = bio_get_string16(msg, &len);
263        handle = do_find_service(bs, s, len, txn->sender_euid);
264        if (!handle)
265            break;
266        bio_put_ref(reply, handle);
267        return 0;
268
269    case SVC_MGR_ADD_SERVICE:
270        s = bio_get_string16(msg, &len);
271        handle = bio_get_ref(msg);
272        allow_isolated = bio_get_uint32(msg) ? 1 : 0;
273        if (do_add_service(bs, s, len, handle, txn->sender_euid,
274            allow_isolated, txn->sender_pid))
275            return -1;
276        break;
277
278    case SVC_MGR_LIST_SERVICES: {
279        uint32_t n = bio_get_uint32(msg);
280
281        si = svclist;
282        while ((n-- > 0) && si)
283            si = si->next;
284        if (si) {
285            bio_put_string16(reply, si->name);
286            return 0;
287        }
288        return -1;
289    }
290    default:
291        ALOGE("unknown code %d\n", txn->code);
292        return -1;
293    }
294
295    bio_put_uint32(reply, 0);
296    return 0;
297}
298
299
300static int audit_callback(void *data, security_class_t cls, char *buf, size_t len)
301{
302    snprintf(buf, len, "service=%s", !data ? "NULL" : (char *)data);
303    return 0;
304}
305
306int main(int argc, char **argv)
307{
308    struct binder_state *bs;
309
310    bs = binder_open(128*1024);
311    if (!bs) {
312        ALOGE("failed to open binder driver\n");
313        return -1;
314    }
315
316    if (binder_become_context_manager(bs)) {
317        ALOGE("cannot become context manager (%s)\n", strerror(errno));
318        return -1;
319    }
320
321    sehandle = selinux_android_service_context_handle();
322
323    union selinux_callback cb;
324    cb.func_audit = audit_callback;
325    selinux_set_callback(SELINUX_CB_AUDIT, cb);
326    cb.func_log = selinux_log_callback;
327    selinux_set_callback(SELINUX_CB_LOG, cb);
328
329    svcmgr_handle = BINDER_SERVICE_MANAGER;
330    binder_loop(bs, svcmgr_handler);
331
332    return 0;
333}
334