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