]> Pileus Git - ~andy/linux/blobdiff - security/selinux/hooks.c
SELinux: remove inode_has_perm_noadp
[~andy/linux] / security / selinux / hooks.c
index d85b793c9321c5866a2f6bd2ce60cb5aaff42e17..8417a6afaf30c6a82a499deddab24c68b5a52b77 100644 (file)
@@ -1488,20 +1488,6 @@ static int inode_has_perm(const struct cred *cred,
        return avc_has_perm_flags(sid, isec->sid, isec->sclass, perms, adp, flags);
 }
 
-static int inode_has_perm_noadp(const struct cred *cred,
-                               struct inode *inode,
-                               u32 perms,
-                               unsigned flags)
-{
-       struct common_audit_data ad;
-       struct selinux_audit_data sad = {0,};
-
-       COMMON_AUDIT_DATA_INIT(&ad, INODE);
-       ad.u.inode = inode;
-       ad.selinux_audit_data = &sad;
-       return inode_has_perm(cred, inode, perms, &ad, flags);
-}
-
 /* Same as inode_has_perm, but pass explicit audit data containing
    the dentry to help the auditing code to more easily generate the
    pathname if needed. */
@@ -2128,21 +2114,17 @@ static inline void flush_unauthorized_files(const struct cred *cred,
                spin_lock(&tty_files_lock);
                if (!list_empty(&tty->tty_files)) {
                        struct tty_file_private *file_priv;
-                       struct inode *inode;
 
                        /* Revalidate access to controlling tty.
-                          Use inode_has_perm on the tty inode directly rather
+                          Use path_has_perm on the tty path directly rather
                           than using file_has_perm, as this particular open
                           file may belong to another process and we are only
                           interested in the inode-based check here. */
                        file_priv = list_first_entry(&tty->tty_files,
                                                struct tty_file_private, list);
                        file = file_priv->file;
-                       inode = file->f_path.dentry->d_inode;
-                       if (inode_has_perm_noadp(cred, inode,
-                                          FILE__READ | FILE__WRITE, 0)) {
+                       if (path_has_perm(cred, &file->f_path, FILE__READ | FILE__WRITE))
                                drop_tty = 1;
-                       }
                }
                spin_unlock(&tty_files_lock);
                tty_kref_put(tty);
@@ -2684,6 +2666,11 @@ static int selinux_inode_permission(struct inode *inode, int mask)
        u32 perms;
        bool from_access;
        unsigned flags = mask & MAY_NOT_BLOCK;
+       struct inode_security_struct *isec;
+       u32 sid;
+       struct av_decision avd;
+       int rc, rc2;
+       u32 audited, denied;
 
        from_access = mask & MAY_ACCESS;
        mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND);
@@ -2692,6 +2679,23 @@ static int selinux_inode_permission(struct inode *inode, int mask)
        if (!mask)
                return 0;
 
+       validate_creds(cred);
+
+       if (unlikely(IS_PRIVATE(inode)))
+               return 0;
+
+       perms = file_mask_to_av(inode->i_mode, mask);
+
+       sid = cred_sid(cred);
+       isec = inode->i_security;
+
+       rc = avc_has_perm_noaudit(sid, isec->sid, isec->sclass, perms, 0, &avd);
+       audited = avc_audit_required(perms, &avd, rc,
+                                    from_access ? FILE__AUDIT_ACCESS : 0,
+                                    &denied);
+       if (likely(!audited))
+               return rc;
+
        COMMON_AUDIT_DATA_INIT(&ad, INODE);
        ad.selinux_audit_data = &sad;
        ad.u.inode = inode;
@@ -2699,15 +2703,18 @@ static int selinux_inode_permission(struct inode *inode, int mask)
        if (from_access)
                ad.selinux_audit_data->auditdeny |= FILE__AUDIT_ACCESS;
 
-       perms = file_mask_to_av(inode->i_mode, mask);
-
-       return inode_has_perm(cred, inode, perms, &ad, flags);
+       rc2 = slow_avc_audit(sid, isec->sid, isec->sclass, perms,
+                            audited, denied, &ad, flags);
+       if (rc2)
+               return rc2;
+       return rc;
 }
 
 static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
 {
        const struct cred *cred = current_cred();
        unsigned int ia_valid = iattr->ia_valid;
+       __u32 av = FILE__WRITE;
 
        /* ATTR_FORCE is just used for ATTR_KILL_S[UG]ID. */
        if (ia_valid & ATTR_FORCE) {
@@ -2721,7 +2728,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);
 
-       return dentry_has_perm(cred, dentry, FILE__WRITE);
+       if (ia_valid & ATTR_SIZE)
+               av |= FILE__OPEN;
+
+       return dentry_has_perm(cred, dentry, av);
 }
 
 static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
