From: Darrel Goeddel <[EMAIL PROTECTED]>

This patch encapsulates the usage of eff_cap (in netlink_skb_params) within
the security framework by extending security_netlink_recv to include a required
capability parameter and converting all direct usage of eff_caps outside
of the lsm modules to use the interface.  It also updates the SELinux
implementation of the security_netlink_send and security_netlink_recv
hooks to take advantage of the sid in the netlink_skb_params struct.
This also enables SELinux to perform auditing of netlink capability checks.
Please apply, for 2.6.18 if possible.

Signed-off-by: Darrel Goeddel <[EMAIL PROTECTED]>
Signed-off-by: Stephen Smalley <[EMAIL PROTECTED]>
Acked-by:  James Morris <[EMAIL PROTECTED]>

---

 include/linux/security.h        |   13 +++++++------
 kernel/audit.c                  |    8 ++++----
 net/core/rtnetlink.c            |    2 +-
 net/decnet/netfilter/dn_rtmsg.c |    2 +-
 net/ipv4/netfilter/ip_queue.c   |    2 +-
 net/ipv6/netfilter/ip6_queue.c  |    2 +-
 net/netfilter/nfnetlink.c       |    2 +-
 net/netlink/genetlink.c         |    2 +-
 net/xfrm/xfrm_user.c            |    2 +-
 security/commoncap.c            |    4 ++--
 security/dummy.c                |    4 ++--
 security/selinux/hooks.c        |   26 +++++++++++++-------------
 12 files changed, 35 insertions(+), 34 deletions(-)

diff -X /home/sds/dontdiff -rup linux-2.6.17-git10/include/linux/security.h 
linux-2.6.17-git10-ss2/include/linux/security.h
--- linux-2.6.17-git10/include/linux/security.h 2006-06-26 09:34:30.000000000 
-0400
+++ linux-2.6.17-git10-ss2/include/linux/security.h     2006-06-26 
09:50:59.000000000 -0400
@@ -67,7 +67,7 @@ struct xfrm_state;
 struct xfrm_user_sec_ctx;
 
 extern int cap_netlink_send(struct sock *sk, struct sk_buff *skb);
-extern int cap_netlink_recv(struct sk_buff *skb);
+extern int cap_netlink_recv(struct sk_buff *skb, int cap);
 
 /*
  * Values used in the task_security_ops calls
@@ -656,6 +656,7 @@ struct swap_info_struct;
  *     Check permission before processing the received netlink message in
  *     @skb.
  *     @skb contains the sk_buff structure for the netlink message.
+ *     @cap indicates the capability required
  *     Return 0 if permission is granted.
  *
  * Security hooks for Unix domain networking.
@@ -1265,7 +1266,7 @@ struct security_operations {
                          struct sembuf * sops, unsigned nsops, int alter);
 
        int (*netlink_send) (struct sock * sk, struct sk_buff * skb);
-       int (*netlink_recv) (struct sk_buff * skb);
+       int (*netlink_recv) (struct sk_buff * skb, int cap);
 
        /* allow module stacking */
        int (*register_security) (const char *name,
@@ -2031,9 +2032,9 @@ static inline int security_netlink_send(
        return security_ops->netlink_send(sk, skb);
 }
 
-static inline int security_netlink_recv(struct sk_buff * skb)
+static inline int security_netlink_recv(struct sk_buff * skb, int cap)
 {
-       return security_ops->netlink_recv(skb);
+       return security_ops->netlink_recv(skb, cap);
 }
 
 /* prototypes */
@@ -2669,9 +2670,9 @@ static inline int security_netlink_send 
        return cap_netlink_send (sk, skb);
 }
 
