On Thu, Oct 9, 2014 at 7:48 AM, Stephen Smalley <sds@xxxxxxxxxxxxx> wrote:
There was some earlier discussion of filtering ioctls via SELinux. If
you want to do that in general, this approach won't get you there - it
cannot scale to deal with more than a handful of ioctl commands. If
however you truly only want this control for this particular ioctl
command, see below for comments on the code. Otherwise, if you want to
explore a generic facility for ioctl filtering, I can send you pointers
to the earlier discussions.
That makes sense. I am a bit conflicted. This is my only use-case, but it sounds like regular filtering of ioctl commands would be generally useful. I understand that my current approach would not scale and would lead to an explosion in permissions. So I am weighing the benefits of this particular permission which seems broadly useful with the risk of either waiting on a general approach or the risk of implementing something that doesn't get mainlined. I would appreciate your thoughts on this. Can you point me towards the earlier discussions?
You can't safely call file_has_perm() with a SOCKET permission as the
file may reference an object with a non-socket security class. So for
example, if a process called ioctl with this command value on a file,
you'd end up getting a very different permission check - whatever that
permission bit corresponds to in the file security class (I guess
nothing at this point, but could potentially be filled in the future).
So I think you need to first check that the file represents a socket
before performing the second check. The other alternative would be to
define the permission in COMMON_FILE_SOCK_PERMS so that it is defined
for all objects that can be presented by struct file, but that would
waste a permission bit for the file classes.
For the first option, something along the lines of:
struct inode *inode = file->f_path.dentry->d_inode;
struct socket *socket;
if (inode->i_sb->s_magic != SOCKFS_MAGIC)
break;
socket = SOCKET_I(inode);
error = sock_has_perm(current, socket->sk, SOCKET__GET_HWADDR);
break;
Thank you for catching that. Here is the patch updated with your recommendations:
---
security/selinux/hooks.c | 14 ++++++++++++++
security/selinux/include/classmap.h | 2 +-
2 files changed, 15 insertions(+), 1 deletion(-)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 1e1266b..5105341 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -3104,10 +3104,14 @@ static void selinux_file_free_security(struct file *file)
file_free_security(file);
}
+static int sock_has_perm(struct task_struct *task, struct sock *sk, u32 perms);
+
static int selinux_file_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
const struct cred *cred = current_cred();
+ struct inode *inode = file->f_path.dentry->d_inode;
+ struct socket *socket;
int error = 0;
switch (cmd) {
@@ -3142,6 +3146,16 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd,
SECURITY_CAP_AUDIT);
break;
+ case SIOCGIFHWADDR:
+ error = file_has_perm(cred, file, FILE__IOCTL);
+ if (error)
+ break;
+ if (inode->i_sb->s_magic != SOCKFS_MAGIC)
+ break;
+ socket = SOCKET_I(inode);
+ error = sock_has_perm(current, socket->sk, SOCKET__GET_HWADDR);
+ break;
+
/* default case assumes that the command will go
* to the file's ioctl() function.
*/
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
index c32ff7b..306f0d2 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -7,7 +7,7 @@
#define COMMON_SOCK_PERMS COMMON_FILE_SOCK_PERMS, "bind", "connect", \
"listen", "accept", "getopt", "setopt", "shutdown", "recvfrom", \
- "sendto", "recv_msg", "send_msg", "name_bind"
+ "sendto", "recv_msg", "send_msg", "name_bind", "get_hwaddr"
#define COMMON_IPC_PERMS "create", "destroy", "getattr", "setattr", "read", \
"write", "associate", "unix_read", "unix_write"
--
2.1.0.rc2.206.gedb03e5
_______________________________________________ Selinux mailing list Selinux@xxxxxxxxxxxxx To unsubscribe, send email to Selinux-leave@xxxxxxxxxxxxx. To get help, send an email containing "help" to Selinux-request@xxxxxxxxxxxxx.