Merge branch 'selinux' ("struct common_audit_data" sanitizer)

Merge common_audit_data cleanup patches from Eric Paris.

This is really too late, but it's a long-overdue cleanup of the costly
wrapper functions for the security layer.

The "struct common_audit_data" is used all over in critical paths,
allocated and initialized on the stack.  And used to be much too large,
causing not only unnecessarily big stack frames but the clearing of the
(mostly useless) data was also very visible in profiles.

As a particular example, in one microbenchmark for just doing "stat()"
over files a lot, selinux_inode_permission() used 7% of the CPU time.
That's despite the fact that it doesn't actually *do* anything: it is
just a helper wrapper function in the selinux security layer.

This patch-series shrinks "struct common_audit_data" sufficiently that
code generation for these kinds of wrapper functions is improved
noticeably, and we spend much less time just initializing data that we
will never use.

The functions still get called all the time, and it still shows up at
3.5+% in my microbenchmark, but it's quite a bit lower down the list,
and much less noticeable.

* Emailed patches from Eric Paris <eparis@redhat.com>:
  lsm_audit: don't specify the audit pre/post callbacks in 'struct common_audit_data'
  SELinux: do not allocate stack space for AVC data unless needed
  SELinux: remove avd from slow_avc_audit()
  SELinux: remove avd from selinux_audit_data
  LSM: shrink the common_audit_data data union
  LSM: shrink sizeof LSM specific portion of common_audit_data
diff --git a/include/linux/lsm_audit.h b/include/linux/lsm_audit.h
index eab507f..fad48aa 100644
--- a/include/linux/lsm_audit.h
+++ b/include/linux/lsm_audit.h
@@ -22,6 +22,23 @@
 #include <linux/key.h>
 #include <linux/skbuff.h>
 
+struct lsm_network_audit {
+	int netif;
+	struct sock *sk;
+	u16 family;
+	__be16 dport;
+	__be16 sport;
+	union {
+		struct {
+			__be32 daddr;
+			__be32 saddr;
+		} v4;
+		struct {
+			struct in6_addr daddr;
+			struct in6_addr saddr;
+		} v6;
+	} fam;
+};
 
 /* Auxiliary data to use in generating the audit record. */
 struct common_audit_data {
@@ -41,23 +58,7 @@
 		struct path path;
 		struct dentry *dentry;
 		struct inode *inode;
-		struct {
-			int netif;
-			struct sock *sk;
-			u16 family;
-			__be16 dport;
-			__be16 sport;
-			union {
-				struct {
-					__be32 daddr;
-					__be32 saddr;
-				} v4;
-				struct {
-					struct in6_addr daddr;
-					struct in6_addr saddr;
-				} v6;
-			} fam;
-		} net;
+		struct lsm_network_audit *net;
 		int cap;
 		int ipc_id;
 		struct task_struct *tsk;
@@ -72,64 +73,15 @@
 	/* this union contains LSM specific data */
 	union {
 #ifdef CONFIG_SECURITY_SMACK
-		/* SMACK data */
-		struct smack_audit_data {
-			const char *function;
-			char *subject;
-			char *object;
-			char *request;
-			int result;
-		} smack_audit_data;
+		struct smack_audit_data *smack_audit_data;
 #endif
 #ifdef CONFIG_SECURITY_SELINUX
-		/* SELinux data */
-		struct {
-			u32 ssid;
-			u32 tsid;
-			u16 tclass;
-			u32 requested;
-			u32 audited;
-			u32 denied;
-			/*
-			 * auditdeny is a bit tricky and unintuitive.  See the
-			 * comments in avc.c for it's meaning and usage.
-			 */
-			u32 auditdeny;
-			struct av_decision *avd;
-			int result;
-		} selinux_audit_data;
+		struct selinux_audit_data *selinux_audit_data;
 #endif
 #ifdef CONFIG_SECURITY_APPARMOR
-		struct {
-			int error;
-			int op;
-			int type;
-			void *profile;
-			const char *name;
-			const char *info;
-			union {
-				void *target;
-				struct {
-					long pos;
-					void *target;
-				} iface;
-				struct {
-					int rlim;
-					unsigned long max;
-				} rlim;
-				struct {
-					const char *target;
-					u32 request;
-					u32 denied;
-					uid_t ouid;
-				} fs;
-			};
-		} apparmor_audit_data;
+		struct apparmor_audit_data *apparmor_audit_data;
 #endif
-	};
-	/* these callback will be implemented by a specific LSM */
-	void (*lsm_pre_audit)(struct audit_buffer *, void *);
-	void (*lsm_post_audit)(struct audit_buffer *, void *);
+	}; /* per LSM data pointer union */
 };
 
 #define v4info fam.v4
@@ -146,6 +98,8 @@
 	{ memset((_d), 0, sizeof(struct common_audit_data)); \
 	 (_d)->type = LSM_AUDIT_DATA_##_t; }
 
-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 *));
 
 #endif
diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c
index 5ff6777..cc3520d 100644
--- a/security/apparmor/audit.c
+++ b/security/apparmor/audit.c
@@ -115,23 +115,23 @@
 
 	if (aa_g_audit_header) {
 		audit_log_format(ab, "apparmor=");
-		audit_log_string(ab, aa_audit_type[sa->aad.type]);
+		audit_log_string(ab, aa_audit_type[sa->aad->type]);
 	}
 
