Index: linux-2.6.9/include/linux/netlink.h =================================================================== --- linux-2.6.9.orig/include/linux/netlink.h 2004-12-02 16:08:23.000000000 -0600 +++ linux-2.6.9/include/linux/netlink.h 2004-12-02 16:14:17.000000000 -0600 @@ -120,6 +120,7 @@ extern void netlink_detach(int unit); extern int netlink_post(int unit, struct sk_buff *skb); extern struct sock *netlink_kernel_create(int unit, void (*input)(struct sock *sk, int len)); +extern int netlink_get_msgtype(struct sk_buff *skb); extern void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err); extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 pid, int nonblock); extern int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 pid, Index: linux-2.6.9/kernel/audit.c =================================================================== --- linux-2.6.9.orig/kernel/audit.c 2004-12-02 16:02:22.000000000 -0600 +++ linux-2.6.9/kernel/audit.c 2004-12-02 17:44:06.000000000 -0600 @@ -327,8 +327,8 @@ &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); @@ -364,8 +364,8 @@ 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 +384,12 @@ 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); Index: linux-2.6.9/kernel/auditsc.c =================================================================== --- linux-2.6.9.orig/kernel/auditsc.c 2004-12-02 16:02:22.000000000 -0600 +++ linux-2.6.9/kernel/auditsc.c 2004-12-02 16:14:17.000000000 -0600 @@ -250,8 +250,6 @@ 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)) { Index: linux-2.6.9/net/netlink/af_netlink.c =================================================================== --- linux-2.6.9.orig/net/netlink/af_netlink.c 2004-12-02 16:09:27.000000000 -0600 +++ linux-2.6.9/net/netlink/af_netlink.c 2004-12-02 16:14:17.000000000 -0600 @@ -518,6 +518,15 @@ return err; } +int netlink_get_msgtype(struct sk_buff *skb) +{ + struct nlmsghdr *nlh = (struct nlmsghdr *)skb->data; + + if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len) + return -EINVAL; + return nlh->nlmsg_type; +} + static int netlink_getname(struct socket *sock, struct sockaddr *addr, int *addr_len, int peer) { struct sock *sk = sock->sk; @@ -1511,6 +1520,7 @@ MODULE_ALIAS_NETPROTO(PF_NETLINK); +EXPORT_SYMBOL(netlink_get_msgtype); EXPORT_SYMBOL(netlink_ack); EXPORT_SYMBOL(netlink_broadcast); EXPORT_SYMBOL(netlink_dump_start); Index: linux-2.6.9/security/commoncap.c =================================================================== --- linux-2.6.9.orig/security/commoncap.c 2004-12-02 16:08:24.000000000 -0600 +++ linux-2.6.9/security/commoncap.c 2004-12-02 18:13:34.150122064 -0600 @@ -23,11 +23,41 @@ #include #include #include +#include + +static int cap_netlink_audit_check (struct sk_buff *skb) +{ + int msgtype = netlink_get_msgtype(skb); + + switch(msgtype) { + case 0: /* not an audit msg */ + + case AUDIT_LIST: + return 0; + + case AUDIT_SET: + case AUDIT_USER: + case AUDIT_LOGIN: + + case AUDIT_ADD: + case AUDIT_DEL: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + return 0; + + default: /* permission denied: bad msg */ + return msgtype; + } +} + +EXPORT_SYMBOL(cap_netlink_audit_check); int cap_netlink_send(struct sock *sk, struct sk_buff *skb) { NETLINK_CB(skb).eff_cap = current->cap_effective; - return 0; + if (sk->sk_protocol != NETLINK_AUDIT) + return 0; + return cap_netlink_audit_check(skb); } EXPORT_SYMBOL(cap_netlink_send); Index: linux-2.6.9/security/dummy.c =================================================================== --- linux-2.6.9.orig/security/dummy.c 2004-12-02 16:08:24.000000000 -0600 +++ linux-2.6.9/security/dummy.c 2004-12-02 18:08:52.966868416 -0600 @@ -726,13 +726,40 @@ return 0; } +static int dummy_netlink_audit_check (struct sk_buff *skb) +{ + int msgtype = netlink_get_msgtype(skb); + + switch(msgtype) { + case 0: /* not an audit msg */ + + case AUDIT_LIST: + return 0; + + case AUDIT_SET: + case AUDIT_USER: + case AUDIT_LOGIN: + + case AUDIT_ADD: + case AUDIT_DEL: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + return 0; + + default: /* permission denied: bad msg */ + return msgtype; + } +} + static int dummy_netlink_send (struct sock *sk, struct sk_buff *skb) { if (current->euid == 0) cap_raise (NETLINK_CB (skb).eff_cap, CAP_NET_ADMIN); else NETLINK_CB (skb).eff_cap = 0; - return 0; + if (sk->sk_protocol != NETLINK_AUDIT) + return 0; + return dummy_netlink_audit_check(skb); } static int dummy_netlink_recv (struct sk_buff *skb)