@@ -2788,8 +2798,25 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
 
        rc = security_context_to_sid(value, size, &newsid);
        if (rc == -EINVAL) {
-               if (!capable(CAP_MAC_ADMIN))
+               if (!capable(CAP_MAC_ADMIN)) {
+                       struct audit_buffer *ab;
+                       size_t audit_size;
+                       const char *str;
+
+                       /* We strip a nul only if it is at the end, otherwise the
+                        * context contains a nul and we should audit that */
+                       str = value;
+                       if (str[size - 1] == '\0')
+                               audit_size = size - 1;
+                       else
+                               audit_size = size;
+                       ab = audit_log_start(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR);
+                       audit_log_format(ab, "op=setxattr invalid_context=");
+                       audit_log_n_untrustedstring(ab, value, audit_size);
+                       audit_log_end(ab);
+
                        return rc;
+               }
                rc = security_context_to_sid_force(value, size, &newsid);
        }
        if (rc)
@@ -2969,7 +2996,7 @@ static int selinux_file_permission(struct file *file, int mask)
 
        if (sid == fsec->sid && fsec->isid == isec->sid &&
            fsec->pseqno == avc_policy_seqno())
-               /* No change since dentry_open check. */
+               /* No change since file_open check. */
                return 0;
 
        return selinux_revalidate_file_permission(file, mask);
@@ -3228,15 +3255,13 @@ static int selinux_file_receive(struct file *file)
        return file_has_perm(cred, file, file_to_av(file));
 }
 
-static int selinux_dentry_open(struct file *file, const struct cred *cred)
+static int selinux_file_open(struct file *file, const struct cred *cred)
 {
        struct file_security_struct *fsec;
-       struct inode *inode;
        struct inode_security_struct *isec;
 
-       inode = file->f_path.dentry->d_inode;
        fsec = file->f_security;
-       isec = inode->i_security;
+       isec = file->f_path.dentry->d_inode->i_security;
        /*
         * Save inode label and policy sequence number
         * at open-time so that selinux_file_permission
@@ -3254,7 +3279,7 @@ static int selinux_dentry_open(struct file *file, const struct cred *cred)
         * new inode label or new policy.
         * This check is not redundant - do not remove.
         */
-       return inode_has_perm_noadp(cred, inode, open_file_to_av(file), 0);
+       return path_has_perm(cred, &file->f_path, open_file_to_av(file));
 }
 
 /* task security operations */
@@ -5331,8 +5356,23 @@ static int selinux_setprocattr(struct task_struct *p,
                }
                error = security_context_to_sid(value, size, &sid);
                if (error == -EINVAL && !strcmp(name, "fscreate")) {
-                       if (!capable(CAP_MAC_ADMIN))
+                       if (!capable(CAP_MAC_ADMIN)) {
+                               struct audit_buffer *ab;
+                               size_t audit_size;
+
+                               /* We strip a nul only if it is at the end, otherwise the
+                                * context contains a nul and we should audit that */
+                               if (str[size - 1] == '\0')
+                                       audit_size = size - 1;
+                               else
+                                       audit_size = size;
+                               ab = audit_log_start(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR);
+                               audit_log_format(ab, "op=fscreate invalid_context=");
+                               audit_log_n_untrustedstring(ab, value, audit_size);
+                               audit_log_end(ab);
+
                                return error;
+                       }
                        error = security_context_to_sid_force(value, size,
                                                              &sid);
                }
@@ -5592,7 +5632,7 @@ static struct security_operations selinux_ops = {
        .file_send_sigiotask =          selinux_file_send_sigiotask,
        .file_receive =                 selinux_file_receive,
 
-       .dentry_open =                  selinux_dentry_open,
+       .file_open =                    selinux_file_open,
 
        .task_create =                  selinux_task_create,
        .cred_alloc_blank =             selinux_cred_alloc_blank,