selinux: do not check open permission on sockets
authorStephen Smalley <sds@tycho.nsa.gov>
Fri, 12 May 2017 16:41:24 +0000 (12:41 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 13 Apr 2018 17:50:10 +0000 (19:50 +0200)
[ Upstream commit ccb544781d34afdb73a9a73ae53035d824d193bf ]

open permission is currently only defined for files in the kernel
(COMMON_FILE_PERMS rather than COMMON_FILE_SOCK_PERMS). Construction of
an artificial test case that tries to open a socket via /proc/pid/fd will
generate a recvfrom avc denial because recvfrom and open happen to map to
the same permission bit in socket vs file classes.

open of a socket via /proc/pid/fd is not supported by the kernel regardless
and will ultimately return ENXIO. But we hit the permission check first and
can thus produce these odd/misleading denials.  Omit the open check when
operating on a socket.

Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
security/selinux/hooks.c

index 4f690ab..99212ff 100644 (file)
@@ -1942,8 +1942,9 @@ static inline u32 file_to_av(struct file *file)
 static inline u32 open_file_to_av(struct file *file)
 {
        u32 av = file_to_av(file);
+       struct inode *inode = file_inode(file);
 
-       if (selinux_policycap_openperm)
+       if (selinux_policycap_openperm && inode->i_sb->s_magic != SOCKFS_MAGIC)
                av |= FILE__OPEN;
 
        return av;
@@ -2912,6 +2913,7 @@ static int selinux_inode_permission(struct inode *inode, int mask)
 static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
 {
        const struct cred *cred = current_cred();
+       struct inode *inode = d_backing_inode(dentry);
        unsigned int ia_valid = iattr->ia_valid;
        __u32 av = FILE__WRITE;
 
@@ -2927,8 +2929,10 @@ static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
                        ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET))
                return dentry_has_perm(cred, dentry, FILE__SETATTR);
 
-       if (selinux_policycap_openperm && (ia_valid & ATTR_SIZE)
-                       && !(ia_valid & ATTR_FILE))
+       if (selinux_policycap_openperm &&
+           inode->i_sb->s_magic != SOCKFS_MAGIC &&
+           (ia_valid & ATTR_SIZE) &&
+           !(ia_valid & ATTR_FILE))
                av |= FILE__OPEN;
 
        return dentry_has_perm(cred, dentry, av);