-	if (sa->aad.op) {
+	if (sa->aad->op) {
 		audit_log_format(ab, " operation=");
-		audit_log_string(ab, op_table[sa->aad.op]);
+		audit_log_string(ab, op_table[sa->aad->op]);
 	}
 
-	if (sa->aad.info) {
+	if (sa->aad->info) {
 		audit_log_format(ab, " info=");
-		audit_log_string(ab, sa->aad.info);
-		if (sa->aad.error)
-			audit_log_format(ab, " error=%d", sa->aad.error);
+		audit_log_string(ab, sa->aad->info);
+		if (sa->aad->error)
+			audit_log_format(ab, " error=%d", sa->aad->error);
 	}
 
-	if (sa->aad.profile) {
-		struct aa_profile *profile = sa->aad.profile;
+	if (sa->aad->profile) {
+		struct aa_profile *profile = sa->aad->profile;
 		pid_t pid;
 		rcu_read_lock();
 		pid = rcu_dereference(tsk->real_parent)->pid;
@@ -145,9 +145,9 @@
 		audit_log_untrustedstring(ab, profile->base.hname);
 	}
 
-	if (sa->aad.name) {
+	if (sa->aad->name) {
 		audit_log_format(ab, " name=");
-		audit_log_untrustedstring(ab, sa->aad.name);
+		audit_log_untrustedstring(ab, sa->aad->name);
 	}
 }
 
@@ -159,10 +159,8 @@
 void aa_audit_msg(int type, struct common_audit_data *sa,
 		  void (*cb) (struct audit_buffer *, void *))
 {
-	sa->aad.type = type;
-	sa->lsm_pre_audit = audit_pre;
-	sa->lsm_post_audit = cb;
-	common_lsm_audit(sa);
+	sa->aad->type = type;
+	common_lsm_audit(sa, audit_pre, cb);
 }
 
 /**
@@ -184,7 +182,7 @@
 	BUG_ON(!profile);
 
 	if (type == AUDIT_APPARMOR_AUTO) {
-		if (likely(!sa->aad.error)) {
+		if (likely(!sa->aad->error)) {
 			if (AUDIT_MODE(profile) != AUDIT_ALL)
 				return 0;
 			type = AUDIT_APPARMOR_AUDIT;
@@ -196,21 +194,21 @@
 	if (AUDIT_MODE(profile) == AUDIT_QUIET ||
 	    (type == AUDIT_APPARMOR_DENIED &&
 	     AUDIT_MODE(profile) == AUDIT_QUIET))
-		return sa->aad.error;
+		return sa->aad->error;
 
 	if (KILL_MODE(profile) && type == AUDIT_APPARMOR_DENIED)
 		type = AUDIT_APPARMOR_KILL;
 
 	if (!unconfined(profile))
-		sa->aad.profile = profile;
+		sa->aad->profile = profile;
 
 	aa_audit_msg(type, sa, cb);
 
-	if (sa->aad.type == AUDIT_APPARMOR_KILL)
+	if (sa->aad->type == AUDIT_APPARMOR_KILL)
 		(void)send_sig_info(SIGKILL, NULL, sa->tsk ? sa->tsk : current);
 
-	if (sa->aad.type == AUDIT_APPARMOR_ALLOWED)
-		return complain_error(sa->aad.error);
+	if (sa->aad->type == AUDIT_APPARMOR_ALLOWED)
+		return complain_error(sa->aad->error);
 
-	return sa->aad.error;
+	return sa->aad->error;
 }
diff --git a/security/apparmor/capability.c b/security/apparmor/capability.c
index 9982c48..088dba3 100644
--- a/security/apparmor/capability.c
+++ b/security/apparmor/capability.c
@@ -64,11 +64,13 @@
 	struct audit_cache *ent;
 	int type = AUDIT_APPARMOR_AUTO;
 	struct common_audit_data sa;
+	struct apparmor_audit_data aad = {0,};
 	COMMON_AUDIT_DATA_INIT(&sa, CAP);
+	sa.aad = &aad;
 	sa.tsk = task;
 	sa.u.cap = cap;
-	sa.aad.op = OP_CAPABLE;
-	sa.aad.error = error;
+	sa.aad->op = OP_CAPABLE;
+	sa.aad->error = error;
 
 	if (likely(!error)) {
 		/* test if auditing is being forced */
diff --git a/security/apparmor/file.c b/security/apparmor/file.c
index 5d176f2..2f8fcba 100644
--- a/security/apparmor/file.c
+++ b/security/apparmor/file.c
@@ -67,22 +67,22 @@
 	struct common_audit_data *sa = va;
 	uid_t fsuid = current_fsuid();
 
-	if (sa->aad.fs.request & AA_AUDIT_FILE_MASK) {
+	if (sa->aad->fs.request & AA_AUDIT_FILE_MASK) {
 		audit_log_format(ab, " requested_mask=");
-		audit_file_mask(ab, sa->aad.fs.request);
+		audit_file_mask(ab, sa->aad->fs.request);
 	}
-	if (sa->aad.fs.denied & AA_AUDIT_FILE_MASK) {
+	if (sa->aad->fs.denied & AA_AUDIT_FILE_MASK) {
 		audit_log_format(ab, " denied_mask=");
-		audit_file_mask(ab, sa->aad.fs.denied);
+		audit_file_mask(ab, sa->aad->fs.denied);
 	}
-	if (sa->aad.fs.request & AA_AUDIT_FILE_MASK) {
+	if (sa->aad->fs.request & AA_AUDIT_FILE_MASK) {
 		audit_log_format(ab, " fsuid=%d", fsuid);
-		audit_log_format(ab, " ouid=%d", sa->aad.fs.ouid);
+		audit_log_format(ab, " ouid=%d", sa->aad->fs.ouid);
 	}
 
-	if (sa->aad.fs.target) {
+	if (sa->aad->fs.target) {
 		audit_log_format(ab, " target=");
-		audit_log_untrustedstring(ab, sa->aad.fs.target);
+		audit_log_untrustedstring(ab, sa->aad->fs.target);
 	}
 }
 
@@ -107,45 +107,47 @@
 {
 	int type = AUDIT_APPARMOR_AUTO;
 	struct common_audit_data sa;
+	struct apparmor_audit_data aad = {0,};
 	COMMON_AUDIT_DATA_INIT(&sa, NONE);
-	sa.aad.op = op,
-	sa.aad.fs.request = request;
-	sa.aad.name = name;
-	sa.aad.fs.target = target;
-	sa.aad.fs.ouid = ouid;
-	sa.aad.info = info;
-	sa.aad.error = error;
+	sa.aad = &aad;
+	aad.op = op,
+	aad.fs.request = request;
+	aad.name = name;
+	aad.fs.target = target;
+	aad.fs.ouid = ouid;
+	aad.info = info;
+	aad.error = error;
 
-	if (likely(!sa.aad.error)) {
+	if (likely(!sa.aad->error)) {
 		u32 mask = perms->audit;
 
 		if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL))
 			mask = 0xffff;
 
 		/* mask off perms that are not being force audited */
-		sa.aad.fs.request &= mask;
+		sa.aad->fs.request &= mask;
 
-		if (likely(!sa.aad.fs.request))
+		if (likely(!sa.aad->fs.request))
 			return 0;
 		type = AUDIT_APPARMOR_AUDIT;
 	} else {
 		/* only report permissions that were denied */
-		sa.aad.fs.request = sa.aad.fs.request & ~perms->allow;
+		sa.aad->fs.request = sa.aad->fs.request & ~perms->allow;
 
-		if (sa.aad.fs.request & perms->kill)
+		if (sa.aad->fs.request & perms->kill)
 			type = AUDIT_APPARMOR_KILL;
 
 		/* quiet known rejects, assumes quiet and kill do not overlap */
-		if ((sa.aad.fs.request & perms->quiet) &&
+		if ((sa.aad->fs.request & perms->quiet) &&
 		    AUDIT_MODE(profile) != AUDIT_NOQUIET &&
 		    AUDIT_MODE(profile) != AUDIT_ALL)
-			sa.aad.fs.request &= ~perms->quiet;
+			sa.aad->fs.request &= ~perms->quiet;
 
-		if (!sa.aad.fs.request)
-			return COMPLAIN_MODE(profile) ? 0 : sa.aad.error;
+		if (!sa.aad->fs.request)
+			return COMPLAIN_MODE(profile) ? 0 : sa.aad->error;
 	}
 
-	sa.aad.fs.denied = sa.aad.fs.request & ~perms->allow;
+	sa.aad->fs.denied = sa.aad->fs.request & ~perms->allow;
 	return aa_audit(type, profile, gfp, &sa, file_audit_cb);
 }
 
diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
index 4ba78c2..3868b1e 100644
--- a/security/apparmor/include/audit.h
+++ b/security/apparmor/include/audit.h
@@ -103,7 +103,33 @@
 };
 
 
-/* define a short hand for apparmor_audit_data portion of common_audit_data */
+struct apparmor_audit_data {
+	int error;
+	int op;
+	int type;
+	void *profile;
+	const char *name;
+	const char *info;
+	union {
+		void *target;
+		struct {
+			long pos;
+			void *target;
+		} iface;
+		struct {
+			int rlim;
+			unsigned long max;
+		} rlim;
+		struct {
+			const char *target;
+			u32 request;
+			u32 denied;
+			uid_t ouid;
+		} fs;
+	};
+};
+
+/* define a short hand for apparmor_audit_data structure */
 #define aad apparmor_audit_data
 
 void aa_audit_msg(int type, struct common_audit_data *sa,
diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c
index 7ee05c6..c3da93a 100644
--- a/security/apparmor/ipc.c
+++ b/security/apparmor/ipc.c
@@ -26,7 +26,7 @@
 {
 	struct common_audit_data *sa = va;
 	audit_log_format(ab, " target=");
-	audit_log_untrustedstring(ab, sa->aad.target);
+	audit_log_untrustedstring(ab, sa->aad->target);
 }
 
 /**
@@ -41,10 +41,12 @@
 			   struct aa_profile *target, int error)
 {
 	struct common_audit_data sa;
+	struct apparmor_audit_data aad = {0,};
 	COMMON_AUDIT_DATA_INIT(&sa, NONE);
-	sa.aad.op = OP_PTRACE;
-	sa.aad.target = target;
-	sa.aad.error = error;
+	sa.aad = &aad;
+	aad.op = OP_PTRACE;
+	aad.target = target;
+	aad.error = error;
 
 	return aa_audit(AUDIT_APPARMOR_AUTO, profile, GFP_ATOMIC, &sa,
 			audit_cb);
diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c
index 9516948..e75829b 100644
--- a/security/apparmor/lib.c
+++ b/security/apparmor/lib.c
@@ -65,8 +65,10 @@
 {
 	if (audit_enabled) {
 		struct common_audit_data sa;
+		struct apparmor_audit_data aad = {0,};
 		COMMON_AUDIT_DATA_INIT(&sa, NONE);
-		sa.aad.info = str;
+		sa.aad = &aad;
+		aad.info = str;
 		aa_audit_msg(AUDIT_APPARMOR_STATUS, &sa, NULL);
 	}
 	printk(KERN_INFO "AppArmor: %s\n", str);
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 97ce8fa..ad05d39 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -588,10 +588,12 @@
 			error = aa_setprocattr_permipc(args);
 		} else {
 			struct common_audit_data sa;
+			struct apparmor_audit_data aad = {0,};
 			COMMON_AUDIT_DATA_INIT(&sa, NONE);
-			sa.aad.op = OP_SETPROCATTR;
-			sa.aad.info = name;
-			sa.aad.error = -EINVAL;
+			sa.aad = &aad;
+			aad.op = OP_SETPROCATTR;
+			aad.info = name;
+			aad.error = -EINVAL;
 			return aa_audit(AUDIT_APPARMOR_DENIED,
 					__aa_current_profile(), GFP_KERNEL,
 					&sa, NULL);
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
index 9064143..f1f7506 100644
--- a/security/apparmor/policy.c
+++ b/security/apparmor/policy.c
@@ -964,11 +964,13 @@
 			int error)
 {
 	struct common_audit_data sa;
+	struct apparmor_audit_data aad = {0,};
 	COMMON_AUDIT_DATA_INIT(&sa, NONE);
-	sa.aad.op = op;
-	sa.aad.name = name;
-	sa.aad.info = info;
-	sa.aad.error = error;
+	sa.aad = &aad;
+	aad.op = op;
+	aad.name = name;
+	aad.info = info;
+	aad.error = error;
 
 	return aa_audit(AUDIT_APPARMOR_STATUS, __aa_current_profile(), gfp,
 			&sa, NULL);
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
index 25fd51e..deab7c7 100644
--- a/security/apparmor/policy_unpack.c
+++ b/security/apparmor/policy_unpack.c
@@ -70,13 +70,13 @@
 static void audit_cb(struct audit_buffer *ab, void *va)
 {
 	struct common_audit_data *sa = va;
-	if (sa->aad.iface.target) {
-		struct aa_profile *name = sa->aad.iface.target;
+	if (sa->aad->iface.target) {
+		struct aa_profile *name = sa->aad->iface.target;
 		audit_log_format(ab, " name=");
 		audit_log_untrustedstring(ab, name->base.hname);
 	}
-	if (sa->aad.iface.pos)
-		audit_log_format(ab, " offset=%ld", sa->aad.iface.pos);
+	if (sa->aad->iface.pos)
+		audit_log_format(ab, " offset=%ld", sa->aad->iface.pos);
 }
 
 /**
@@ -94,13 +94,15 @@
 {
 	struct aa_profile *profile = __aa_current_profile();
 	struct common_audit_data sa;
+	struct apparmor_audit_data aad = {0,};
 	COMMON_AUDIT_DATA_INIT(&sa, NONE);
+	sa.aad = &aad;
 	if (e)
-		sa.aad.iface.pos = e->pos - e->start;
-	sa.aad.iface.target = new;
-	sa.aad.name = name;
-	sa.aad.info = info;
-	sa.aad.error = error;
+		aad.iface.pos = e->pos - e->start;
+	aad.iface.target = new;
+	aad.name = name;
+	aad.info = info;
+	aad.error = error;
 
 	return aa_audit(AUDIT_APPARMOR_STATUS, profile, GFP_KERNEL, &sa,
 			audit_cb);
diff --git a/security/apparmor/resource.c b/security/apparmor/resource.c
index 72c25a4f..2fe8613 100644
--- a/security/apparmor/resource.c
+++ b/security/apparmor/resource.c
@@ -34,7 +34,7 @@
 	struct common_audit_data *sa = va;
 
 	audit_log_format(ab, " rlimit=%s value=%lu",
-			 rlim_names[sa->aad.rlim.rlim], sa->aad.rlim.max);
+			 rlim_names[sa->aad->rlim.rlim], sa->aad->rlim.max);
 }
 
 /**
@@ -50,12 +50,14 @@
 			  unsigned long value, int error)
 {
 	struct common_audit_data sa;
+	struct apparmor_audit_data aad = {0,};
 
 	COMMON_AUDIT_DATA_INIT(&sa, NONE);
-	sa.aad.op = OP_SETRLIMIT,
-	sa.aad.rlim.rlim = resource;
-	sa.aad.rlim.max = value;
-	sa.aad.error = error;
+	sa.aad = &aad;
+	aad.op = OP_SETRLIMIT,
+	aad.rlim.rlim = resource;
+	aad.rlim.max = value;
+	aad.error = error;
 	return aa_audit(AUDIT_APPARMOR_AUTO, profile, GFP_KERNEL, &sa,
 			audit_cb);
 }
diff --git a/security/lsm_audit.c b/security/lsm_audit.c
index 8b8f090..90c129b 100644
--- a/security/lsm_audit.c
+++ b/security/lsm_audit.c
@@ -49,8 +49,8 @@
 	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;
@@ -64,8 +64,8 @@
 		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: {
@@ -73,8 +73,8 @@
 		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: {
@@ -82,16 +82,16 @@
 		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:
@@ -119,8 +119,8 @@
 	ip6 = ipv6_hdr(skb);
 	if (ip6 == NULL)
 		return -EINVAL;
-	ad->u.net.v6info.saddr = ip6->saddr;
-	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 */
@@ -140,8 +140,8 @@
 		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: {
@@ -151,8 +151,8 @@
 		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: {
@@ -162,8 +162,8 @@
 		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: {
@@ -172,8 +172,8 @@
 		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:
@@ -281,8 +281,8 @@
 		}
 		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;
@@ -330,29 +330,29 @@
 			}
 		}
 
-		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);
@@ -378,11 +378,15 @@
 /**
  * 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;
 
@@ -394,13 +398,13 @@
 	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);
 }
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index 1a70fa2..8ee42b2 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -436,9 +436,9 @@
 {
 	struct common_audit_data *ad = a;
 	audit_log_format(ab, "avc:  %s ",
-			 ad->selinux_audit_data.denied ? "denied" : "granted");
-	avc_dump_av(ab, ad->selinux_audit_data.tclass,
-			ad->selinux_audit_data.audited);
+			 ad->selinux_audit_data->slad->denied ? "denied" : "granted");
+	avc_dump_av(ab, ad->selinux_audit_data->slad->tclass,
+			ad->selinux_audit_data->slad->audited);
 	audit_log_format(ab, " for ");
 }
 
@@ -452,22 +452,25 @@
 {
 	struct common_audit_data *ad = a;
 	audit_log_format(ab, " ");
-	avc_dump_query(ab, ad->selinux_audit_data.ssid,
-			   ad->selinux_audit_data.tsid,
-			   ad->selinux_audit_data.tclass);
+	avc_dump_query(ab, ad->selinux_audit_data->slad->ssid,
+			   ad->selinux_audit_data->slad->tsid,
+			   ad->selinux_audit_data->slad->tclass);
 }
 
 /* This is the slow part of avc audit with big stack footprint */
 static noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass,
 		u32 requested, u32 audited, u32 denied,
-		struct av_decision *avd, struct common_audit_data *a,
+		struct common_audit_data *a,
 		unsigned flags)
 {
 	struct common_audit_data stack_data;
+	struct selinux_audit_data sad = {0,};
+	struct selinux_late_audit_data slad;
 
 	if (!a) {
 		a = &stack_data;
 		COMMON_AUDIT_DATA_INIT(a, NONE);
+		a->selinux_audit_data = &sad;
 	}
 
 	/*
@@ -481,15 +484,15 @@
 	    (flags & MAY_NOT_BLOCK))
 		return -ECHILD;
 
-	a->selinux_audit_data.tclass = tclass;
-	a->selinux_audit_data.requested = requested;
-	a->selinux_audit_data.ssid = ssid;
-	a->selinux_audit_data.tsid = tsid;
-	a->selinux_audit_data.audited = audited;
-	a->selinux_audit_data.denied = denied;
-	a->lsm_pre_audit = avc_audit_pre_callback;
-	a->lsm_post_audit = avc_audit_post_callback;
-	common_lsm_audit(a);
+	slad.tclass = tclass;
+	slad.requested = requested;
+	slad.ssid = ssid;
+	slad.tsid = tsid;
+	slad.audited = audited;
+	slad.denied = denied;
+
+	a->selinux_audit_data->slad = &slad;
+	common_lsm_audit(a, avc_audit_pre_callback, avc_audit_post_callback);
 	return 0;
 }
 
@@ -523,7 +526,7 @@
 	if (unlikely(denied)) {
 		audited = denied & avd->auditdeny;
 		/*
-		 * a->selinux_audit_data.auditdeny is TRICKY!  Setting a bit in
+		 * a->selinux_audit_data->auditdeny is TRICKY!  Setting a bit in
 		 * this field means that ANY denials should NOT be audited if
 		 * the policy contains an explicit dontaudit rule for that
 		 * permission.  Take notice that this is unrelated to the
@@ -532,15 +535,15 @@
 		 *
 		 * denied == READ
 		 * avd.auditdeny & ACCESS == 0 (not set means explicit rule)
-		 * selinux_audit_data.auditdeny & ACCESS == 1
+		 * selinux_audit_data->auditdeny & ACCESS == 1
 		 *
 		 * We will NOT audit the denial even though the denied
 		 * permission was READ and the auditdeny checks were for
 		 * ACCESS
 		 */
 		if (a &&
-		    a->selinux_audit_data.auditdeny &&
-		    !(a->selinux_audit_data.auditdeny & avd->auditdeny))
+		    a->selinux_audit_data->auditdeny &&
+		    !(a->selinux_audit_data->auditdeny & avd->auditdeny))
 			audited = 0;
 	} else if (result)
 		audited = denied = requested;
@@ -551,7 +554,7 @@
 
 	return slow_avc_audit(ssid, tsid, tclass,
 		requested, audited, denied,
-		avd, a, flags);
+		a, flags);
 }
 
 /**
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 28482f9..d85b793 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1420,6 +1420,7 @@
 			       int cap, int audit)
 {
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 	struct av_decision avd;
 	u16 sclass;
 	u32 sid = cred_sid(cred);
@@ -1427,6 +1428,7 @@
 	int rc;
 
 	COMMON_AUDIT_DATA_INIT(&ad, CAP);
+	ad.selinux_audit_data = &sad;
 	ad.tsk = current;
 	ad.u.cap = cap;
 
@@ -1492,9 +1494,11 @@
 				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);
 }
 
@@ -1507,9 +1511,11 @@
 {
 	struct inode *inode = dentry->d_inode;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 
 	COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
 	ad.u.dentry = dentry;
+	ad.selinux_audit_data = &sad;
 	return inode_has_perm(cred, inode, av, &ad, 0);
 }
 
@@ -1522,9 +1528,11 @@
 {
 	struct inode *inode = path->dentry->d_inode;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 
 	COMMON_AUDIT_DATA_INIT(&ad, PATH);
 	ad.u.path = *path;
+	ad.selinux_audit_data = &sad;
 	return inode_has_perm(cred, inode, av, &ad, 0);
 }
 
@@ -1543,11 +1551,13 @@
 	struct file_security_struct *fsec = file->f_security;
 	struct inode *inode = file->f_path.dentry->d_inode;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 	u32 sid = cred_sid(cred);
 	int rc;
 
 	COMMON_AUDIT_DATA_INIT(&ad, PATH);
 	ad.u.path = file->f_path;
+	ad.selinux_audit_data = &sad;
 
 	if (sid != fsec->sid) {
 		rc = avc_has_perm(sid, fsec->sid,
@@ -1577,6 +1587,7 @@
 	struct superblock_security_struct *sbsec;
 	u32 sid, newsid;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 	int rc;
 
 	dsec = dir->i_security;
@@ -1587,6 +1598,7 @@
 
 	COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
 	ad.u.dentry = dentry;
+	ad.selinux_audit_data = &sad;
 
 	rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR,
 			  DIR__ADD_NAME | DIR__SEARCH,
@@ -1631,6 +1643,7 @@
 {
 	struct inode_security_struct *dsec, *isec;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 	u32 sid = current_sid();
 	u32 av;
 	int rc;
@@ -1640,6 +1653,7 @@
 
 	COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
 	ad.u.dentry = dentry;
+	ad.selinux_audit_data = &sad;
 
 	av = DIR__SEARCH;
 	av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME);
@@ -1674,6 +1688,7 @@
 {
 	struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 	u32 sid = current_sid();
 	u32 av;
 	int old_is_dir, new_is_dir;
@@ -1685,6 +1700,7 @@
 	new_dsec = new_dir->i_security;
 
 	COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
+	ad.selinux_audit_data = &sad;
 
 	ad.u.dentry = old_dentry;
 	rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR,
@@ -1970,6 +1986,7 @@
 	struct task_security_struct *new_tsec;
 	struct inode_security_struct *isec;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 	struct inode *inode = bprm->file->f_path.dentry->d_inode;
 	int rc;
 
@@ -2009,6 +2026,7 @@
 	}
 
 	COMMON_AUDIT_DATA_INIT(&ad, PATH);
+	ad.selinux_audit_data = &sad;
 	ad.u.path = bprm->file->f_path;
 
 	if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
@@ -2098,6 +2116,7 @@
 					    struct files_struct *files)
 {
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 	struct file *file, *devnull = NULL;
 	struct tty_struct *tty;
 	struct fdtable *fdt;
@@ -2135,6 +2154,7 @@
 	/* Revalidate access to inherited open files. */
 
 	COMMON_AUDIT_DATA_INIT(&ad, INODE);
+	ad.selinux_audit_data = &sad;
 
 	spin_lock(&files->file_lock);
 	for (;;) {
@@ -2472,6 +2492,7 @@
 {
 	const struct cred *cred = current_cred();
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 	int rc;
 
 	rc = superblock_doinit(sb, data);
@@ -2483,6 +2504,7 @@
 		return 0;
 
 	COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
+	ad.selinux_audit_data = &sad;
 	ad.u.dentry = sb->s_root;
 	return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad);
 }
@@ -2491,8 +2513,10 @@
 {
 	const struct cred *cred = current_cred();
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 
 	COMMON_AUDIT_DATA_INIT(&ad, 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);
 }
@@ -2656,6 +2680,7 @@
 {
 	const struct cred *cred = current_cred();
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 	u32 perms;
 	bool from_access;
 	unsigned flags = mask & MAY_NOT_BLOCK;
@@ -2668,10 +2693,11 @@
 		return 0;
 
 	COMMON_AUDIT_DATA_INIT(&ad, INODE);
+	ad.selinux_audit_data = &sad;
 	ad.u.inode = inode;
 
 	if (from_access)
-		ad.selinux_audit_data.auditdeny |= FILE__AUDIT_ACCESS;
+		ad.selinux_audit_data->auditdeny |= FILE__AUDIT_ACCESS;
 
 	perms = file_mask_to_av(inode->i_mode, mask);
 
@@ -2737,6 +2763,7 @@
 	struct inode_security_struct *isec = inode->i_security;
 	struct superblock_security_struct *sbsec;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 	u32 newsid, sid = current_sid();
 	int rc = 0;
 
@@ -2751,6 +2778,7 @@
 		return -EPERM;
 
 	COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
+	ad.selinux_audit_data = &sad;
 	ad.u.dentry = dentry;
 
 	rc = avc_has_perm(sid, isec->sid, isec->sclass,
@@ -3345,10 +3373,12 @@
 {
 	u32 sid;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 
 	sid = task_sid(current);
 
 	COMMON_AUDIT_DATA_INIT(&ad, KMOD);
+	ad.selinux_audit_data = &sad;
 	ad.u.kmod_name = kmod_name;
 
 	return avc_has_perm(sid, SECINITSID_KERNEL, SECCLASS_SYSTEM,
@@ -3487,8 +3517,8 @@
 	if (ihlen < sizeof(_iph))
 		goto out;
 
-	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;
 	ret = 0;
 
 	if (proto)
@@ -3506,8 +3536,8 @@
 		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;
 	}
 
@@ -3522,8 +3552,8 @@
 		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;
 	}
 
@@ -3538,8 +3568,8 @@
 		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;
 	}
 
@@ -3566,8 +3596,8 @@
 	if (ip6 == NULL)
 		goto out;
 
-	ad->u.net.v6info.saddr = ip6->saddr;
-	ad->u.net.v6info.daddr = ip6->daddr;
+	ad->u.net->v6info.saddr = ip6->saddr;
+	ad->u.net->v6info.daddr = ip6->daddr;
 	ret = 0;
 
 	nexthdr = ip6->nexthdr;
@@ -3587,8 +3617,8 @@
 		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;
 	}
 
@@ -3599,8 +3629,8 @@
 		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;
 	}
 
