]> Pileus Git - ~andy/linux/blobdiff - security/selinux/hooks.c
LSM: do not initialize common_audit_data to 0
[~andy/linux] / security / selinux / hooks.c
index dc15f16a357cf4d561793430eac1cae36dc6f402..d9fa2489a55167ae4d90b00c2ceb21a602aa5b0c 100644 (file)
@@ -1427,9 +1427,8 @@ static int cred_has_capability(const struct cred *cred,
        u32 av = CAP_TO_MASK(cap);
        int rc;
 
-       COMMON_AUDIT_DATA_INIT(&ad, CAP);
+       ad.type = LSM_AUDIT_DATA_CAP;
        ad.selinux_audit_data = &sad;
-       ad.tsk = current;
        ad.u.cap = cap;
 
        switch (CAP_TO_INDEX(cap)) {
@@ -1488,20 +1487,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. */
@@ -1513,7 +1498,7 @@ static inline int dentry_has_perm(const struct cred *cred,
        struct common_audit_data ad;
        struct selinux_audit_data sad = {0,};
 
-       COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
+       ad.type = LSM_AUDIT_DATA_DENTRY;
        ad.u.dentry = dentry;
        ad.selinux_audit_data = &sad;
        return inode_has_perm(cred, inode, av, &ad, 0);
@@ -1530,7 +1515,7 @@ static inline int path_has_perm(const struct cred *cred,
        struct common_audit_data ad;
        struct selinux_audit_data sad = {0,};
 
-       COMMON_AUDIT_DATA_INIT(&ad, PATH);
+       ad.type = LSM_AUDIT_DATA_PATH;
        ad.u.path = *path;
        ad.selinux_audit_data = &sad;
        return inode_has_perm(cred, inode, av, &ad, 0);
@@ -1555,7 +1540,7 @@ static int file_has_perm(const struct cred *cred,
        u32 sid = cred_sid(cred);
        int rc;
 
-       COMMON_AUDIT_DATA_INIT(&ad, PATH);
+       ad.type = LSM_AUDIT_DATA_PATH;
        ad.u.path = file->f_path;
        ad.selinux_audit_data = &sad;
 
@@ -1596,7 +1581,7 @@ static int may_create(struct inode *dir,
        sid = tsec->sid;
        newsid = tsec->create_sid;
 
-       COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
+       ad.type = LSM_AUDIT_DATA_DENTRY;
        ad.u.dentry = dentry;
        ad.selinux_audit_data = &sad;
 
@@ -1651,7 +1636,7 @@ static int may_link(struct inode *dir,
        dsec = dir->i_security;
        isec = dentry->d_inode->i_security;
 
-       COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
+       ad.type = LSM_AUDIT_DATA_DENTRY;
        ad.u.dentry = dentry;
        ad.selinux_audit_data = &sad;
 
@@ -1699,7 +1684,7 @@ static inline int may_rename(struct inode *old_dir,
        old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
        new_dsec = new_dir->i_security;
 
-       COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
+       ad.type = LSM_AUDIT_DATA_DENTRY;
        ad.selinux_audit_data = &sad;
 
        ad.u.dentry = old_dentry;
@@ -2025,7 +2010,7 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
                        return rc;
        }
 
-       COMMON_AUDIT_DATA_INIT(&ad, PATH);
+       ad.type = LSM_AUDIT_DATA_PATH;
        ad.selinux_audit_data = &sad;
        ad.u.path = bprm->file->f_path;
 
@@ -2128,21 +2113,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);
@@ -2153,7 +2134,7 @@ static inline void flush_unauthorized_files(const struct cred *cred,
 
        /* Revalidate access to inherited open files. */
 
-       COMMON_AUDIT_DATA_INIT(&ad, INODE);
+       ad.type = LSM_AUDIT_DATA_INODE;
        ad.selinux_audit_data = &sad;
 
        spin_lock(&files->file_lock);
@@ -2503,7 +2484,7 @@ static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data)
        if (flags & MS_KERNMOUNT)
                return 0;
 
-       COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
+       ad.type = LSM_AUDIT_DATA_DENTRY;
        ad.selinux_audit_data = &sad;
        ad.u.dentry = sb->s_root;
        return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad);
@@ -2515,7 +2496,7 @@ static int selinux_sb_statfs(struct dentry *dentry)
        struct common_audit_data ad;
        struct selinux_audit_data sad = {0,};
 
-       COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
+       ad.type = LSM_AUDIT_DATA_DENTRY;
        ad.selinux_audit_data = &sad;
        ad.u.dentry = dentry->d_sb->s_root;
        return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
@@ -2676,14 +2657,37 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *na
        return dentry_has_perm(cred, dentry, FILE__READ);
 }
 
-static int selinux_inode_permission(struct inode *inode, int mask)
+static noinline int audit_inode_permission(struct inode *inode,
+                                          u32 perms, u32 audited, u32 denied,
+                                          unsigned flags)
 {
-       const struct cred *cred = current_cred();
        struct common_audit_data ad;
        struct selinux_audit_data sad = {0,};
+       struct inode_security_struct *isec = inode->i_security;
+       int rc;
+
+       ad.type = LSM_AUDIT_DATA_INODE;
+       ad.selinux_audit_data = &sad;
+       ad.u.inode = inode;
+
+       rc = slow_avc_audit(current_sid(), isec->sid, isec->sclass, perms,
+                           audited, denied, &ad, flags);
+       if (rc)
+               return rc;
+       return 0;
+}
+
+static int selinux_inode_permission(struct inode *inode, int mask)
+{
+       const struct cred *cred = current_cred();
        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,16 +2696,27 @@ static int selinux_inode_permission(struct inode *inode, int mask)
        if (!mask)
                return 0;
 
-       COMMON_AUDIT_DATA_INIT(&ad, INODE);
-       ad.selinux_audit_data = &sad;
-       ad.u.inode = inode;
+       validate_creds(cred);
 
-       if (from_access)
-               ad.selinux_audit_data->auditdeny |= FILE__AUDIT_ACCESS;
+       if (unlikely(IS_PRIVATE(inode)))
+               return 0;
 
        perms = file_mask_to_av(inode->i_mode, mask);
 
-       return inode_has_perm(cred, inode, perms, &ad, flags);
+       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;
+
+       rc2 = audit_inode_permission(inode, perms, audited, denied, flags);
+       if (rc2)
+               return rc2;
+       return rc;
 }
 
 static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
@@ -2781,7 +2796,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
        if (!inode_owner_or_capable(inode))
                return -EPERM;
 
-       COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
+       ad.type = LSM_AUDIT_DATA_DENTRY;
        ad.selinux_audit_data = &sad;
        ad.u.dentry = dentry;
 
@@ -2792,8 +2807,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)
@@ -3235,12 +3267,10 @@ static int selinux_file_receive(struct file *file)
 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
@@ -3258,7 +3288,7 @@ static int selinux_file_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 */
@@ -3381,7 +3411,7 @@ static int selinux_kernel_module_request(char *kmod_name)
 
        sid = task_sid(current);
 
-       COMMON_AUDIT_DATA_INIT(&ad, KMOD);
+       ad.type = LSM_AUDIT_DATA_KMOD;
        ad.selinux_audit_data = &sad;
        ad.u.kmod_name = kmod_name;
 
@@ -3762,7 +3792,7 @@ static int sock_has_perm(struct task_struct *task, struct sock *sk, u32 perms)
        if (sksec->sid == SECINITSID_KERNEL)
                return 0;
 
-       COMMON_AUDIT_DATA_INIT(&ad, NET);
+       ad.type = LSM_AUDIT_DATA_NET;
        ad.selinux_audit_data = &sad;
        ad.u.net = &net;
        ad.u.net->sk = sk;
@@ -3870,7 +3900,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
                                                      snum, &sid);
                                if (err)
                                        goto out;
-                               COMMON_AUDIT_DATA_INIT(&ad, NET);
+                               ad.type = LSM_AUDIT_DATA_NET;
                                ad.selinux_audit_data = &sad;
                                ad.u.net = &net;
                                ad.u.net->sport = htons(snum);
@@ -3905,7 +3935,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
                if (err)
                        goto out;
 
-               COMMON_AUDIT_DATA_INIT(&ad, NET);
+               ad.type = LSM_AUDIT_DATA_NET;
                ad.selinux_audit_data = &sad;
                ad.u.net = &net;
                ad.u.net->sport = htons(snum);
@@ -3967,7 +3997,7 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address,
                perm = (sksec->sclass == SECCLASS_TCP_SOCKET) ?
                       TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT;
 
-               COMMON_AUDIT_DATA_INIT(&ad, NET);
+               ad.type = LSM_AUDIT_DATA_NET;
                ad.selinux_audit_data = &sad;
                ad.u.net = &net;
                ad.u.net->dport = htons(snum);
@@ -4064,7 +4094,7 @@ static int selinux_socket_unix_stream_connect(struct sock *sock,
        struct lsm_network_audit net = {0,};
        int err;
 
-       COMMON_AUDIT_DATA_INIT(&ad, NET);
+       ad.type = LSM_AUDIT_DATA_NET;
        ad.selinux_audit_data = &sad;
        ad.u.net = &net;
        ad.u.net->sk = other;
@@ -4097,7 +4127,7 @@ static int selinux_socket_unix_may_send(struct socket *sock,
        struct selinux_audit_data sad = {0,};
        struct lsm_network_audit net = {0,};
 
-       COMMON_AUDIT_DATA_INIT(&ad, NET);
+       ad.type = LSM_AUDIT_DATA_NET;
        ad.selinux_audit_data = &sad;
        ad.u.net = &net;
        ad.u.net->sk = other->sk;
@@ -4140,7 +4170,7 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
        struct lsm_network_audit net = {0,};
        char *addrp;
 
-       COMMON_AUDIT_DATA_INIT(&ad, NET);
+       ad.type = LSM_AUDIT_DATA_NET;
        ad.selinux_audit_data = &sad;
        ad.u.net = &net;
        ad.u.net->netif = skb->skb_iif;
@@ -4196,7 +4226,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
        if (!secmark_active && !peerlbl_active)
                return 0;
 
-       COMMON_AUDIT_DATA_INIT(&ad, NET);
+       ad.type = LSM_AUDIT_DATA_NET;
        ad.selinux_audit_data = &sad;
        ad.u.net = &net;
        ad.u.net->netif = skb->skb_iif;
@@ -4553,7 +4583,7 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
        if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0)
                return NF_DROP;
 
-       COMMON_AUDIT_DATA_INIT(&ad, NET);
+       ad.type = LSM_AUDIT_DATA_NET;
        ad.selinux_audit_data = &sad;
        ad.u.net = &net;
        ad.u.net->netif = ifindex;
@@ -4653,7 +4683,7 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
                return NF_ACCEPT;
        sksec = sk->sk_security;
 
-       COMMON_AUDIT_DATA_INIT(&ad, NET);
+       ad.type = LSM_AUDIT_DATA_NET;
        ad.selinux_audit_data = &sad;
        ad.u.net = &net;
        ad.u.net->netif = ifindex;
@@ -4726,7 +4756,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
                secmark_perm = PACKET__SEND;
        }
 
-       COMMON_AUDIT_DATA_INIT(&ad, NET);
+       ad.type = LSM_AUDIT_DATA_NET;
        ad.selinux_audit_data = &sad;
        ad.u.net = &net;
        ad.u.net->netif = ifindex;
@@ -4850,7 +4880,7 @@ static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
 
        isec = ipc_perms->security;
 
-       COMMON_AUDIT_DATA_INIT(&ad, IPC);
+       ad.type = LSM_AUDIT_DATA_IPC;
        ad.selinux_audit_data = &sad;
        ad.u.ipc_id = ipc_perms->key;
 
@@ -4882,7 +4912,7 @@ static int selinux_msg_queue_alloc_security(struct msg_queue *msq)
 
        isec = msq->q_perm.security;
 
-       COMMON_AUDIT_DATA_INIT(&ad, IPC);
+       ad.type = LSM_AUDIT_DATA_IPC;
        ad.selinux_audit_data = &sad;
        ad.u.ipc_id = msq->q_perm.key;
 
@@ -4909,7 +4939,7 @@ static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg)
 
        isec = msq->q_perm.security;
 
-       COMMON_AUDIT_DATA_INIT(&ad, IPC);
+       ad.type = LSM_AUDIT_DATA_IPC;
        ad.selinux_audit_data = &sad;
        ad.u.ipc_id = msq->q_perm.key;
 
@@ -4971,7 +5001,7 @@ static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg,
                        return rc;
        }
 