-static inline int security_netlink_recv (struct sk_buff *skb)
+static inline int security_netlink_recv (struct sk_buff *skb, int cap)
 {
-       return cap_netlink_recv (skb);
+       return cap_netlink_recv (skb, cap);
 }
 
 static inline struct dentry *securityfs_create_dir(const char *name,
diff -X /home/sds/dontdiff -rup linux-2.6.17-git10/kernel/audit.c 
linux-2.6.17-git10-ss2/kernel/audit.c
--- linux-2.6.17-git10/kernel/audit.c   2006-06-26 09:34:30.000000000 -0400
+++ linux-2.6.17-git10-ss2/kernel/audit.c       2006-06-26 09:50:59.000000000 
-0400
@@ -445,7 +445,7 @@ void audit_send_reply(int pid, int seq, 
  * Check for appropriate CAP_AUDIT_ capabilities on incoming audit
  * control messages.
  */
-static int audit_netlink_ok(kernel_cap_t eff_cap, u16 msg_type)
+static int audit_netlink_ok(struct sk_buff *skb, u16 msg_type)
 {
        int err = 0;
 
@@ -459,13 +459,13 @@ static int audit_netlink_ok(kernel_cap_t
        case AUDIT_DEL:
        case AUDIT_DEL_RULE:
        case AUDIT_SIGNAL_INFO:
-               if (!cap_raised(eff_cap, CAP_AUDIT_CONTROL))
+               if (security_netlink_recv(skb, CAP_AUDIT_CONTROL))
                        err = -EPERM;
                break;
        case AUDIT_USER:
        case AUDIT_FIRST_USER_MSG...AUDIT_LAST_USER_MSG:
        case AUDIT_FIRST_USER_MSG2...AUDIT_LAST_USER_MSG2:
-               if (!cap_raised(eff_cap, CAP_AUDIT_WRITE))
+               if (security_netlink_recv(skb, CAP_AUDIT_WRITE))
                        err = -EPERM;
                break;
        default:  /* bad msg */
@@ -488,7 +488,7 @@ static int audit_receive_msg(struct sk_b
        char                    *ctx;
        u32                     len;
 
-       err = audit_netlink_ok(NETLINK_CB(skb).eff_cap, msg_type);
+       err = audit_netlink_ok(skb, msg_type);
        if (err)
                return err;
 
diff -X /home/sds/dontdiff -rup linux-2.6.17-git10/net/core/rtnetlink.c 
linux-2.6.17-git10-ss2/net/core/rtnetlink.c
--- linux-2.6.17-git10/net/core/rtnetlink.c     2006-06-26 09:34:30.000000000 
-0400
+++ linux-2.6.17-git10-ss2/net/core/rtnetlink.c 2006-06-26 09:50:59.000000000 
-0400
@@ -663,7 +663,7 @@ rtnetlink_rcv_msg(struct sk_buff *skb, s
        sz_idx = type>>2;
        kind = type&3;
 
-       if (kind != 2 && security_netlink_recv(skb)) {
+       if (kind != 2 && security_netlink_recv(skb, CAP_NET_ADMIN)) {
                *errp = -EPERM;
                return -1;
        }
diff -X /home/sds/dontdiff -rup 
linux-2.6.17-git10/net/decnet/netfilter/dn_rtmsg.c 
linux-2.6.17-git10-ss2/net/decnet/netfilter/dn_rtmsg.c
--- linux-2.6.17-git10/net/decnet/netfilter/dn_rtmsg.c  2006-06-26 
09:34:30.000000000 -0400
+++ linux-2.6.17-git10-ss2/net/decnet/netfilter/dn_rtmsg.c      2006-06-26 
09:50:59.000000000 -0400
@@ -107,7 +107,7 @@ static inline void dnrmg_receive_user_sk
        if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len)
                return;
 
-       if (!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN))
+       if (security_netlink_recv(skb, CAP_NET_ADMIN))
                RCV_SKB_FAIL(-EPERM);
 
        /* Eventually we might send routing messages too */
diff -X /home/sds/dontdiff -rup 
linux-2.6.17-git10/net/ipv4/netfilter/ip_queue.c 
linux-2.6.17-git10-ss2/net/ipv4/netfilter/ip_queue.c
--- linux-2.6.17-git10/net/ipv4/netfilter/ip_queue.c    2006-06-26 
09:34:30.000000000 -0400
+++ linux-2.6.17-git10-ss2/net/ipv4/netfilter/ip_queue.c        2006-06-26 
09:50:59.000000000 -0400
@@ -507,7 +507,7 @@ ipq_rcv_skb(struct sk_buff *skb)
        if (type <= IPQM_BASE)
                return;
                
-       if (security_netlink_recv(skb))
+       if (security_netlink_recv(skb, CAP_NET_ADMIN))
                RCV_SKB_FAIL(-EPERM);
        
        write_lock_bh(&queue_lock);
diff -X /home/sds/dontdiff -rup 
linux-2.6.17-git10/net/ipv6/netfilter/ip6_queue.c 
linux-2.6.17-git10-ss2/net/ipv6/netfilter/ip6_queue.c
--- linux-2.6.17-git10/net/ipv6/netfilter/ip6_queue.c   2006-06-26 
09:34:30.000000000 -0400
+++ linux-2.6.17-git10-ss2/net/ipv6/netfilter/ip6_queue.c       2006-06-26 
09:50:59.000000000 -0400
@@ -505,7 +505,7 @@ ipq_rcv_skb(struct sk_buff *skb)
        if (type <= IPQM_BASE)
                return;
        
-       if (security_netlink_recv(skb))
+       if (security_netlink_recv(skb, CAP_NET_ADMIN))
                RCV_SKB_FAIL(-EPERM);   
 
        write_lock_bh(&queue_lock);
diff -X /home/sds/dontdiff -rup linux-2.6.17-git10/net/netfilter/nfnetlink.c 
linux-2.6.17-git10-ss2/net/netfilter/nfnetlink.c
--- linux-2.6.17-git10/net/netfilter/nfnetlink.c        2006-06-26 
09:34:30.000000000 -0400
+++ linux-2.6.17-git10-ss2/net/netfilter/nfnetlink.c    2006-06-26 
09:50:59.000000000 -0400
@@ -229,7 +229,7 @@ static int nfnetlink_rcv_msg(struct sk_b
                 NFNL_SUBSYS_ID(nlh->nlmsg_type),
                 NFNL_MSG_TYPE(nlh->nlmsg_type));
 
-       if (!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN)) {
+       if (security_netlink_recv(skb, CAP_NET_ADMIN)) {
                DEBUGP("missing CAP_NET_ADMIN\n");
                *errp = -EPERM;
                return -1;
diff -X /home/sds/dontdiff -rup linux-2.6.17-git10/net/netlink/genetlink.c 
linux-2.6.17-git10-ss2/net/netlink/genetlink.c
--- linux-2.6.17-git10/net/netlink/genetlink.c  2006-06-26 09:34:30.000000000 
-0400
+++ linux-2.6.17-git10-ss2/net/netlink/genetlink.c      2006-06-26 
09:50:59.000000000 -0400
@@ -320,7 +320,7 @@ static int genl_rcv_msg(struct sk_buff *
                goto errout;
        }
 
-       if ((ops->flags & GENL_ADMIN_PERM) && security_netlink_recv(skb)) {
+       if ((ops->flags & GENL_ADMIN_PERM) && security_netlink_recv(skb, 
CAP_NET_ADMIN)) {
                err = -EPERM;
                goto errout;
        }
diff -X /home/sds/dontdiff -rup linux-2.6.17-git10/net/xfrm/xfrm_user.c 
linux-2.6.17-git10-ss2/net/xfrm/xfrm_user.c
--- linux-2.6.17-git10/net/xfrm/xfrm_user.c     2006-06-26 09:34:30.000000000 
-0400
+++ linux-2.6.17-git10-ss2/net/xfrm/xfrm_user.c 2006-06-26 09:50:59.000000000 
-0400
@@ -1435,7 +1435,7 @@ static int xfrm_user_rcv_msg(struct sk_b
        link = &xfrm_dispatch[type];
 
        /* All operations require privileges, even GET */
-       if (security_netlink_recv(skb)) {
+       if (security_netlink_recv(skb, CAP_NET_ADMIN)) {
                *errp = -EPERM;
                return -1;
        }
diff -X /home/sds/dontdiff -rup linux-2.6.17-git10/security/commoncap.c 
linux-2.6.17-git10-ss2/security/commoncap.c
--- linux-2.6.17-git10/security/commoncap.c     2006-06-26 09:34:30.000000000 
-0400
+++ linux-2.6.17-git10-ss2/security/commoncap.c 2006-06-26 09:50:59.000000000 
-0400
@@ -33,9 +33,9 @@ int cap_netlink_send(struct sock *sk, st
 
 EXPORT_SYMBOL(cap_netlink_send);
 
-int cap_netlink_recv(struct sk_buff *skb)
+int cap_netlink_recv(struct sk_buff *skb, int cap)
 {
-       if (!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN))
+       if (!cap_raised(NETLINK_CB(skb).eff_cap, cap))
                return -EPERM;
        return 0;
 }
diff -X /home/sds/dontdiff -rup linux-2.6.17-git10/security/dummy.c 
linux-2.6.17-git10-ss2/security/dummy.c
--- linux-2.6.17-git10/security/dummy.c 2006-06-26 09:34:30.000000000 -0400
+++ linux-2.6.17-git10-ss2/security/dummy.c     2006-06-26 09:50:59.000000000 
-0400
@@ -675,9 +675,9 @@ static int dummy_netlink_send (struct so
        return 0;
 }
 
-static int dummy_netlink_recv (struct sk_buff *skb)
+static int dummy_netlink_recv (struct sk_buff *skb, int cap)
 {
-       if (!cap_raised (NETLINK_CB (skb).eff_cap, CAP_NET_ADMIN))
+       if (!cap_raised (NETLINK_CB (skb).eff_cap, cap))
                return -EPERM;
        return 0;
 }
diff -X /home/sds/dontdiff -rup linux-2.6.17-git10/security/selinux/hooks.c 
linux-2.6.17-git10-ss2/security/selinux/hooks.c
--- linux-2.6.17-git10/security/selinux/hooks.c 2006-06-26 10:34:54.000000000 
-0400
+++ linux-2.6.17-git10-ss2/security/selinux/hooks.c     2006-06-26 
09:50:59.000000000 -0400
@@ -3622,32 +3622,32 @@ static unsigned int selinux_ipv6_postrou
 
 static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
 {
-       struct task_security_struct *tsec;
-       struct av_decision avd;
        int err;
 
        err = secondary_ops->netlink_send(sk, skb);
        if (err)
                return err;
 
-       tsec = current->security;
-
-       avd.allowed = 0;
-       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);
 
        return err;
 }
 
-static int selinux_netlink_recv(struct sk_buff *skb)
+static int selinux_netlink_recv(struct sk_buff *skb, int capability)
 {
-       if (!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN))
-               return -EPERM;
-       return 0;
+       int err;
+       struct avc_audit_data ad;
+
+       err = secondary_ops->netlink_recv(skb, capability);
+       if (err)
+               return err;
+
+       AVC_AUDIT_DATA_INIT(&ad, CAP);
+       ad.u.cap = capability;
+
+       return avc_has_perm(NETLINK_CB(skb).sid, NETLINK_CB(skb).sid,
+                           SECCLASS_CAPABILITY, CAP_TO_MASK(capability), &ad);
 }
 
 static int ipc_alloc_security(struct task_struct *task,

-- 
Stephen Smalley
National Security Agency

-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to