2019年12月15日 星期日

Linux LSM security hook flow

 //include/linux/types.h
struct hlist_head {
    struct hlist_node *first;
};

//lsm_hooks.h
struct security_hook_heads {
    struct hlist_head binder_set_context_mgr;
    struct hlist_head binder_transaction;
    struct hlist_head binder_transfer_binder;
    ...
    struct hlist_head secid_to_secctx; // Entry point for the secid_to_secctx linked list
    struct hlist_head file_permission; // Entry point for checking file permissions
    struct hlist_head inode_permission; // Entry point for checking inode permissions
    struct hlist_head task_alloc; // Entry point for checking process creation
    ...
};

//security.c
//declare global variable
struct security_hook_heads security_hook_heads;

//lsm_hooks.h
struct security_hook_list {
    struct hlist_node             list;
    struct hlist_head           *head;
    union security_list_options  hook;
    const char                  *lsm;
};

//selinux/hooks.c
static struct security_hook_list selinux_hooks[] = {
    LSM_HOOK_INIT(binder_set_context_mgr,     selinux_binder_set_context_mgr),
    LSM_HOOK_INIT(binder_transaction,         selinux_binder_transaction),
    LSM_HOOK_INIT(binder_transfer_binder,     selinux_binder_transfer_binder),
    LSM_HOOK_INIT(binder_transfer_file,     selinux_binder_transfer_file),
    ...
    LSM_HOOK_INIT(secid_to_secctx, selinux_secid_to_secctx),
    ...
}

******** selinux_init ********
//include/linux/lsm_hooks.h
#define LSM_HOOK_INIT(HEAD, HOOK) \
    { .head = &security_hook_heads.HEAD, .hook = { .HEAD = HOOK } }

//selinux/hooks.c
//run LSM_HOOK_INIT(secid_to_secctx, selinux_secid_to_secctx)
#define LSM_HOOK_INIT(HEAD, HOOK) \
{ \
    .head = &security_hook_heads.secid_to_secctx, \
    .hook = { .secid_to_secctx = selinux_secid_to_secctx } \
}

selinux_hooks[202] = {
    .head = &security_hook_heads.secid_to_secctx,
    .hook = { .secid_to_secctx = selinux_secid_to_secctx },
    .lsm  = NULL,                           // not yet initialized
    .list = { .next = NULL, .pprev = NULL } // not yet load
};

//selinux/hooks.c
static __init int selinux_init(void) {
    ....
    security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks), "selinux");
    ....
}

//security.c
void __init security_add_hooks(struct security_hook_list *hooks, int count, const char *lsm)
{
    int i;
    for (i = 0; i < count; i++) {
        hooks[i].lsm = lsm;
        hlist_add_tail_rcu(&hooks[i].list, hooks[i].head);
    }
    ...
}

//include/linux/rculist.h
static inline void hlist_add_tail_rcu(struct hlist_node *n,  struct hlist_head *h)
{
    struct hlist_node *i, *last = NULL;

    for (i = h->first; i; i = i->next)
        last = i;

    if (last) {
        n->next = last->next;
        WRITE_ONCE(n->pprev, &last->next);
        rcu_assign_pointer(hlist_next_rcu(last), n);
    } else {
        //hlist_add_head_rcu(n, h);
        struct hlist_node *first = h->first;
        n->next = first;
        WRITE_ONCE(n->pprev, &h->first);
        rcu_assign_pointer(hlist_first_rcu(h), n);
        if (first)
            WRITE_ONCE(first->pprev, &n->next);
    }
}

//after security_add_hooks cause result 1
selinux_hooks[202] = {
    .head = &security_hook_heads.secid_to_secctx,
    .hook = { .secid_to_secctx = selinux_secid_to_secctx },
    .lsm  = "selinux",
    .list = {
        .next = NULL, .pprev = &security_hook_heads.secid_to_secctx.first
    }
};

//security.c
//after security_add_hooks cause result 2
security_hook_heads.secid_to_secctx.first = &selinux_hooks[202].list;

******** get secctx ********
//binder.c
static void binder_transaction(...) {
...
security_secid_to_secctx(secid, &secctx, &secctx_sz);
...
}

//security.c
int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
{
    struct security_hook_list *hp;
    int rc;

    /*hlist_for_each_entry(hp, &security_hook_heads.secid_to_secctx, list) {
        rc = hp->hook.secid_to_secctx(secid, secdata, seclen);
        if (rc != LSM_RET_DEFAULT(secid_to_secctx))
            return rc;
    }*/
    for (hp = hlist_entry_safe((&security_hook_heads.secid_to_secctx)->first, struct security_hook_list, list);
         hp != NULL;
         hp = hlist_entry_safe((hp)->list.next, struct security_hook_list, list))
    {
        rc = hp->hook.secid_to_secctx(secid, secdata, seclen);

        if (rc != LSM_RET_DEFAULT(secid_to_secctx))
            return rc;
    }

    return LSM_RET_DEFAULT(secid_to_secctx);
}

secctx = "u:r:untrusted_app:s0:c164,c512"



沒有留言:

張貼留言