Smack: include magic.h in smackfs.c
[linux-3.10.git] / security / lsm_audit.c
index 8c36506..8d8d97d 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/types.h>
 #include <linux/stddef.h>
 #include <linux/kernel.h>
+#include <linux/gfp.h>
 #include <linux/fs.h>
 #include <linux/init.h>
 #include <net/sock.h>
@@ -48,8 +49,8 @@ int ipv4_skb_to_auditdata(struct sk_buff *skb,
        if (ih == NULL)
                return -EINVAL;
 
-       ad->u.net.v4info.saddr = ih->saddr;
-       ad->u.net.v4info.daddr = ih->daddr;
+       ad->u.net->v4info.saddr = ih->saddr;
+       ad->u.net->v4info.daddr = ih->daddr;
 
        if (proto)
                *proto = ih->protocol;
@@ -63,8 +64,8 @@ int ipv4_skb_to_auditdata(struct sk_buff *skb,
                if (th == NULL)
                        break;
 
-               ad->u.net.sport = th->source;
-               ad->u.net.dport = th->dest;
+               ad->u.net->sport = th->source;
+               ad->u.net->dport = th->dest;
                break;
        }
        case IPPROTO_UDP: {
@@ -72,8 +73,8 @@ int ipv4_skb_to_auditdata(struct sk_buff *skb,
                if (uh == NULL)
                        break;
 
-               ad->u.net.sport = uh->source;
-               ad->u.net.dport = uh->dest;
+               ad->u.net->sport = uh->source;
+               ad->u.net->dport = uh->dest;
                break;
        }
        case IPPROTO_DCCP: {
@@ -81,16 +82,16 @@ int ipv4_skb_to_auditdata(struct sk_buff *skb,
                if (dh == NULL)
                        break;
 
-               ad->u.net.sport = dh->dccph_sport;
-               ad->u.net.dport = dh->dccph_dport;
+               ad->u.net->sport = dh->dccph_sport;
+               ad->u.net->dport = dh->dccph_dport;
                break;
        }
        case IPPROTO_SCTP: {
                struct sctphdr *sh = sctp_hdr(skb);
                if (sh == NULL)
                        break;
-               ad->u.net.sport = sh->source;
-               ad->u.net.dport = sh->dest;
+               ad->u.net->sport = sh->source;
+               ad->u.net->dport = sh->dest;
                break;
        }
        default:
@@ -113,19 +114,20 @@ int ipv6_skb_to_auditdata(struct sk_buff *skb,
        int offset, ret = 0;
        struct ipv6hdr *ip6;
        u8 nexthdr;
+       __be16 frag_off;
 
        ip6 = ipv6_hdr(skb);
        if (ip6 == NULL)
                return -EINVAL;
-       ipv6_addr_copy(&ad->u.net.v6info.saddr, &ip6->saddr);
-       ipv6_addr_copy(&ad->u.net.v6info.daddr, &ip6->daddr);
+       ad->u.net->v6info.saddr = ip6->saddr;
+       ad->u.net->v6info.daddr = ip6->daddr;
        ret = 0;
        /* IPv6 can have several extension header before the Transport header
         * skip them */
        offset = skb_network_offset(skb);
        offset += sizeof(*ip6);
        nexthdr = ip6->nexthdr;
-       offset = ipv6_skip_exthdr(skb, offset, &nexthdr);
+       offset = ipv6_skip_exthdr(skb, offset, &nexthdr, &frag_off);
        if (offset < 0)
                return 0;
        if (proto)
@@ -138,8 +140,8 @@ int ipv6_skb_to_auditdata(struct sk_buff *skb,
                if (th == NULL)
                        break;
 
-               ad->u.net.sport = th->source;
-               ad->u.net.dport = th->dest;
+               ad->u.net->sport = th->source;
+               ad->u.net->dport = th->dest;
                break;
        }
        case IPPROTO_UDP: {
@@ -149,8 +151,8 @@ int ipv6_skb_to_auditdata(struct sk_buff *skb,
                if (uh == NULL)
                        break;
 
-               ad->u.net.sport = uh->source;
-               ad->u.net.dport = uh->dest;
+               ad->u.net->sport = uh->source;
+               ad->u.net->dport = uh->dest;
                break;
        }
        case IPPROTO_DCCP: {
@@ -160,8 +162,8 @@ int ipv6_skb_to_auditdata(struct sk_buff *skb,
                if (dh == NULL)
                        break;
 
-               ad->u.net.sport = dh->dccph_sport;
-               ad->u.net.dport = dh->dccph_dport;
+               ad->u.net->sport = dh->dccph_sport;
+               ad->u.net->dport = dh->dccph_dport;
                break;
        }
        case IPPROTO_SCTP: {
@@ -170,8 +172,8 @@ int ipv6_skb_to_auditdata(struct sk_buff *skb,
                sh = skb_header_pointer(skb, offset, sizeof(_sctph), &_sctph);
                if (sh == NULL)
                        break;
-               ad->u.net.sport = sh->source;
-               ad->u.net.dport = sh->dest;
+               ad->u.net->sport = sh->source;
+               ad->u.net->dport = sh->dest;
                break;
        }
        default:
@@ -209,15 +211,17 @@ static inline void print_ipv4_addr(struct audit_buffer *ab, __be32 addr,
 static void dump_common_audit_data(struct audit_buffer *ab,
                                   struct common_audit_data *a)
 {
-       struct inode *inode = NULL;
        struct task_struct *tsk = current;
 
-       if (a->tsk)
-               tsk = a->tsk;
-       if (tsk && tsk->pid) {
-               audit_log_format(ab, " pid=%d comm=", tsk->pid);
-               audit_log_untrustedstring(ab, tsk->comm);
-       }
+       /*
+        * To keep stack sizes in check force programers to notice if they
+        * start making this union too large!  See struct lsm_network_audit
+        * as an example of how to deal with large data.
+        */
+       BUILD_BUG_ON(sizeof(a->u) > sizeof(void *)*2);
+
+       audit_log_format(ab, " pid=%d comm=", tsk->pid);
+       audit_log_untrustedstring(ab, tsk->comm);
 
        switch (a->type) {
        case LSM_AUDIT_DATA_NONE:
@@ -228,33 +232,50 @@ static void dump_common_audit_data(struct audit_buffer *ab,
        case LSM_AUDIT_DATA_CAP:
                audit_log_format(ab, " capability=%d ", a->u.cap);
                break;
-       case LSM_AUDIT_DATA_FS:
-               if (a->u.fs.path.dentry) {
-                       struct dentry *dentry = a->u.fs.path.dentry;
-                       if (a->u.fs.path.mnt) {
-                               audit_log_d_path(ab, "path=", &a->u.fs.path);
-                       } else {
-                               audit_log_format(ab, " name=");
-                               audit_log_untrustedstring(ab,
-                                                dentry->d_name.name);
-                       }
-                       inode = dentry->d_inode;
-               } else if (a->u.fs.inode) {
-                       struct dentry *dentry;
-                       inode = a->u.fs.inode;
-                       dentry = d_find_alias(inode);
-                       if (dentry) {
-                               audit_log_format(ab, " name=");
-                               audit_log_untrustedstring(ab,
-                                                dentry->d_name.name);
-                               dput(dentry);
-                       }
+       case LSM_AUDIT_DATA_PATH: {
+               struct inode *inode;
+
+               audit_log_d_path(ab, " path=", &a->u.path);
+
+               inode = a->u.path.dentry->d_inode;
+               if (inode) {
+                       audit_log_format(ab, " dev=");
+                       audit_log_untrustedstring(ab, inode->i_sb->s_id);
+                       audit_log_format(ab, " ino=%lu", inode->i_ino);
                }
-               if (inode)
-                       audit_log_format(ab, " dev=%s ino=%lu",
-                                       inode->i_sb->s_id,
-                                       inode->i_ino);
                break;
+       }
+       case LSM_AUDIT_DATA_DENTRY: {
+               struct inode *inode;
+
+               audit_log_format(ab, " name=");
+               audit_log_untrustedstring(ab, a->u.dentry->d_name.name);
+
+               inode = a->u.dentry->d_inode;
+               if (inode) {
+                       audit_log_format(ab, " dev=");
+                       audit_log_untrustedstring(ab, inode->i_sb->s_id);
+                       audit_log_format(ab, " ino=%lu", inode->i_ino);
+               }
+               break;
+       }
+       case LSM_AUDIT_DATA_INODE: {
+               struct dentry *dentry;
+               struct inode *inode;
+
+               inode = a->u.inode;
+               dentry = d_find_alias(inode);
+               if (dentry) {
+                       audit_log_format(ab, " name=");
+                       audit_log_untrustedstring(ab,
+                                        dentry->d_name.name);
+                       dput(dentry);
+               }
+               audit_log_format(ab, " dev=");
+               audit_log_untrustedstring(ab, inode->i_sb->s_id);
+               audit_log_format(ab, " ino=%lu", inode->i_ino);
+               break;
+       }
        case LSM_AUDIT_DATA_TASK:
                tsk = a->u.tsk;
                if (tsk && tsk->pid) {
@@ -263,8 +284,8 @@ static void dump_common_audit_data(struct audit_buffer *ab,
                }
                break;
        case LSM_AUDIT_DATA_NET:
-               if (a->u.net.sk) {
-                       struct sock *sk = a->u.net.sk;
+               if (a->u.net->sk) {
+                       struct sock *sk = a->u.net->sk;
                        struct unix_sock *u;
                        int len = 0;
                        char *p = NULL;
@@ -295,12 +316,8 @@ static void dump_common_audit_data(struct audit_buffer *ab,
                        }
                        case AF_UNIX:
                                u = unix_sk(sk);
-                               if (u->dentry) {
-                                       struct path path = {
-                                               .dentry = u->dentry,
-                                               .mnt = u->mnt
-                                       };
-                                       audit_log_d_path(ab, "path=", &path);
+                               if (u->path.dentry) {
+                                       audit_log_d_path(ab, " path=", &u->path);
                                        break;
                                }
                                if (!u->addr)
@@ -316,29 +333,29 @@ static void dump_common_audit_data(struct audit_buffer *ab,
                        }
                }
 
-               switch (a->u.net.family) {
+               switch (a->u.net->family) {
                case AF_INET:
-                       print_ipv4_addr(ab, a->u.net.v4info.saddr,
-                                       a->u.net.sport,
+                       print_ipv4_addr(ab, a->u.net->v4info.saddr,
+                                       a->u.net->sport,
                                        "saddr", "src");
-                       print_ipv4_addr(ab, a->u.net.v4info.daddr,
-                                       a->u.net.dport,
+                       print_ipv4_addr(ab, a->u.net->v4info.daddr,
+                                       a->u.net->dport,
                                        "daddr", "dest");
                        break;
                case AF_INET6:
-                       print_ipv6_addr(ab, &a->u.net.v6info.saddr,
-                                       a->u.net.sport,
+                       print_ipv6_addr(ab, &a->u.net->v6info.saddr,
+                                       a->u.net->sport,
                                        "saddr", "src");
-                       print_ipv6_addr(ab, &a->u.net.v6info.daddr,
-                                       a->u.net.dport,
+                       print_ipv6_addr(ab, &a->u.net->v6info.daddr,
+                                       a->u.net->dport,
                                        "daddr", "dest");
                        break;
                }
-               if (a->u.net.netif > 0) {
+               if (a->u.net->netif > 0) {
                        struct net_device *dev;
 
                        /* NOTE: we always use init's namespace */
-                       dev = dev_get_by_index(&init_net, a->u.net.netif);
+                       dev = dev_get_by_index(&init_net, a->u.net->netif);
                        if (dev) {
                                audit_log_format(ab, " netif=%s", dev->name);
                                dev_put(dev);
@@ -364,11 +381,15 @@ static void dump_common_audit_data(struct audit_buffer *ab,
 /**
  * common_lsm_audit - generic LSM auditing function
  * @a:  auxiliary audit data
+ * @pre_audit: lsm-specific pre-audit callback
+ * @post_audit: lsm-specific post-audit callback
  *
  * setup the audit buffer for common security information
  * uses callback to print LSM specific information
  */
-void common_lsm_audit(struct common_audit_data *a)
+void common_lsm_audit(struct common_audit_data *a,
+       void (*pre_audit)(struct audit_buffer *, void *),
+       void (*post_audit)(struct audit_buffer *, void *))
 {
        struct audit_buffer *ab;
 
@@ -380,13 +401,13 @@ void common_lsm_audit(struct common_audit_data *a)
        if (ab == NULL)
                return;
 
-       if (a->lsm_pre_audit)
-               a->lsm_pre_audit(ab, a);
+       if (pre_audit)
+               pre_audit(ab, a);
 
        dump_common_audit_data(ab, a);
 
-       if (a->lsm_post_audit)
-               a->lsm_post_audit(ab, a);
+       if (post_audit)
+               post_audit(ab, a);
 
        audit_log_end(ab);
 }