From 79af73079d753b2d04e46f7445716d3b5f914dbd Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Wed, 21 Jan 2015 10:54:10 -0500 Subject: Add security hooks to binder and implement the hooks for SELinux. 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 of 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). These hooks have been included in the Android kernel trees since Android 4.3. (Updated to reflect upstream relocation and changes to the binder driver, changes to the LSM audit data structures, coding style cleanups, and to add inline documentation for the hooks). Signed-off-by: Stephen Smalley Acked-by: Nick Kralevich Acked-by: Jeffrey Vander Stoep Signed-off-by: Greg Kroah-Hartman --- security/selinux/hooks.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) (limited to 'security/selinux/hooks.c') diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 6da7532893a1..9d984bfb978b 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1933,6 +1933,74 @@ 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; + int rc; + + ad.type = LSM_AUDIT_DATA_PATH; + ad.u.path = file->f_path; + + 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) { @@ -5810,6 +5878,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, -- cgit v1.2.3 From 2088d60e3b2f53d0c9590a0202eeff85b288b1eb Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Wed, 4 Feb 2015 11:34:30 -0500 Subject: selinux: quiet the filesystem labeling behavior message While the filesystem labeling method is only printed at the KERN_DEBUG level, this still appears in dmesg and on modern Linux distributions that create a lot of tmpfs mounts for session handling, the dmesg can easily be filled with a lot of "SELinux: initialized (dev X ..." messages. This patch removes this notification for the normal case but leaves the error message intact (displayed when mounting a filesystem with an unknown labeling behavior). Reported-by: Dave Jones Signed-off-by: Paul Moore --- security/selinux/hooks.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'security/selinux/hooks.c') diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 6da7532893a1..c253caa90bb4 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -456,10 +456,6 @@ static int sb_finish_set_opts(struct super_block *sb) if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors)) printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n", sb->s_id, sb->s_type->name); - else - printk(KERN_DEBUG "SELinux: initialized (dev %s, type %s), %s\n", - sb->s_id, sb->s_type->name, - labeling_behaviors[sbsec->behavior-1]); sbsec->flags |= SE_SBINITIALIZED; if (selinux_is_sblabel_mnt(sb)) -- cgit v1.2.3 From d5f3a5f6e7e7822df5680d4fe39bf0b6979a1535 Mon Sep 17 00:00:00 2001 From: Mark Salyzyn Date: Wed, 4 Feb 2015 11:34:30 -0500 Subject: selinux: add security in-core xattr support for pstore and debugfs - add "pstore" and "debugfs" to list of in-core exceptions - change fstype checks to boolean equation - change from strncmp to strcmp for checking Signed-off-by: Mark Salyzyn Acked-by: Stephen Smalley [PM: tweaked the subject line prefix to "selinux"] Signed-off-by: Paul Moore --- security/selinux/hooks.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) (limited to 'security/selinux/hooks.c') diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index c253caa90bb4..87a915656eab 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -401,23 +401,14 @@ static int selinux_is_sblabel_mnt(struct super_block *sb) { struct superblock_security_struct *sbsec = sb->s_security; - if (sbsec->behavior == SECURITY_FS_USE_XATTR || - sbsec->behavior == SECURITY_FS_USE_TRANS || - sbsec->behavior == SECURITY_FS_USE_TASK) - return 1; - - /* Special handling for sysfs. Is genfs but also has setxattr handler*/ - if (strncmp(sb->s_type->name, "sysfs", sizeof("sysfs")) == 0) - return 1; - - /* - * Special handling for rootfs. Is genfs but supports - * setting SELinux context on in-core inodes. - */ - if (strncmp(sb->s_type->name, "rootfs", sizeof("rootfs")) == 0) - return 1; - - return 0; + return sbsec->behavior == SECURITY_FS_USE_XATTR || + sbsec->behavior == SECURITY_FS_USE_TRANS || + sbsec->behavior == SECURITY_FS_USE_TASK || + /* Special handling. Genfs but also in-core setxattr handler */ + !strcmp(sb->s_type->name, "sysfs") || + !strcmp(sb->s_type->name, "pstore") || + !strcmp(sb->s_type->name, "debugfs") || + !strcmp(sb->s_type->name, "rootfs"); } static int sb_finish_set_opts(struct super_block *sb) -- cgit v1.2.3 From 2c616d4d88de1dc5b1545eefdc2e291eeb9f2e9d Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 29 Jan 2015 12:02:33 +0000 Subject: SELinux: Use d_is_positive() rather than testing dentry->d_inode Use d_is_positive() rather than testing dentry->d_inode in SELinux to get rid of direct references to d_inode outside of the VFS. Signed-off-by: David Howells Signed-off-by: Al Viro --- security/selinux/hooks.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'security/selinux/hooks.c') diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 29c39e0b03ed..79f2c2cb68ad 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1822,12 +1822,12 @@ static inline int may_rename(struct inode *old_dir, ad.u.dentry = new_dentry; av = DIR__ADD_NAME | DIR__SEARCH; - if (new_dentry->d_inode) + if (d_is_positive(new_dentry)) av |= DIR__REMOVE_NAME; rc = avc_has_perm(sid, new_dsec->sid, SECCLASS_DIR, av, &ad); if (rc) return rc; - if (new_dentry->d_inode) { + if (d_is_positive(new_dentry)) { new_isec = new_dentry->d_inode->i_security; new_is_dir = S_ISDIR(new_dentry->d_inode->i_mode); rc = avc_has_perm(sid, new_isec->sid, -- cgit v1.2.3 From e36cb0b89ce20b4f8786a57e8a6bc8476f577650 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 29 Jan 2015 12:02:35 +0000 Subject: VFS: (Scripted) Convert S_ISLNK/DIR/REG(dentry->d_inode) to d_is_*(dentry) Convert the following where appropriate: (1) S_ISLNK(dentry->d_inode) to d_is_symlink(dentry). (2) S_ISREG(dentry->d_inode) to d_is_reg(dentry). (3) S_ISDIR(dentry->d_inode) to d_is_dir(dentry). This is actually more complicated than it appears as some calls should be converted to d_can_lookup() instead. The difference is whether the directory in question is a real dir with a ->lookup op or whether it's a fake dir with a ->d_automount op. In some circumstances, we can subsume checks for dentry->d_inode not being NULL into this, provided we the code isn't in a filesystem that expects d_inode to be NULL if the dirent really *is* negative (ie. if we're going to use d_inode() rather than d_backing_inode() to get the inode pointer). Note that the dentry type field may be set to something other than DCACHE_MISS_TYPE when d_inode is NULL in the case of unionmount, where the VFS manages the fall-through from a negative dentry to a lower layer. In such a case, the dentry type of the negative union dentry is set to the same as the type of the lower dentry. However, if you know d_inode is not NULL at the call site, then you can use the d_is_xxx() functions even in a filesystem. There is one further complication: a 0,0 chardev dentry may be labelled DCACHE_WHITEOUT_TYPE rather than DCACHE_SPECIAL_TYPE. Strictly, this was intended for special directory entry types that don't have attached inodes. The following perl+coccinelle script was used: use strict; my @callers; open($fd, 'git grep -l \'S_IS[A-Z].*->d_inode\' |') || die "Can't grep for S_ISDIR and co. callers"; @callers = <$fd>; close($fd); unless (@callers) { print "No matches\n"; exit(0); } my @cocci = ( '@@', 'expression E;', '@@', '', '- S_ISLNK(E->d_inode->i_mode)', '+ d_is_symlink(E)', '', '@@', 'expression E;', '@@', '', '- S_ISDIR(E->d_inode->i_mode)', '+ d_is_dir(E)', '', '@@', 'expression E;', '@@', '', '- S_ISREG(E->d_inode->i_mode)', '+ d_is_reg(E)' ); my $coccifile = "tmp.sp.cocci"; open($fd, ">$coccifile") || die $coccifile; print($fd "$_\n") || die $coccifile foreach (@cocci); close($fd); foreach my $file (@callers) { chomp $file; print "Processing ", $file, "\n"; system("spatch", "--sp-file", $coccifile, $file, "--in-place", "--no-show-diff") == 0 || die "spatch failed"; } [AV: overlayfs parts skipped] Signed-off-by: David Howells Signed-off-by: Al Viro --- security/selinux/hooks.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'security/selinux/hooks.c') diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 79f2c2cb68ad..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, old_dsec = old_dir->i_security; old_isec = old_dentry->d_inode->i_security; - old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode); + old_is_dir = d_is_dir(old_dentry); new_dsec = new_dir->i_security; ad.type = LSM_AUDIT_DATA_DENTRY; @@ -1829,7 +1829,7 @@ static inline int may_rename(struct inode *old_dir, return rc; if (d_is_positive(new_dentry)) { new_isec = new_dentry->d_inode->i_security; - new_is_dir = S_ISDIR(new_dentry->d_inode->i_mode); + new_is_dir = d_is_dir(new_dentry); rc = avc_has_perm(sid, new_isec->sid, new_isec->sclass, (new_is_dir ? DIR__RMDIR : FILE__UNLINK), &ad); -- cgit v1.2.3