]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/commitdiff
Add security hooks to binder and implement the hooks for SELinux.
authorStephen Smalley <sds@tycho.nsa.gov>
Mon, 5 Nov 2012 13:15:34 +0000 (08:15 -0500)
committerRiley Andrews <riandrews@google.com>
Tue, 13 Jan 2015 22:48:51 +0000 (22:48 +0000)
Add security hooks to the binder and implement the hooks for SELinux.
The security hooks enable security modules such as SELinux to implement
controls over binder IPC.  The security hooks include support for
controlling what process can become the binder context manager
(binder_set_context_mgr), controlling the ability of a process
to invoke a binder transaction/IPC to another process (binder_transaction),
controlling the ability a process to transfer a binder reference to
another process (binder_transfer_binder), and controlling the ability
of a process to transfer an open file to another process (binder_transfer_file).

This support is used by SE Android, http://selinuxproject.org/page/SEAndroid.

Change-Id: I34266b66320b6a3df9ac01833d7f94daf742920e
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
drivers/android/binder.c
include/linux/security.h
security/capability.c
security/security.c
security/selinux/hooks.c
security/selinux/include/classmap.h

index 3d0750780217553a6d09e3fbfdc262ae03098b28..c048624fc6b742a7b35d25c48ea675294cc17771 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/vmalloc.h>
 #include <linux/slab.h>
 #include <linux/pid_namespace.h>
+#include <linux/security.h>
 
 #ifdef CONFIG_ANDROID_BINDER_IPC_32BIT
 #define BINDER_IPC_32BIT 1
@@ -1404,6 +1405,10 @@ static void binder_transaction(struct binder_proc *proc,
                        return_error = BR_DEAD_REPLY;
                        goto err_dead_binder;
                }
+               if (security_binder_transaction(proc->tsk, target_proc->tsk) < 0) {
+                       return_error = BR_FAILED_REPLY;
+                       goto err_invalid_target_handle;
+               }
                if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) {
                        struct binder_transaction *tmp;
 
@@ -1561,6 +1566,10 @@ static void binder_transaction(struct binder_proc *proc,
                                return_error = BR_FAILED_REPLY;
                                goto err_binder_get_ref_for_node_failed;
                        }
+                       if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) {
+                               return_error = BR_FAILED_REPLY;
+                               goto err_binder_get_ref_for_node_failed;
+                       }
                        ref = binder_get_ref_for_node(target_proc, node);
                        if (ref == NULL) {
                                return_error = BR_FAILED_REPLY;
@@ -1591,6 +1600,10 @@ static void binder_transaction(struct binder_proc *proc,
                                return_error = BR_FAILED_REPLY;
                                goto err_binder_get_ref_failed;
                        }
+                       if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) {
+                               return_error = BR_FAILED_REPLY;
+                               goto err_binder_get_ref_failed;
+                       }
                        if (ref->node->proc == target_proc) {
                                if (fp->type == BINDER_TYPE_HANDLE)
                                        fp->type = BINDER_TYPE_BINDER;
@@ -1648,6 +1661,11 @@ static void binder_transaction(struct binder_proc *proc,
                                return_error = BR_FAILED_REPLY;
                                goto err_fget_failed;
                        }
+                       if (security_binder_transfer_file(proc->tsk, target_proc->tsk, file) < 0) {
+                               fput(file);
+                               return_error = BR_FAILED_REPLY;
+                               goto err_get_unused_fd_failed;
+                       }
                        target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC);
                        if (target_fd < 0) {
                                fput(file);
@@ -2685,6 +2703,9 @@ static int binder_ioctl_set_ctx_mgr(struct file *filp)
                ret = -EBUSY;
                goto out;
        }
