aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDarrel Goeddel <dgoeddel@trustedcs.com>2006-06-27 16:26:11 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2006-06-29 19:57:55 -0400
commitc7bdb545d23026b18be53289fd866d1ac07f5f8c (patch)
tree6d9a218871d88f7579dd53f14692df2529b6e712
parent576a30eb6453439b3c37ba24455ac7090c247b5a (diff)
[NETLINK]: Encapsulate eff_cap usage within security framework.
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 <dgoeddel@trustedcs.com> Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov> Acked-by: James Morris <jmorris@namei.org> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/security.h13
-rw-r--r--kernel/audit.c8
-rw-r--r--net/core/rtnetlink.c2
-rw-r--r--net/decnet/netfilter/dn_rtmsg.c2
-rw-r--r--net/ipv4/netfilter/ip_queue.c2
-rw-r--r--net/ipv6/netfilter/ip6_queue.c2
-rw-r--r--net/netfilter/nfnetlink.c2
-rw-r--r--net/netlink/genetlink.c2
-rw-r--r--net/xfrm/xfrm_user.c2
-rw-r--r--security/commoncap.c4
-rw-r--r--security/dummy.c4
-rw-r--r--security/selinux/hooks.c26
12 files changed, 35 insertions, 34 deletions
diff --git a/include/linux/security.h b/include/linux/security.h
index 51805806f974..c7ea15716dce 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -67,7 +67,7 @@ struct xfrm_state;
67struct xfrm_user_sec_ctx; 67struct xfrm_user_sec_ctx;
68 68
69extern int cap_netlink_send(struct sock *sk, struct sk_buff *skb); 69extern int cap_netlink_send(struct sock *sk, struct sk_buff *skb);
70extern int cap_netlink_recv(struct sk_buff *skb); 70extern int cap_netlink_recv(struct sk_buff *skb, int cap);
71 71
72/* 72/*
73 * Values used in the task_security_ops calls 73 * Values used in the task_security_ops calls
@@ -656,6 +656,7 @@ struct swap_info_struct;
656 * Check permission before processing the received netlink message in 656 * Check permission before processing the received netlink message in
657 * @skb. 657 * @skb.
658 * @skb contains the sk_buff structure for the netlink message. 658 * @skb contains the sk_buff structure for the netlink message.
659 * @cap indicates the capability required
659 * Return 0 if permission is granted. 660 * Return 0 if permission is granted.
660 * 661 *
661 * Security hooks for Unix domain networking. 662 * Security hooks for Unix domain networking.
@@ -1266,7 +1267,7 @@ struct security_operations {
1266 struct sembuf * sops, unsigned nsops, int alter); 1267 struct sembuf * sops, unsigned nsops, int alter);
1267 1268
1268 int (*netlink_send) (struct sock * sk, struct sk_buff * skb); 1269 int (*netlink_send) (struct sock * sk, struct sk_buff * skb);
1269 int (*netlink_recv) (struct sk_buff * skb); 1270 int (*netlink_recv) (struct sk_buff * skb, int cap);
1270 1271
1271 /* allow module stacking */ 1272 /* allow module stacking */
1272 int (*register_security) (const char *name, 1273 int (*register_security) (const char *name,
@@ -2032,9 +2033,9 @@ static inline int security_netlink_send(struct sock *sk, struct sk_buff * skb)
2032 return security_ops->netlink_send(sk, skb); 2033 return security_ops->netlink_send(sk, skb);
2033} 2034}
2034 2035
2035static inline int security_netlink_recv(struct sk_buff * skb) 2036static inline int security_netlink_recv(struct sk_buff * skb, int cap)
2036{ 2037{
2037 return security_ops->netlink_recv(skb); 2038 return security_ops->netlink_recv(skb, cap);
2038} 2039}
2039 2040
2040/* prototypes */ 2041/* prototypes */
@@ -2670,9 +2671,9 @@ static inline int security_netlink_send (struct sock *sk, struct sk_buff *skb)
2670 return cap_netlink_send (sk, skb); 2671 return cap_netlink_send (sk, skb);
2671} 2672}
2672 2673
2673static inline int security_netlink_recv (struct sk_buff *skb) 2674static inline int security_netlink_recv (struct sk_buff *skb, int cap)
2674{ 2675{
2675 return cap_netlink_recv (skb); 2676 return cap_netlink_recv (skb, cap);
2676} 2677}
2677 2678
2678static inline struct dentry *securityfs_create_dir(const char *name, 2679static inline struct dentry *securityfs_create_dir(const char *name,
diff --git a/kernel/audit.c b/kernel/audit.c
index 82443fb433ef..d417ca1db79b 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -445,7 +445,7 @@ void audit_send_reply(int pid, int seq, int type, int done, int multi,
445 * Check for appropriate CAP_AUDIT_ capabilities on incoming audit 445 * Check for appropriate CAP_AUDIT_ capabilities on incoming audit
446 * control messages. 446 * control messages.
447 */ 447 */
448static int audit_netlink_ok(kernel_cap_t eff_cap, u16 msg_type) 448static int audit_netlink_ok(struct sk_buff *skb, u16 msg_type)
449{ 449{
450 int err = 0; 450 int err = 0;
451 451
@@ -459,13 +459,13 @@ static int audit_netlink_ok(kernel_cap_t eff_cap, u16 msg_type)
459 case AUDIT_DEL: 459 case AUDIT_DEL:
460 case AUDIT_DEL_RULE: 460 case AUDIT_DEL_RULE:
461 case AUDIT_SIGNAL_INFO: 461 case AUDIT_SIGNAL_INFO:
462 if (!cap_raised(eff_cap, CAP_AUDIT_CONTROL)) 462 if (security_netlink_recv(skb, CAP_AUDIT_CONTROL))
463 err = -EPERM; 463 err = -EPERM;
464 break; 464 break;
465 case AUDIT_USER: 465 case AUDIT_USER:
466 case AUDIT_FIRST_USER_MSG...AUDIT_LAST_USER_MSG: 466 case AUDIT_FIRST_USER_MSG...AUDIT_LAST_USER_MSG:
467 case AUDIT_FIRST_USER_MSG2...AUDIT_LAST_USER_MSG2: 467 case AUDIT_FIRST_USER_MSG2...AUDIT_LAST_USER_MSG2:
468 if (!cap_raised(eff_cap, CAP_AUDIT_WRITE)) 468 if (security_netlink_recv(skb, CAP_AUDIT_WRITE))
469 err = -EPERM; 469 err = -EPERM;
470 break; 470 break;
471 default: /* bad msg */ 471 default: /* bad msg */
@@ -488,7 +488,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
488 char *ctx; 488 char *ctx;
489 u32 len; 489 u32 len;
490 490
491 err = audit_netlink_ok(NETLINK_CB(skb).eff_cap, msg_type); 491 err = audit_netlink_ok(skb, msg_type);
492 if (err) 492 if (err)
493 return err; 493 return err;
494 494
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 3fcfa9c59e1f..f25aac17497a 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -663,7 +663,7 @@ rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp)
663 sz_idx = type>>2; 663 sz_idx = type>>2;
664 kind = type&3; 664 kind = type&3;
665 665
666 if (kind != 2 && security_netlink_recv(skb)) { 666 if (kind != 2 && security_netlink_recv(skb, CAP_NET_ADMIN)) {
667 *errp = -EPERM; 667 *errp = -EPERM;
668 return -1; 668 return -1;
669 } 669 }
diff --git a/net/decnet/netfilter/dn_rtmsg.c b/net/decnet/netfilter/dn_rtmsg.c
index 74133ecd7700..8b99bd33540d 100644
--- a/net/decnet/netfilter/dn_rtmsg.c
+++ b/net/decnet/netfilter/dn_rtmsg.c
@@ -107,7 +107,7 @@ static inline void dnrmg_receive_user_skb(struct sk_buff *skb)
107 if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len) 107 if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len)
108 return; 108 return;
109 109
110 if (!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN)) 110 if (security_netlink_recv(skb, CAP_NET_ADMIN))
111 RCV_SKB_FAIL(-EPERM); 111 RCV_SKB_FAIL(-EPERM);
112 112
113 /* Eventually we might send routing messages too */ 113 /* Eventually we might send routing messages too */
diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c
index 213d116e5bb9..198ac36db861 100644
--- a/net/ipv4/netfilter/ip_queue.c
+++ b/net/ipv4/netfilter/ip_queue.c
@@ -515,7 +515,7 @@ ipq_rcv_skb(struct sk_buff *skb)
515 if (type <= IPQM_BASE) 515 if (type <= IPQM_BASE)
516 return; 516 return;
517 517
518 if (security_netlink_recv(skb)) 518 if (security_netlink_recv(skb, CAP_NET_ADMIN))
519 RCV_SKB_FAIL(-EPERM); 519 RCV_SKB_FAIL(-EPERM);
520 520
521 write_lock_bh(&queue_lock); 521 write_lock_bh(&queue_lock);
diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c
index b4b7d441af25..968a14be0d05 100644
--- a/net/ipv6/netfilter/ip6_queue.c
+++ b/net/ipv6/netfilter/ip6_queue.c
@@ -505,7 +505,7 @@ ipq_rcv_skb(struct sk_buff *skb)
505 if (type <= IPQM_BASE) 505 if (type <= IPQM_BASE)
506 return; 506 return;
507 507
508 if (security_netlink_recv(skb)) 508 if (security_netlink_recv(skb, CAP_NET_ADMIN))
509 RCV_SKB_FAIL(-EPERM); 509 RCV_SKB_FAIL(-EPERM);
510 510
511 write_lock_bh(&queue_lock); 511 write_lock_bh(&queue_lock);
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c
index b88e82a1a987..ec9f0efea6bb 100644
--- a/net/netfilter/nfnetlink.c
+++ b/net/netfilter/nfnetlink.c
@@ -229,7 +229,7 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb,
229 NFNL_SUBSYS_ID(nlh->nlmsg_type), 229 NFNL_SUBSYS_ID(nlh->nlmsg_type),
230 NFNL_MSG_TYPE(nlh->nlmsg_type)); 230 NFNL_MSG_TYPE(nlh->nlmsg_type));
231 231
232 if (!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN)) { 232 if (security_netlink_recv(skb, CAP_NET_ADMIN)) {
233 DEBUGP("missing CAP_NET_ADMIN\n"); 233 DEBUGP("missing CAP_NET_ADMIN\n");
234 *errp = -EPERM; 234 *errp = -EPERM;
235 return -1; 235 return -1;
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index f329b72578f5..edf084becd5e 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -320,7 +320,7 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
320 goto errout; 320 goto errout;
321 } 321 }
322 322
323 if ((ops->flags & GENL_ADMIN_PERM) && security_netlink_recv(skb)) { 323 if ((ops->flags & GENL_ADMIN_PERM) && security_netlink_recv(skb, CAP_NET_ADMIN)) {
324 err = -EPERM; 324 err = -EPERM;
325 goto errout; 325 goto errout;
326 } 326 }
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index c21dc26141ea..3e6a722d072e 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -1435,7 +1435,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *err
1435 link = &xfrm_dispatch[type]; 1435 link = &xfrm_dispatch[type];
1436 1436
1437 /* All operations require privileges, even GET */ 1437 /* All operations require privileges, even GET */
1438 if (security_netlink_recv(skb)) { 1438 if (security_netlink_recv(skb, CAP_NET_ADMIN)) {
1439 *errp = -EPERM; 1439 *errp = -EPERM;
1440 return -1; 1440 return -1;
1441 } 1441 }
diff --git a/security/commoncap.c b/security/commoncap.c
index 841eb4e5c62b..57673ee07ceb 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -33,9 +33,9 @@ int cap_netlink_send(struct sock *sk, struct sk_buff *skb)
33 33
34EXPORT_SYMBOL(cap_netlink_send); 34EXPORT_SYMBOL(cap_netlink_send);
35 35
36int cap_netlink_recv(struct sk_buff *skb) 36int cap_netlink_recv(struct sk_buff *skb, int cap)
37{ 37{
38 if (!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN)) 38 if (!cap_raised(NETLINK_CB(skb).eff_cap, cap))
39 return -EPERM; 39 return -EPERM;
40 return 0; 40 return 0;
41} 41}
diff --git a/security/dummy.c b/security/dummy.c
index 310fcdf7b749..913540808577 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -675,9 +675,9 @@ static int dummy_netlink_send (struct sock *sk, struct sk_buff *skb)
675 return 0; 675 return 0;
676} 676}
677 677
678static int dummy_netlink_recv (struct sk_buff *skb) 678static int dummy_netlink_recv (struct sk_buff *skb, int cap)
679{ 679{
680 if (!cap_raised (NETLINK_CB (skb).eff_cap, CAP_NET_ADMIN)) 680 if (!cap_raised (NETLINK_CB (skb).eff_cap, cap))
681 return -EPERM; 681 return -EPERM;
682 return 0; 682 return 0;
683} 683}
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 28832e689800..b6c378dd4f12 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -3641,32 +3641,32 @@ static unsigned int selinux_ipv6_postroute_last(unsigned int hooknum,
3641 3641
3642static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb) 3642static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
3643{ 3643{
3644 struct task_security_struct *tsec;
3645 struct av_decision avd;
3646 int err; 3644 int err;
3647 3645
3648 err = secondary_ops->netlink_send(sk, skb); 3646 err = secondary_ops->netlink_send(sk, skb);
3649 if (err) 3647 if (err)
3650 return err; 3648 return err;
3651 3649
3652 tsec = current->security;
3653
3654 avd.allowed = 0;
3655 avc_has_perm_noaudit(tsec->sid, tsec->sid,
3656 SECCLASS_CAPABILITY, ~0, &avd);
3657 cap_mask(NETLINK_CB(skb).eff_cap, avd.allowed);
3658
3659 if (policydb_loaded_version >= POLICYDB_VERSION_NLCLASS) 3650 if (policydb_loaded_version >= POLICYDB_VERSION_NLCLASS)
3660 err = selinux_nlmsg_perm(sk, skb); 3651 err = selinux_nlmsg_perm(sk, skb);
3661 3652
3662 return err; 3653 return err;
3663} 3654}
3664 3655
3665static int selinux_netlink_recv(struct sk_buff *skb) 3656static int selinux_netlink_recv(struct sk_buff *skb, int capability)
3666{ 3657{
3667 if (!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN)) 3658 int err;
3668 return -EPERM; 3659 struct avc_audit_data ad;
3669 return 0; 3660
3661 err = secondary_ops->netlink_recv(skb, capability);
3662 if (err)
3663 return err;
3664
3665 AVC_AUDIT_DATA_INIT(&ad, CAP);
3666 ad.u.cap = capability;
3667
3668 return avc_has_perm(NETLINK_CB(skb).sid, NETLINK_CB(skb).sid,
3669 SECCLASS_CAPABILITY, CAP_TO_MASK(capability), &ad);
3670} 3670}
3671 3671
3672static int ipc_alloc_security(struct task_struct *task, 3672static int ipc_alloc_security(struct task_struct *task,