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