@@ -3611,8 +3641,8 @@
 		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;
 	}
 
@@ -3632,13 +3662,13 @@
 	char *addrp;
 	int ret;
 
-	switch (ad->u.net.family) {
+	switch (ad->u.net->family) {
 	case PF_INET:
 		ret = selinux_parse_skb_ipv4(skb, ad, proto);
 		if (ret)
 			goto parse_error;
-		addrp = (char *)(src ? &ad->u.net.v4info.saddr :
-				       &ad->u.net.v4info.daddr);
+		addrp = (char *)(src ? &ad->u.net->v4info.saddr :
+				       &ad->u.net->v4info.daddr);
 		goto okay;
 
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
@@ -3646,8 +3676,8 @@
 		ret = selinux_parse_skb_ipv6(skb, ad, proto);
 		if (ret)
 			goto parse_error;
-		addrp = (char *)(src ? &ad->u.net.v6info.saddr :
-				       &ad->u.net.v6info.daddr);
+		addrp = (char *)(src ? &ad->u.net->v6info.saddr :
+				       &ad->u.net->v6info.daddr);
 		goto okay;
 #endif	/* IPV6 */
 	default:
@@ -3721,13 +3751,17 @@
 {
 	struct sk_security_struct *sksec = sk->sk_security;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
+	struct lsm_network_audit net = {0,};
 	u32 tsid = task_sid(task);
 
 	if (sksec->sid == SECINITSID_KERNEL)
 		return 0;
 
 	COMMON_AUDIT_DATA_INIT(&ad, NET);
-	ad.u.net.sk = sk;
+	ad.selinux_audit_data = &sad;
+	ad.u.net = &net;
+	ad.u.net->sk = sk;
 
 	return avc_has_perm(tsid, sksec->sid, sksec->sclass, perms, &ad);
 }
@@ -3805,6 +3839,8 @@
 		char *addrp;
 		struct sk_security_struct *sksec = sk->sk_security;
 		struct common_audit_data ad;
+		struct selinux_audit_data sad = {0,};
+		struct lsm_network_audit net = {0,};
 		struct sockaddr_in *addr4 = NULL;
 		struct sockaddr_in6 *addr6 = NULL;
 		unsigned short snum;
@@ -3831,8 +3867,10 @@
 				if (err)
 					goto out;
 				COMMON_AUDIT_DATA_INIT(&ad, NET);
-				ad.u.net.sport = htons(snum);
-				ad.u.net.family = family;
+				ad.selinux_audit_data = &sad;
+				ad.u.net = &net;
+				ad.u.net->sport = htons(snum);
+				ad.u.net->family = family;
 				err = avc_has_perm(sksec->sid, sid,
 						   sksec->sclass,
 						   SOCKET__NAME_BIND, &ad);
@@ -3864,13 +3902,15 @@
 			goto out;
 
 		COMMON_AUDIT_DATA_INIT(&ad, NET);
-		ad.u.net.sport = htons(snum);
-		ad.u.net.family = family;
+		ad.selinux_audit_data = &sad;
+		ad.u.net = &net;
+		ad.u.net->sport = htons(snum);
+		ad.u.net->family = family;
 
 		if (family == PF_INET)
-			ad.u.net.v4info.saddr = addr4->sin_addr.s_addr;
+			ad.u.net->v4info.saddr = addr4->sin_addr.s_addr;
 		else
-			ad.u.net.v6info.saddr = addr6->sin6_addr;
+			ad.u.net->v6info.saddr = addr6->sin6_addr;
 
 		err = avc_has_perm(sksec->sid, sid,
 				   sksec->sclass, node_perm, &ad);
@@ -3897,6 +3937,8 @@
 	if (sksec->sclass == SECCLASS_TCP_SOCKET ||
 	    sksec->sclass == SECCLASS_DCCP_SOCKET) {
 		struct common_audit_data ad;
+		struct selinux_audit_data sad = {0,};
+		struct lsm_network_audit net = {0,};
 		struct sockaddr_in *addr4 = NULL;
 		struct sockaddr_in6 *addr6 = NULL;
 		unsigned short snum;
@@ -3922,8 +3964,10 @@
 		       TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT;
 
 		COMMON_AUDIT_DATA_INIT(&ad, NET);
-		ad.u.net.dport = htons(snum);
-		ad.u.net.family = sk->sk_family;
+		ad.selinux_audit_data = &sad;
+		ad.u.net = &net;
+		ad.u.net->dport = htons(snum);
+		ad.u.net->family = sk->sk_family;
 		err = avc_has_perm(sksec->sid, sid, sksec->sclass, perm, &ad);
 		if (err)
 			goto out;
@@ -4012,10 +4056,14 @@
 	struct sk_security_struct *sksec_other = other->sk_security;
 	struct sk_security_struct *sksec_new = newsk->sk_security;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
+	struct lsm_network_audit net = {0,};
 	int err;
 
 	COMMON_AUDIT_DATA_INIT(&ad, NET);
-	ad.u.net.sk = other;
+	ad.selinux_audit_data = &sad;
+	ad.u.net = &net;
+	ad.u.net->sk = other;
 
 	err = avc_has_perm(sksec_sock->sid, sksec_other->sid,
 			   sksec_other->sclass,
@@ -4042,9 +4090,13 @@
 	struct sk_security_struct *ssec = sock->sk->sk_security;
 	struct sk_security_struct *osec = other->sk->sk_security;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
+	struct lsm_network_audit net = {0,};
 
 	COMMON_AUDIT_DATA_INIT(&ad, NET);
-	ad.u.net.sk = other->sk;
+	ad.selinux_audit_data = &sad;
+	ad.u.net = &net;
+	ad.u.net->sk = other->sk;
 
 	return avc_has_perm(ssec->sid, osec->sid, osec->sclass, SOCKET__SENDTO,
 			    &ad);
@@ -4080,11 +4132,15 @@
 	struct sk_security_struct *sksec = sk->sk_security;
 	u32 sk_sid = sksec->sid;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
+	struct lsm_network_audit net = {0,};
 	char *addrp;
 
 	COMMON_AUDIT_DATA_INIT(&ad, NET);
-	ad.u.net.netif = skb->skb_iif;
-	ad.u.net.family = family;
+	ad.selinux_audit_data = &sad;
+	ad.u.net = &net;
+	ad.u.net->netif = skb->skb_iif;
+	ad.u.net->family = family;
 	err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
 	if (err)
 		return err;
@@ -4111,6 +4167,8 @@
 	u16 family = sk->sk_family;
 	u32 sk_sid = sksec->sid;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
+	struct lsm_network_audit net = {0,};
 	char *addrp;
 	u8 secmark_active;
 	u8 peerlbl_active;
@@ -4135,8 +4193,10 @@
 		return 0;
 
 	COMMON_AUDIT_DATA_INIT(&ad, NET);
-	ad.u.net.netif = skb->skb_iif;
-	ad.u.net.family = family;
+	ad.selinux_audit_data = &sad;
+	ad.u.net = &net;
+	ad.u.net->netif = skb->skb_iif;
+	ad.u.net->family = family;
 	err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
 	if (err)
 		return err;
@@ -4471,6 +4531,8 @@
 	char *addrp;
 	u32 peer_sid;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
+	struct lsm_network_audit net = {0,};
 	u8 secmark_active;
 	u8 netlbl_active;
 	u8 peerlbl_active;
@@ -4488,8 +4550,10 @@
 		return NF_DROP;
 
 	COMMON_AUDIT_DATA_INIT(&ad, NET);
-	ad.u.net.netif = ifindex;
-	ad.u.net.family = family;
+	ad.selinux_audit_data = &sad;
+	ad.u.net = &net;
+	ad.u.net->netif = ifindex;
+	ad.u.net->family = family;
 	if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
 		return NF_DROP;
 
@@ -4576,6 +4640,8 @@
 	struct sock *sk = skb->sk;
 	struct sk_security_struct *sksec;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
+	struct lsm_network_audit net = {0,};
 	char *addrp;
 	u8 proto;
 
@@ -4584,8 +4650,10 @@
 	sksec = sk->sk_security;
 
 	COMMON_AUDIT_DATA_INIT(&ad, NET);
-	ad.u.net.netif = ifindex;
-	ad.u.net.family = family;
+	ad.selinux_audit_data = &sad;
+	ad.u.net = &net;
+	ad.u.net->netif = ifindex;
+	ad.u.net->family = family;
 	if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto))
 		return NF_DROP;
 
@@ -4607,6 +4675,8 @@
 	u32 peer_sid;
 	struct sock *sk;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
+	struct lsm_network_audit net = {0,};
 	char *addrp;
 	u8 secmark_active;
 	u8 peerlbl_active;
@@ -4653,8 +4723,10 @@
 	}
 
 	COMMON_AUDIT_DATA_INIT(&ad, NET);
-	ad.u.net.netif = ifindex;
-	ad.u.net.family = family;
+	ad.selinux_audit_data = &sad;
+	ad.u.net = &net;
+	ad.u.net->netif = ifindex;
+	ad.u.net->family = family;
 	if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL))
 		return NF_DROP;
 
