diff options
author | Darrel Goeddel <dgoeddel@trustedcs.com> | 2006-06-27 16:26:11 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-06-29 19:57:55 -0400 |
commit | c7bdb545d23026b18be53289fd866d1ac07f5f8c (patch) | |
tree | 6d9a218871d88f7579dd53f14692df2529b6e712 | |
parent | 576a30eb6453439b3c37ba24455ac7090c247b5a (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.h | 13 | ||||
-rw-r--r-- | kernel/audit.c | 8 | ||||
-rw-r--r-- | net/core/rtnetlink.c | 2 | ||||
-rw-r--r-- | net/decnet/netfilter/dn_rtmsg.c | 2 | ||||
-rw-r--r-- | net/ipv4/netfilter/ip_queue.c | 2 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6_queue.c | 2 | ||||
-rw-r--r-- | net/netfilter/nfnetlink.c | 2 | ||||
-rw-r--r-- | net/netlink/genetlink.c | 2 | ||||
-rw-r--r-- | net/xfrm/xfrm_user.c | 2 | ||||
-rw-r--r-- | security/commoncap.c | 4 | ||||
-rw-r--r-- | security/dummy.c | 4 | ||||
-rw-r--r-- | security/selinux/hooks.c | 26 |
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; | |||
67 | struct xfrm_user_sec_ctx; | 67 | struct xfrm_user_sec_ctx; |
68 | 68 | ||
69 | extern int cap_netlink_send(struct sock *sk, struct sk_buff *skb); | 69 | extern int cap_netlink_send(struct sock *sk, struct sk_buff *skb); |
70 | extern int cap_netlink_recv(struct sk_buff *skb); | 70 | extern 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 | ||
2035 | static inline int security_netlink_recv(struct sk_buff * skb) | 2036 | static 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 | ||
2673 | static inline int security_netlink_recv (struct sk_buff *skb) | 2674 | static 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 | ||
2678 | static inline struct dentry *securityfs_create_dir(const char *name, | 2679 | static 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 | */ |
448 | static int audit_netlink_ok(kernel_cap_t eff_cap, u16 msg_type) | 448 | static 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 | ||
34 | EXPORT_SYMBOL(cap_netlink_send); | 34 | EXPORT_SYMBOL(cap_netlink_send); |
35 | 35 | ||
36 | int cap_netlink_recv(struct sk_buff *skb) | 36 | int 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 | ||
678 | static int dummy_netlink_recv (struct sk_buff *skb) | 678 | static 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 | ||
3642 | static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb) | 3642 | static 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 | ||
3665 | static int selinux_netlink_recv(struct sk_buff *skb) | 3656 | static 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 | ||
3672 | static int ipc_alloc_security(struct task_struct *task, | 3672 | static int ipc_alloc_security(struct task_struct *task, |