+       ret = security_binder_set_context_mgr(proc->tsk);
+       if (ret < 0)
+               goto out;
        if (uid_valid(binder_context_mgr_uid)) {
                if (!uid_eq(binder_context_mgr_uid, curr_euid)) {
                        pr_err("BINDER_SET_CONTEXT_MGR bad uid %d != %d\n",
index 4686491852a70b0665633ee1bce5e44d344b3aa3..17e1888ff505c6fd35b08ce7a42d575fa6b553d3 100644 (file)
@@ -1402,6 +1402,11 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
 struct security_operations {
        char name[SECURITY_NAME_MAX + 1];
 
+       int (*binder_set_context_mgr) (struct task_struct *mgr);
+       int (*binder_transaction) (struct task_struct *from, struct task_struct *to);
+       int (*binder_transfer_binder) (struct task_struct *from, struct task_struct *to);
+       int (*binder_transfer_file) (struct task_struct *from, struct task_struct *to, struct file *file);
+
        int (*ptrace_access_check) (struct task_struct *child, unsigned int mode);
        int (*ptrace_traceme) (struct task_struct *parent);
        int (*capget) (struct task_struct *target,
@@ -1690,6 +1695,10 @@ extern void __init security_fixup_ops(struct security_operations *ops);
 
 
 /* Security operations */
+int security_binder_set_context_mgr(struct task_struct *mgr);
+int security_binder_transaction(struct task_struct *from, struct task_struct *to);
+int security_binder_transfer_binder(struct task_struct *from, struct task_struct *to);
+int security_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file);
 int security_ptrace_access_check(struct task_struct *child, unsigned int mode);
 int security_ptrace_traceme(struct task_struct *parent);
 int security_capget(struct task_struct *target,
@@ -1869,6 +1878,26 @@ static inline int security_init(void)
        return 0;
 }
 
+static inline int security_binder_set_context_mgr(struct task_struct *mgr)
+{
+       return 0;
+}
+
+static inline int security_binder_transaction(struct task_struct *from, struct task_struct *to)
+{
+       return 0;
+}
+
+static inline int security_binder_transfer_binder(struct task_struct *from, struct task_struct *to)
+{
+       return 0;
+}
+
+static inline int security_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file)
+{
+       return 0;
+}
+
 static inline int security_ptrace_access_check(struct task_struct *child,
                                             unsigned int mode)
 {
index 1728d4e375db509c4e192e0e69fb1a0ee020bf49..6e4fc776badf16cf568adcd88386d1fcfeacb8aa 100644 (file)
 
 #include <linux/security.h>
 
+static int cap_binder_set_context_mgr(struct task_struct *mgr)
+{
+       return 0;
+}
+
+static int cap_binder_transaction(struct task_struct *from, struct task_struct *to)
+{
+       return 0;
+}
+
+static int cap_binder_transfer_binder(struct task_struct *from, struct task_struct *to)
+{
+       return 0;
+}
+
+static int cap_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file)
+{
+       return 0;
+}
+
 static int cap_syslog(int type)
 {
        return 0;
@@ -903,6 +923,10 @@ static void cap_audit_rule_free(void *lsmrule)
 
 void __init security_fixup_ops(struct security_operations *ops)
 {
+       set_to_cap_if_null(ops, binder_set_context_mgr);
+       set_to_cap_if_null(ops, binder_transaction);
+       set_to_cap_if_null(ops, binder_transfer_binder);
+       set_to_cap_if_null(ops, binder_transfer_file);
        set_to_cap_if_null(ops, ptrace_access_check);
        set_to_cap_if_null(ops, ptrace_traceme);
        set_to_cap_if_null(ops, capget);
index a3dce87d1aeffccb92181631ef2687baec41d36c..d6ab2d2b363dace7394b060a2a64646762dc0d1f 100644 (file)
@@ -134,6 +134,26 @@ int __init register_security(struct security_operations *ops)
 
 /* Security operations */
 
+int security_binder_set_context_mgr(struct task_struct *mgr)
+{
+       return security_ops->binder_set_context_mgr(mgr);
+}
+
+int security_binder_transaction(struct task_struct *from, struct task_struct *to)
+{
+       return security_ops->binder_transaction(from, to);
+}
+
+int security_binder_transfer_binder(struct task_struct *from, struct task_struct *to)
+{
+       return security_ops->binder_transfer_binder(from, to);
+}
+
+int security_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file)
+{
+       return security_ops->binder_transfer_file(from, to, file);
+}
+
 int security_ptrace_access_check(struct task_struct *child, unsigned int mode)
 {
 #ifdef CONFIG_SECURITY_YAMA_STACKED
index 8908c367425b834cc8651c869fb8ac4b2db58d3f..a8de30bd733a5cc2d2043e234fbf0ba360d7282f 100644 (file)
@@ -1844,6 +1844,67 @@ static inline u32 open_file_to_av(struct file *file)
 
 /* Hook functions begin here. */
 
+static int selinux_binder_set_context_mgr(struct task_struct *mgr)
+{
+       u32 mysid = current_sid();
+       u32 mgrsid = task_sid(mgr);
+
+       return avc_has_perm(mysid, mgrsid, SECCLASS_BINDER, BINDER__SET_CONTEXT_MGR, NULL);
+}
+
+static int selinux_binder_transaction(struct task_struct *from, struct task_struct *to)
+{
+       u32 mysid = current_sid();
+       u32 fromsid = task_sid(from);
+       u32 tosid = task_sid(to);
+       int rc;
+
+       if (mysid != fromsid) {
+               rc = avc_has_perm(mysid, fromsid, SECCLASS_BINDER, BINDER__IMPERSONATE, NULL);
+               if (rc)
+                       return rc;
+       }
+
+       return avc_has_perm(fromsid, tosid, SECCLASS_BINDER, BINDER__CALL, NULL);
+}
+
+static int selinux_binder_transfer_binder(struct task_struct *from, struct task_struct *to)
+{
+       u32 fromsid = task_sid(from);
+       u32 tosid = task_sid(to);
+       return avc_has_perm(fromsid, tosid, SECCLASS_BINDER, BINDER__TRANSFER, NULL);
+}
+
+static int selinux_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file)
+{
+       u32 sid = task_sid(to);
+       struct file_security_struct *fsec = file->f_security;
+       struct inode *inode = file->f_path.dentry->d_inode;
+       struct inode_security_struct *isec = inode->i_security;
+       struct common_audit_data ad;
+       struct selinux_audit_data sad = {0,};
+       int rc;
+
+       ad.type = LSM_AUDIT_DATA_PATH;
+       ad.u.path = file->f_path;
+       ad.selinux_audit_data = &sad;
+
+       if (sid != fsec->sid) {
+               rc = avc_has_perm(sid, fsec->sid,
+                                 SECCLASS_FD,
+                                 FD__USE,
+                                 &ad);
+               if (rc)
+                       return rc;
+       }
+
+       if (unlikely(IS_PRIVATE(inode)))
+               return 0;
+
+       return avc_has_perm(sid, isec->sid, isec->sclass, file_to_av(file),
+                           &ad);
+}
+
 static int selinux_ptrace_access_check(struct task_struct *child,
                                     unsigned int mode)
 {
@@ -5556,6 +5617,11 @@ static int selinux_key_getsecurity(struct key *key, char **_buffer)
 static struct security_operations selinux_ops = {
        .name =                         "selinux",
 
+       .binder_set_context_mgr =       selinux_binder_set_context_mgr,
+       .binder_transaction =           selinux_binder_transaction,
+       .binder_transfer_binder =       selinux_binder_transfer_binder,
+       .binder_transfer_file =         selinux_binder_transfer_file,
+
        .ptrace_access_check =          selinux_ptrace_access_check,
        .ptrace_traceme =               selinux_ptrace_traceme,
        .capget =                       selinux_capget,
index 14d04e63b1f0e09ef15b4cf64057bd7cc861ed1d..c32ff7bde81ab97ab85f868661856dca828e3d6e 100644 (file)
@@ -151,5 +151,6 @@ struct security_class_mapping secclass_map[] = {
        { "kernel_service", { "use_as_override", "create_files_as", NULL } },
        { "tun_socket",
          { COMMON_SOCK_PERMS, "attach_queue", NULL } },
+       { "binder", { "impersonate", "call", "set_context_mgr", "transfer", NULL } },
        { NULL }
   };