diff -Nrup /home/hallyn/kernels/linux-2.6.8.1/include/linux/audit.h linux-2.6.8.1-auditfix/include/linux/audit.h
--- /home/hallyn/kernels/linux-2.6.8.1/include/linux/audit.h	2004-08-14 05:55:32.000000000 -0500
+++ linux-2.6.8.1-auditfix/include/linux/audit.h	2004-09-17 10:59:20.389060392 -0500
@@ -165,6 +165,15 @@ extern int  audit_set_loginuid(struct au
 #define audit_inode(n,i,d) do { ; } while (0)
 #endif
 
+#if defined(CONFIG_AUDIT) && defined(CONFIG_NET)
+/* For use by LSMs granting audit controls */
+struct sock;
+struct sk_buff;
+extern int audit_get_msgtype(struct sock *sk, struct sk_buff *skb);
+#else
+#define audit_get_msgtype(sk,skb) ({ 0; })
+#endif
+
 #ifdef CONFIG_AUDIT
 /* These are defined in audit.c */
 				/* Public API */
diff -Nrup /home/hallyn/kernels/linux-2.6.8.1/include/linux/security.h linux-2.6.8.1-auditfix/include/linux/security.h
--- /home/hallyn/kernels/linux-2.6.8.1/include/linux/security.h	2004-08-14 05:55:48.000000000 -0500
+++ linux-2.6.8.1-auditfix/include/linux/security.h	2004-09-17 09:39:15.000000000 -0500
@@ -53,10 +53,38 @@ extern void cap_task_reparent_to_init (s
 extern int cap_syslog (int type);
 extern int cap_vm_enough_memory (long pages);
 
+static inline int cap_netlink_auditcheck (struct sock *sk, struct sk_buff *skb)
+{
+	int msgtype = audit_get_msgtype(sk, skb);
+
+	switch(msgtype) {
+		case 0:   /* not an audit msg */
+			return 0;
+		case AUDIT_SET:
+		case AUDIT_USER:
+		case AUDIT_LOGIN:
+			if (!capable(CAP_SYS_ADMIN))
+				return -EPERM;
+			return 0;
+
+		case AUDIT_LIST:
+			return 0;
+
+		case AUDIT_ADD:
+		case AUDIT_DEL:
+			if (!capable(CAP_SYS_ADMIN))
+				return -EPERM;
+			return 0;
+
+		default:  /* permission denied: bad msg */
+			return msgtype;
+	}
+}
+
 static inline int cap_netlink_send (struct sock *sk, struct sk_buff *skb)
 {
 	NETLINK_CB (skb).eff_cap = current->cap_effective;
-	return 0;
+	return cap_netlink_auditcheck(sk, skb);
 }
 
 static inline int cap_netlink_recv (struct sk_buff *skb)
diff -Nrup /home/hallyn/kernels/linux-2.6.8.1/kernel/audit.c linux-2.6.8.1-auditfix/kernel/audit.c
--- /home/hallyn/kernels/linux-2.6.8.1/kernel/audit.c	2004-08-14 05:56:24.000000000 -0500
+++ linux-2.6.8.1-auditfix/kernel/audit.c	2004-09-17 09:39:00.000000000 -0500
@@ -327,8 +327,8 @@ static int audit_receive_msg(struct sk_b
 				 &status_set, sizeof(status_set));
 		break;
 	case AUDIT_SET:
-		if (!capable(CAP_SYS_ADMIN))
-			return -EPERM;
+		if (nlh->nlmsg_len < sizeof(struct audit_status))
+			return -EINVAL;
 		status_get   = (struct audit_status *)data;
 		if (status_get->mask & AUDIT_STATUS_ENABLED) {
 			err = audit_set_enabled(status_get->enabled);
@@ -353,6 +353,7 @@ static int audit_receive_msg(struct sk_b
 		ab = audit_log_start(NULL);
 		if (!ab)
 			break;	/* audit_panic has been called */
+		/* what kind of check do we want to do on length of "data"? */
 		audit_log_format(ab,
 				 "user pid=%d uid=%d length=%d msg='%.1024s'",
 				 pid, uid,
@@ -364,8 +365,8 @@ static int audit_receive_msg(struct sk_b
 		audit_log_end(ab);
 		break;
 	case AUDIT_LOGIN:
-		if (!capable(CAP_SYS_ADMIN))
-			return -EPERM;
+		if (nlh->nlmsg_len < sizeof(struct audit_login))
+			return -EINVAL;
 		login = (struct audit_login *)data;
 		ab = audit_log_start(NULL);
 		if (ab) {
@@ -384,9 +385,12 @@ static int audit_receive_msg(struct sk_b
 					 login->loginuid);
 #endif
 		break;
-	case AUDIT_LIST:
 	case AUDIT_ADD:
 	case AUDIT_DEL:
+		if (nlh->nlmsg_len < sizeof(struct audit_rule))
+			return -EINVAL;
+		/* fallthrough */
+	case AUDIT_LIST:
 #ifdef CONFIG_AUDITSYSCALL
 		err = audit_receive_filter(nlh->nlmsg_type, pid, uid, seq,
 					   data);
@@ -537,6 +541,24 @@ int __init audit_init(void)
 	return 0;
 }
 
+/* For use by LSMs granting audit controls */
+int audit_get_msgtype(struct sock *sk, struct sk_buff *skb)
+{
+	struct nlmsghdr *nlh;
+
+	if (sk->sk_protocol != NETLINK_AUDIT)
+		return 0;
+
+	if (skb->len < NLMSG_SPACE(0))
+		return -EINVAL;
+
+	nlh = (struct nlmsghdr *)skb->data;
+	if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len)
+		return -EINVAL;
+	return nlh->nlmsg_type;
+}
+
+EXPORT_SYMBOL_GPL(audit_get_msgtype);
 #else
 /* Without CONFIG_NET, we have no skbuffs.  For now, print what we have
  * in the buffer. */
diff -Nrup /home/hallyn/kernels/linux-2.6.8.1/kernel/auditsc.c linux-2.6.8.1-auditfix/kernel/auditsc.c
--- /home/hallyn/kernels/linux-2.6.8.1/kernel/auditsc.c	2004-08-14 05:55:48.000000000 -0500
+++ linux-2.6.8.1-auditfix/kernel/auditsc.c	2004-09-17 08:58:36.000000000 -0500
@@ -250,8 +250,6 @@ int audit_receive_filter(int type, int p
 		audit_send_reply(pid, seq, AUDIT_LIST, 1, 1, NULL, 0);
 		break;
 	case AUDIT_ADD:
-		if (!capable(CAP_SYS_ADMIN))
-			return -EPERM;
 		if (!(entry = kmalloc(sizeof(*entry), GFP_KERNEL)))
 			return -ENOMEM;
 		if (audit_copy_rule(&entry->rule, data)) {
diff -Nrup /home/hallyn/kernels/linux-2.6.8.1/security/dummy.c linux-2.6.8.1-auditfix/security/dummy.c
--- /home/hallyn/kernels/linux-2.6.8.1/security/dummy.c	2004-08-14 05:54:51.000000000 -0500
+++ linux-2.6.8.1-auditfix/security/dummy.c	2004-09-17 09:08:02.000000000 -0500
@@ -726,7 +726,7 @@ static int dummy_netlink_send (struct so
 		cap_raise (NETLINK_CB (skb).eff_cap, CAP_NET_ADMIN);
 	else
 		NETLINK_CB (skb).eff_cap = 0;
-	return 0;
+	return cap_netlink_auditcheck(sk, skb);
 }
 
 static int dummy_netlink_recv (struct sk_buff *skb)