@@ -4769,11 +4841,13 @@
 {
 	struct ipc_security_struct *isec;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 	u32 sid = current_sid();
 
 	isec = ipc_perms->security;
 
 	COMMON_AUDIT_DATA_INIT(&ad, IPC);
+	ad.selinux_audit_data = &sad;
 	ad.u.ipc_id = ipc_perms->key;
 
 	return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
@@ -4794,6 +4868,7 @@
 {
 	struct ipc_security_struct *isec;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 	u32 sid = current_sid();
 	int rc;
 
@@ -4804,6 +4879,7 @@
 	isec = msq->q_perm.security;
 
 	COMMON_AUDIT_DATA_INIT(&ad, IPC);
+	ad.selinux_audit_data = &sad;
 	ad.u.ipc_id = msq->q_perm.key;
 
 	rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
@@ -4824,11 +4900,13 @@
 {
 	struct ipc_security_struct *isec;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 	u32 sid = current_sid();
 
 	isec = msq->q_perm.security;
 
 	COMMON_AUDIT_DATA_INIT(&ad, IPC);
+	ad.selinux_audit_data = &sad;
 	ad.u.ipc_id = msq->q_perm.key;
 
 	return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
@@ -4868,6 +4946,7 @@
 	struct ipc_security_struct *isec;
 	struct msg_security_struct *msec;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 	u32 sid = current_sid();
 	int rc;
 
@@ -4889,6 +4968,7 @@
 	}
 
 	COMMON_AUDIT_DATA_INIT(&ad, IPC);
+	ad.selinux_audit_data = &sad;
 	ad.u.ipc_id = msq->q_perm.key;
 
 	/* Can this process write to the queue? */
@@ -4913,6 +4993,7 @@
 	struct ipc_security_struct *isec;
 	struct msg_security_struct *msec;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 	u32 sid = task_sid(target);
 	int rc;
 
@@ -4920,6 +5001,7 @@
 	msec = msg->security;
 
 	COMMON_AUDIT_DATA_INIT(&ad, IPC);
+	ad.selinux_audit_data = &sad;
 	ad.u.ipc_id = msq->q_perm.key;
 
 	rc = avc_has_perm(sid, isec->sid,
@@ -4935,6 +5017,7 @@
 {
 	struct ipc_security_struct *isec;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 	u32 sid = current_sid();
 	int rc;
 
@@ -4945,6 +5028,7 @@
 	isec = shp->shm_perm.security;
 
 	COMMON_AUDIT_DATA_INIT(&ad, IPC);
+	ad.selinux_audit_data = &sad;
 	ad.u.ipc_id = shp->shm_perm.key;
 
 	rc = avc_has_perm(sid, isec->sid, SECCLASS_SHM,
@@ -4965,11 +5049,13 @@
 {
 	struct ipc_security_struct *isec;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 	u32 sid = current_sid();
 
 	isec = shp->shm_perm.security;
 
 	COMMON_AUDIT_DATA_INIT(&ad, IPC);
+	ad.selinux_audit_data = &sad;
 	ad.u.ipc_id = shp->shm_perm.key;
 
 	return avc_has_perm(sid, isec->sid, SECCLASS_SHM,
@@ -5027,6 +5113,7 @@
 {
 	struct ipc_security_struct *isec;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 	u32 sid = current_sid();
 	int rc;
 
@@ -5037,6 +5124,7 @@
 	isec = sma->sem_perm.security;
 
 	COMMON_AUDIT_DATA_INIT(&ad, IPC);
+	ad.selinux_audit_data = &sad;
 	ad.u.ipc_id = sma->sem_perm.key;
 
 	rc = avc_has_perm(sid, isec->sid, SECCLASS_SEM,
@@ -5057,11 +5145,13 @@
 {
 	struct ipc_security_struct *isec;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 	u32 sid = current_sid();
 
 	isec = sma->sem_perm.security;
 
 	COMMON_AUDIT_DATA_INIT(&ad, IPC);
+	ad.selinux_audit_data = &sad;
 	ad.u.ipc_id = sma->sem_perm.key;
 
 	return avc_has_perm(sid, isec->sid, SECCLASS_SEM,
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h
index 005a91b..1931370 100644
--- a/security/selinux/include/avc.h
+++ b/security/selinux/include/avc.h
@@ -47,6 +47,31 @@
 };
 
 /*
+ * We only need this data after we have decided to send an audit message.
+ */
+struct selinux_late_audit_data {
+	u32 ssid;
+	u32 tsid;
+	u16 tclass;
+	u32 requested;
+	u32 audited;
+	u32 denied;
+	int result;
+};
+
+/*
+ * We collect this at the beginning or during an selinux security operation
+ */
+struct selinux_audit_data {
+	/*
+	 * auditdeny is a bit tricky and unintuitive.  See the
+	 * comments in avc.c for it's meaning and usage.
+	 */
+	u32 auditdeny;
+	struct selinux_late_audit_data *slad;
+};
+
+/*
  * AVC operations
  */
 
diff --git a/security/smack/smack.h b/security/smack/smack.h
index 2ad0065..4ede719 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -185,6 +185,15 @@
  */
 #define SMK_NUM_ACCESS_TYPE 5
 
+/* SMACK data */
+struct smack_audit_data {
+	const char *function;
+	char *subject;
+	char *object;
+	char *request;
+	int result;
+};
+
 /*
  * Smack audit data; is empty if CONFIG_AUDIT not set
  * to save some stack
@@ -192,6 +201,7 @@
 struct smk_audit_info {
 #ifdef CONFIG_AUDIT
 	struct common_audit_data a;
+	struct smack_audit_data sad;
 #endif
 };
 /*
@@ -311,7 +321,16 @@
 {
 	memset(a, 0, sizeof(*a));
 	a->a.type = type;
-	a->a.smack_audit_data.function = func;
+	a->a.smack_audit_data = &a->sad;
+	a->a.smack_audit_data->function = func;
+}
+
+static inline void smk_ad_init_net(struct smk_audit_info *a, const char *func,
+				   char type, struct lsm_network_audit *net)
+{
+	smk_ad_init(a, func, type);
+	memset(net, 0, sizeof(*net));
+	a->a.u.net = net;
 }
 
 static inline void smk_ad_setfield_u_tsk(struct smk_audit_info *a,
@@ -337,7 +356,7 @@
 static inline void smk_ad_setfield_u_net_sk(struct smk_audit_info *a,
 					    struct sock *sk)
 {
-	a->a.u.net.sk = sk;
+	a->a.u.net->sk = sk;
 }
 
 #else /* no AUDIT */
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c
index cc7cb6e..c8115f7 100644
--- a/security/smack/smack_access.c
+++ b/security/smack/smack_access.c
@@ -275,9 +275,9 @@
 static void smack_log_callback(struct audit_buffer *ab, void *a)
 {
 	struct common_audit_data *ad = a;
-	struct smack_audit_data *sad = &ad->smack_audit_data;
+	struct smack_audit_data *sad = ad->smack_audit_data;
 	audit_log_format(ab, "lsm=SMACK fn=%s action=%s",
-			 ad->smack_audit_data.function,
+			 ad->smack_audit_data->function,
 			 sad->result ? "denied" : "granted");
 	audit_log_format(ab, " subject=");
 	audit_log_untrustedstring(ab, sad->subject);
@@ -310,19 +310,19 @@
 	if (result == 0 && (log_policy & SMACK_AUDIT_ACCEPT) == 0)
 		return;
 
-	if (a->smack_audit_data.function == NULL)
-		a->smack_audit_data.function = "unknown";
+	sad = a->smack_audit_data;
+
+	if (sad->function == NULL)
+		sad->function = "unknown";
 
 	/* end preparing the audit data */
-	sad = &a->smack_audit_data;
 	smack_str_from_perm(request_buffer, request);
 	sad->subject = subject_label;
 	sad->object  = object_label;
 	sad->request = request_buffer;
 	sad->result  = result;
-	a->lsm_pre_audit = smack_log_callback;
 
-	common_lsm_audit(a);
+	common_lsm_audit(a, smack_log_callback, NULL);
 }
 #else /* #ifdef CONFIG_AUDIT */
 void smack_log(char *subject_label, char *object_label, int request,
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index cd667b4..81c03a5 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -1939,16 +1939,17 @@
 	char *hostsp;
 	struct socket_smack *ssp = sk->sk_security;
 	struct smk_audit_info ad;
+	struct lsm_network_audit net;
 
 	rcu_read_lock();
 	hostsp = smack_host_label(sap);
 	if (hostsp != NULL) {
 		sk_lbl = SMACK_UNLABELED_SOCKET;
 #ifdef CONFIG_AUDIT
-		smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET);
-		ad.a.u.net.family = sap->sin_family;
-		ad.a.u.net.dport = sap->sin_port;
-		ad.a.u.net.v4info.daddr = sap->sin_addr.s_addr;
+		smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
+		ad.a.u.net->family = sap->sin_family;
+		ad.a.u.net->dport = sap->sin_port;
+		ad.a.u.net->v4info.daddr = sap->sin_addr.s_addr;
 #endif
 		rc = smk_access(ssp->smk_out, hostsp, MAY_WRITE, &ad);
 	} else {
@@ -2808,9 +2809,10 @@
 	struct socket_smack *osp = other->sk_security;
 	struct socket_smack *nsp = newsk->sk_security;
 	struct smk_audit_info ad;
+	struct lsm_network_audit net;
 	int rc = 0;
 
-	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET);
+	smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
 	smk_ad_setfield_u_net_sk(&ad, other);
 
 	if (!capable(CAP_MAC_OVERRIDE))
@@ -2840,9 +2842,10 @@
 	struct socket_smack *ssp = sock->sk->sk_security;
 	struct socket_smack *osp = other->sk->sk_security;
 	struct smk_audit_info ad;
+	struct lsm_network_audit net;
 	int rc = 0;
 
-	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET);
+	smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
 	smk_ad_setfield_u_net_sk(&ad, other->sk);
 
 	if (!capable(CAP_MAC_OVERRIDE))
@@ -2990,6 +2993,7 @@
 	char *csp;
 	int rc;
 	struct smk_audit_info ad;
+	struct lsm_network_audit net;
 	if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6)
 		return 0;
 
@@ -3007,9 +3011,9 @@
 	netlbl_secattr_destroy(&secattr);
 
 #ifdef CONFIG_AUDIT
-	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET);
-	ad.a.u.net.family = sk->sk_family;
-	ad.a.u.net.netif = skb->skb_iif;
+	smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
+	ad.a.u.net->family = sk->sk_family;
+	ad.a.u.net->netif = skb->skb_iif;
 	ipv4_skb_to_auditdata(skb, &ad.a, NULL);
 #endif
 	/*
@@ -3152,6 +3156,7 @@
 	char *sp;
 	int rc;
 	struct smk_audit_info ad;
+	struct lsm_network_audit net;
 
 	/* handle mapped IPv4 packets arriving via IPv6 sockets */
 	if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
@@ -3166,9 +3171,9 @@
 	netlbl_secattr_destroy(&secattr);
 
 #ifdef CONFIG_AUDIT
-	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET);
-	ad.a.u.net.family = family;
-	ad.a.u.net.netif = skb->skb_iif;
+	smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
+	ad.a.u.net->family = family;
+	ad.a.u.net->netif = skb->skb_iif;
 	ipv4_skb_to_auditdata(skb, &ad.a, NULL);
 #endif
 	/*