Audit capability patch
Serge E. Hallyn
serue at us.ibm.com
Fri Jan 14 21:43:53 UTC 2005
Thanks. New patch attached.
Changelog:
1/14/2005: remove redundant message length checks.
1/14/2005: return -EINVAL on non-audit message
1/14/2005: return -EINVAL on non-audit message
1/14/2005: removed/inlined netlink_get_msgtype() function.
-serge
Quoting Stephen Smalley (sds at epoch.ncsc.mil):
> On Fri, 2005-01-14 at 13:07, Stephen Smalley wrote:
> > On Fri, 2005-01-14 at 12:52, Serge Hallyn wrote:
> > > Attached is a "final" version of the audit caps patch. I will send this
> > > to lkml tomorrow if noone complains.
> >
> > As Darrel noted earlier, the skb->len and nlh->nlmsg_len checks are
> > already performed by audit_receive_skb() prior to calling
> > audit_receive_msg(), so you don't need them in audit_netlink_ok(),
> > right? And as he noted, you can just pass the nlh->nlmsg_type directly
> > from audit_receive_msg() to audit_netlink_ok(), you don't need to
> > re-extract it.
>
> Also, I think you want to remove the case 0 from the switch statement in
> audit_netlink_ok, so that it will use the default case and return
> -EINVAL rather than proceeding.
>
> --
> Stephen Smalley <sds at epoch.ncsc.mil>
> National Security Agency
>
> --
> Linux-audit mailing list
> Linux-audit at redhat.com
> http://www.redhat.com/mailman/listinfo/linux-audit
-------------- next part --------------
Index: linux-2.6.10/include/linux/capability.h
===================================================================
--- linux-2.6.10.orig/include/linux/capability.h 2004-12-24 15:34:27.000000000 -0600
+++ linux-2.6.10/include/linux/capability.h 2005-01-14 10:50:13.000000000 -0600
@@ -284,6 +284,10 @@ typedef __u32 kernel_cap_t;
#define CAP_LEASE 28
+#define CAP_AUDIT_WRITE 29
+
+#define CAP_AUDIT_CONTROL 30
+
#ifdef __KERNEL__
/*
* Bounding set
Index: linux-2.6.10/kernel/audit.c
===================================================================
--- linux-2.6.10.orig/kernel/audit.c 2005-01-14 10:49:06.000000000 -0600
+++ linux-2.6.10/kernel/audit.c 2005-01-14 16:28:55.000000000 -0600
@@ -300,21 +300,61 @@ nlmsg_failure: /* Used by NLMSG_PUT */
kfree_skb(skb);
}
+/*
+ * This function causes two checks on the incoming audit control
+ * message. 1. netlink_get_msgtype() will perform a length check,
+ * and 2. we check for CAP_AUDIT perms on a message which might
+ * change audit params.
+ */
+int audit_netlink_ok(struct sk_buff *skb, u16 msg_type)
+{
+ int err = 0;
+
+ switch(msg_type) {
+ case AUDIT_GET:
+ case AUDIT_LIST:
+ case AUDIT_SET:
+ case AUDIT_LOGIN:
+ case AUDIT_ADD:
+ case AUDIT_DEL:
+ if (!cap_raised(NETLINK_CB (skb).eff_cap,
+ CAP_AUDIT_CONTROL))
+ err = -EPERM;
+ break;
+
+ case AUDIT_USER:
+ if (!cap_raised(NETLINK_CB (skb).eff_cap,
+ CAP_AUDIT_WRITE))
+ err = -EPERM;
+ break;
+
+ default: /* permission denied: bad msg */
+ err = -EINVAL;
+ }
+
+ return err;
+}
+
static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
{
u32 uid, pid, seq;
void *data;
struct audit_status *status_get, status_set;
struct audit_login *login;
- int err = 0;
+ int err;
struct audit_buffer *ab;
+ u16 msg_type = nlh->nlmsg_type;
+
+ err = audit_netlink_ok(skb, msg_type);
+ if (err)
+ return err;
pid = NETLINK_CREDS(skb)->pid;
uid = NETLINK_CREDS(skb)->uid;
seq = nlh->nlmsg_seq;
data = NLMSG_DATA(nlh);
- switch (nlh->nlmsg_type) {
+ switch (msg_type) {
case AUDIT_GET:
status_set.enabled = audit_enabled;
status_set.failure = audit_failure;
@@ -327,8 +367,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);
@@ -364,8 +404,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 +424,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);
@@ -394,7 +437,7 @@ static int audit_receive_msg(struct sk_b
err = -EOPNOTSUPP;
#endif
break;
- default:
+ default: /* no longer needed... */
err = -EINVAL;
break;
}
Index: linux-2.6.10/kernel/auditsc.c
===================================================================
--- linux-2.6.10.orig/kernel/auditsc.c 2005-01-14 10:50:09.000000000 -0600
+++ linux-2.6.10/kernel/auditsc.c 2005-01-14 16:07:32.000000000 -0600
@@ -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)) {
Index: linux-2.6.10/security/dummy.c
===================================================================
--- linux-2.6.10.orig/security/dummy.c 2005-01-14 10:49:07.000000000 -0600
+++ linux-2.6.10/security/dummy.c 2005-01-14 10:50:13.000000000 -0600
@@ -685,10 +685,11 @@ static int dummy_sem_semop (struct sem_a
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;
+ kernel_cap_t dummy_cap, eff_cap;
+
+ dummy_capget(current, &eff_cap, &dummy_cap, &dummy_cap);
+ NETLINK_CB (skb).eff_cap = eff_cap;
+
return 0;
}
Index: linux-2.6.10/security/selinux/hooks.c
===================================================================
--- linux-2.6.10.orig/security/selinux/hooks.c 2005-01-14 10:49:07.000000000 -0600
+++ linux-2.6.10/security/selinux/hooks.c 2005-01-14 10:50:13.000000000 -0600
@@ -3502,12 +3502,20 @@ static inline int selinux_nlmsg_perm(str
static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
{
- int err = 0;
+ struct task_security_struct *tsec;
+ struct av_decision avd;
+ int err;
- if (capable(CAP_NET_ADMIN))
- cap_raise (NETLINK_CB (skb).eff_cap, CAP_NET_ADMIN);
- else
- NETLINK_CB(skb).eff_cap = 0;
+ err = secondary_ops->netlink_send(sk, skb);
+ if (err)
+ return err;
+
+ tsec = current->security;
+
+ avd.allowed = 0;
+ (void)avc_has_perm_noaudit(tsec->sid, tsec->sid,
+ SECCLASS_CAPABILITY, ~0, &avd);
+ cap_mask(NETLINK_CB(skb).eff_cap, avd.allowed);
if (policydb_loaded_version >= POLICYDB_VERSION_NLCLASS)
err = selinux_nlmsg_perm(sk, skb);
More information about the Linux-audit
mailing list