diff options
Diffstat (limited to 'security/selinux')
-rw-r--r-- | security/selinux/hooks.c | 81 | ||||
-rw-r--r-- | security/selinux/include/classmap.h | 2 | ||||
-rw-r--r-- | security/selinux/selinuxfs.c | 52 |
3 files changed, 82 insertions, 53 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 87a915656eab..4d1a54190388 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -1799,7 +1799,7 @@ static inline int may_rename(struct inode *old_dir, | |||
1799 | 1799 | ||
1800 | old_dsec = old_dir->i_security; | 1800 | old_dsec = old_dir->i_security; |
1801 | old_isec = old_dentry->d_inode->i_security; | 1801 | old_isec = old_dentry->d_inode->i_security; |
1802 | old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode); | 1802 | old_is_dir = d_is_dir(old_dentry); |
1803 | new_dsec = new_dir->i_security; | 1803 | new_dsec = new_dir->i_security; |
1804 | 1804 | ||
1805 | ad.type = LSM_AUDIT_DATA_DENTRY; | 1805 | ad.type = LSM_AUDIT_DATA_DENTRY; |
@@ -1822,14 +1822,14 @@ static inline int may_rename(struct inode *old_dir, | |||
1822 | 1822 | ||
1823 | ad.u.dentry = new_dentry; | 1823 | ad.u.dentry = new_dentry; |
1824 | av = DIR__ADD_NAME | DIR__SEARCH; | 1824 | av = DIR__ADD_NAME | DIR__SEARCH; |
1825 | if (new_dentry->d_inode) | 1825 | if (d_is_positive(new_dentry)) |
1826 | av |= DIR__REMOVE_NAME; | 1826 | av |= DIR__REMOVE_NAME; |
1827 | rc = avc_has_perm(sid, new_dsec->sid, SECCLASS_DIR, av, &ad); | 1827 | rc = avc_has_perm(sid, new_dsec->sid, SECCLASS_DIR, av, &ad); |
1828 | if (rc) | 1828 | if (rc) |
1829 | return rc; | 1829 | return rc; |
1830 | if (new_dentry->d_inode) { | 1830 | if (d_is_positive(new_dentry)) { |
1831 | new_isec = new_dentry->d_inode->i_security; | 1831 | new_isec = new_dentry->d_inode->i_security; |
1832 | new_is_dir = S_ISDIR(new_dentry->d_inode->i_mode); | 1832 | new_is_dir = d_is_dir(new_dentry); |
1833 | rc = avc_has_perm(sid, new_isec->sid, | 1833 | rc = avc_has_perm(sid, new_isec->sid, |
1834 | new_isec->sclass, | 1834 | new_isec->sclass, |
1835 | (new_is_dir ? DIR__RMDIR : FILE__UNLINK), &ad); | 1835 | (new_is_dir ? DIR__RMDIR : FILE__UNLINK), &ad); |
@@ -1920,6 +1920,74 @@ static inline u32 open_file_to_av(struct file *file) | |||
1920 | 1920 | ||
1921 | /* Hook functions begin here. */ | 1921 | /* Hook functions begin here. */ |
1922 | 1922 | ||
1923 | static int selinux_binder_set_context_mgr(struct task_struct *mgr) | ||
1924 | { | ||
1925 | u32 mysid = current_sid(); | ||
1926 | u32 mgrsid = task_sid(mgr); | ||
1927 | |||
1928 | return avc_has_perm(mysid, mgrsid, SECCLASS_BINDER, | ||
1929 | BINDER__SET_CONTEXT_MGR, NULL); | ||
1930 | } | ||
1931 | |||
1932 | static int selinux_binder_transaction(struct task_struct *from, | ||
1933 | struct task_struct *to) | ||
1934 | { | ||
1935 | u32 mysid = current_sid(); | ||
1936 | u32 fromsid = task_sid(from); | ||
1937 | u32 tosid = task_sid(to); | ||
1938 | int rc; | ||
1939 | |||
1940 | if (mysid != fromsid) { | ||
1941 | rc = avc_has_perm(mysid, fromsid, SECCLASS_BINDER, | ||
1942 | BINDER__IMPERSONATE, NULL); | ||
1943 | if (rc) | ||
1944 | return rc; | ||
1945 | } | ||
1946 | |||
1947 | return avc_has_perm(fromsid, tosid, SECCLASS_BINDER, BINDER__CALL, | ||
1948 | NULL); | ||
1949 | } | ||
1950 | |||
1951 | static int selinux_binder_transfer_binder(struct task_struct *from, | ||
1952 | struct task_struct *to) | ||
1953 | { | ||
1954 | u32 fromsid = task_sid(from); | ||
1955 | u32 tosid = task_sid(to); | ||
1956 | |||
1957 | return avc_has_perm(fromsid, tosid, SECCLASS_BINDER, BINDER__TRANSFER, | ||
1958 | NULL); | ||
1959 | } | ||
1960 | |||
1961 | static int selinux_binder_transfer_file(struct task_struct *from, | ||
1962 | struct task_struct *to, | ||
1963 | struct file *file) | ||
1964 | { | ||
1965 | u32 sid = task_sid(to); | ||
1966 | struct file_security_struct *fsec = file->f_security; | ||
1967 | struct inode *inode = file->f_path.dentry->d_inode; | ||
1968 | struct inode_security_struct *isec = inode->i_security; | ||
1969 | struct common_audit_data ad; | ||
1970 | int rc; | ||
1971 | |||
1972 | ad.type = LSM_AUDIT_DATA_PATH; | ||
1973 | ad.u.path = file->f_path; | ||
1974 | |||
1975 | if (sid != fsec->sid) { | ||
1976 | rc = avc_has_perm(sid, fsec->sid, | ||
1977 | SECCLASS_FD, | ||
1978 | FD__USE, | ||
1979 | &ad); | ||
1980 | if (rc) | ||
1981 | return rc; | ||
1982 | } | ||
1983 | |||
1984 | if (unlikely(IS_PRIVATE(inode))) | ||
1985 | return 0; | ||
1986 | |||
1987 | return avc_has_perm(sid, isec->sid, isec->sclass, file_to_av(file), | ||
1988 | &ad); | ||
1989 | } | ||
1990 | |||
1923 | static int selinux_ptrace_access_check(struct task_struct *child, | 1991 | static int selinux_ptrace_access_check(struct task_struct *child, |
1924 | unsigned int mode) | 1992 | unsigned int mode) |
1925 | { | 1993 | { |
@@ -5797,6 +5865,11 @@ static int selinux_key_getsecurity(struct key *key, char **_buffer) | |||
5797 | static struct security_operations selinux_ops = { | 5865 | static struct security_operations selinux_ops = { |
5798 | .name = "selinux", | 5866 | .name = "selinux", |
5799 | 5867 | ||
5868 | .binder_set_context_mgr = selinux_binder_set_context_mgr, | ||
5869 | .binder_transaction = selinux_binder_transaction, | ||
5870 | .binder_transfer_binder = selinux_binder_transfer_binder, | ||
5871 | .binder_transfer_file = selinux_binder_transfer_file, | ||
5872 | |||
5800 | .ptrace_access_check = selinux_ptrace_access_check, | 5873 | .ptrace_access_check = selinux_ptrace_access_check, |
5801 | .ptrace_traceme = selinux_ptrace_traceme, | 5874 | .ptrace_traceme = selinux_ptrace_traceme, |
5802 | .capget = selinux_capget, | 5875 | .capget = selinux_capget, |
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h index be491a74c1ed..eccd61b3de8a 100644 --- a/security/selinux/include/classmap.h +++ b/security/selinux/include/classmap.h | |||
@@ -151,5 +151,7 @@ struct security_class_mapping secclass_map[] = { | |||
151 | { "kernel_service", { "use_as_override", "create_files_as", NULL } }, | 151 | { "kernel_service", { "use_as_override", "create_files_as", NULL } }, |
152 | { "tun_socket", | 152 | { "tun_socket", |
153 | { COMMON_SOCK_PERMS, "attach_queue", NULL } }, | 153 | { COMMON_SOCK_PERMS, "attach_queue", NULL } }, |
154 | { "binder", { "impersonate", "call", "set_context_mgr", "transfer", | ||
155 | NULL } }, | ||
154 | { NULL } | 156 | { NULL } |
155 | }; | 157 | }; |
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 138949a31eab..5fde34326dcf 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c | |||
@@ -1195,30 +1195,8 @@ static const struct file_operations sel_commit_bools_ops = { | |||
1195 | 1195 | ||
1196 | static void sel_remove_entries(struct dentry *de) | 1196 | static void sel_remove_entries(struct dentry *de) |
1197 | { | 1197 | { |
1198 | struct list_head *node; | 1198 | d_genocide(de); |
1199 | 1199 | shrink_dcache_parent(de); | |
1200 | spin_lock(&de->d_lock); | ||
1201 | node = de->d_subdirs.next; | ||
1202 | while (node != &de->d_subdirs) { | ||
1203 | struct dentry *d = list_entry(node, struct dentry, d_child); | ||
1204 | |||
1205 | spin_lock_nested(&d->d_lock, DENTRY_D_LOCK_NESTED); | ||
1206 | list_del_init(node); | ||
1207 | |||
1208 | if (d->d_inode) { | ||
1209 | dget_dlock(d); | ||
1210 | spin_unlock(&de->d_lock); | ||
1211 | spin_unlock(&d->d_lock); | ||
1212 | d_delete(d); | ||
1213 | simple_unlink(de->d_inode, d); | ||
1214 | dput(d); | ||
1215 | spin_lock(&de->d_lock); | ||
1216 | } else | ||
1217 | spin_unlock(&d->d_lock); | ||
1218 | node = de->d_subdirs.next; | ||
1219 | } | ||
1220 | |||
1221 | spin_unlock(&de->d_lock); | ||
1222 | } | 1200 | } |
1223 | 1201 | ||
1224 | #define BOOL_DIR_NAME "booleans" | 1202 | #define BOOL_DIR_NAME "booleans" |
@@ -1668,37 +1646,13 @@ static int sel_make_class_dir_entries(char *classname, int index, | |||
1668 | return rc; | 1646 | return rc; |
1669 | } | 1647 | } |
1670 | 1648 | ||
1671 | static void sel_remove_classes(void) | ||
1672 | { | ||
1673 | struct list_head *class_node; | ||
1674 | |||
1675 | list_for_each(class_node, &class_dir->d_subdirs) { | ||
1676 | struct dentry *class_subdir = list_entry(class_node, | ||
1677 | struct dentry, d_child); | ||
1678 | struct list_head *class_subdir_node; | ||
1679 | |||
1680 | list_for_each(class_subdir_node, &class_subdir->d_subdirs) { | ||
1681 | struct dentry *d = list_entry(class_subdir_node, | ||
1682 | struct dentry, d_child); | ||
1683 | |||
1684 | if (d->d_inode) | ||
1685 | if (d->d_inode->i_mode & S_IFDIR) | ||
1686 | sel_remove_entries(d); | ||
1687 | } | ||
1688 | |||
1689 | sel_remove_entries(class_subdir); | ||
1690 | } | ||
1691 | |||
1692 | sel_remove_entries(class_dir); | ||
1693 | } | ||
1694 | |||
1695 | static int sel_make_classes(void) | 1649 | static int sel_make_classes(void) |
1696 | { | 1650 | { |
1697 | int rc, nclasses, i; | 1651 | int rc, nclasses, i; |
1698 | char **classes; | 1652 | char **classes; |
1699 | 1653 | ||
1700 | /* delete any existing entries */ | 1654 | /* delete any existing entries */ |
1701 | sel_remove_classes(); | 1655 | sel_remove_entries(class_dir); |
1702 | 1656 | ||
1703 | rc = security_get_classes(&classes, &nclasses); | 1657 | rc = security_get_classes(&classes, &nclasses); |
1704 | if (rc) | 1658 | if (rc) |