-       COMMON_AUDIT_DATA_INIT(&ad, IPC);
+       ad.type = LSM_AUDIT_DATA_IPC;
        ad.selinux_audit_data = &sad;
        ad.u.ipc_id = msq->q_perm.key;
 
@@ -5004,7 +5034,7 @@ static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
        isec = msq->q_perm.security;
        msec = msg->security;
 
-       COMMON_AUDIT_DATA_INIT(&ad, IPC);
+       ad.type = LSM_AUDIT_DATA_IPC;
        ad.selinux_audit_data = &sad;
        ad.u.ipc_id = msq->q_perm.key;
 
@@ -5031,7 +5061,7 @@ static int selinux_shm_alloc_security(struct shmid_kernel *shp)
 
        isec = shp->shm_perm.security;
 
-       COMMON_AUDIT_DATA_INIT(&ad, IPC);
+       ad.type = LSM_AUDIT_DATA_IPC;
        ad.selinux_audit_data = &sad;
        ad.u.ipc_id = shp->shm_perm.key;
 
@@ -5058,7 +5088,7 @@ static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg)
 
        isec = shp->shm_perm.security;
 
-       COMMON_AUDIT_DATA_INIT(&ad, IPC);
+       ad.type = LSM_AUDIT_DATA_IPC;
        ad.selinux_audit_data = &sad;
        ad.u.ipc_id = shp->shm_perm.key;
 
@@ -5127,7 +5157,7 @@ static int selinux_sem_alloc_security(struct sem_array *sma)
 
        isec = sma->sem_perm.security;
 
-       COMMON_AUDIT_DATA_INIT(&ad, IPC);
+       ad.type = LSM_AUDIT_DATA_IPC;
        ad.selinux_audit_data = &sad;
        ad.u.ipc_id = sma->sem_perm.key;
 
@@ -5154,7 +5184,7 @@ static int selinux_sem_associate(struct sem_array *sma, int semflg)
 
        isec = sma->sem_perm.security;
 
-       COMMON_AUDIT_DATA_INIT(&ad, IPC);
+       ad.type = LSM_AUDIT_DATA_IPC;
        ad.selinux_audit_data = &sad;
        ad.u.ipc_id = sma->sem_perm.key;
 
@@ -5335,8 +5365,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);
                }