aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoy Latten <latten@austin.ibm.com>2007-06-04 19:05:57 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-06-07 16:42:46 -0400
commit4aa2e62c45b5ca08be2d0d3c0744d7585b56e860 (patch)
tree16649593d55f3df4dac54227fcda28bb4fb49f17
parentb00b4bf94edb42852d55619af453588b2de2dc5e (diff)
xfrm: Add security check before flushing SAD/SPD
Currently we check for permission before deleting entries from SAD and SPD, (see security_xfrm_policy_delete() security_xfrm_state_delete()) However we are not checking for authorization when flushing the SPD and the SAD completely. It was perhaps missed in the original security hooks patch. This patch adds a security check when flushing entries from the SAD and SPD. It runs the entire database and checks each entry for a denial. If the process attempting the flush is unable to remove all of the entries a denial is logged the the flush function returns an error without removing anything. This is particularly useful when a process may need to create or delete its own xfrm entries used for things like labeled networking but that same process should not be able to delete other entries or flush the entire database. Signed-off-by: Joy Latten<latten@austin.ibm.com> Signed-off-by: Eric Paris <eparis@parisplace.org> Signed-off-by: James Morris <jmorris@namei.org>
-rw-r--r--include/net/xfrm.h6
-rw-r--r--net/key/af_key.c10
-rw-r--r--net/xfrm/xfrm_policy.c63
-rw-r--r--net/xfrm/xfrm_state.c46
-rw-r--r--net/xfrm/xfrm_user.c9
5 files changed, 121 insertions, 13 deletions
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 90185e8b335e..311f25af5e1a 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -964,7 +964,7 @@ struct xfrmk_spdinfo {
964 964
965extern struct xfrm_state *xfrm_find_acq_byseq(u32 seq); 965extern struct xfrm_state *xfrm_find_acq_byseq(u32 seq);
966extern int xfrm_state_delete(struct xfrm_state *x); 966extern int xfrm_state_delete(struct xfrm_state *x);
967extern void xfrm_state_flush(u8 proto, struct xfrm_audit *audit_info); 967extern int xfrm_state_flush(u8 proto, struct xfrm_audit *audit_info);
968extern void xfrm_sad_getinfo(struct xfrmk_sadinfo *si); 968extern void xfrm_sad_getinfo(struct xfrmk_sadinfo *si);
969extern void xfrm_spd_getinfo(struct xfrmk_spdinfo *si); 969extern void xfrm_spd_getinfo(struct xfrmk_spdinfo *si);
970extern int xfrm_replay_check(struct xfrm_state *x, __be32 seq); 970extern int xfrm_replay_check(struct xfrm_state *x, __be32 seq);
@@ -1020,13 +1020,13 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir,
1020 struct xfrm_sec_ctx *ctx, int delete, 1020 struct xfrm_sec_ctx *ctx, int delete,
1021 int *err); 1021 int *err);
1022struct xfrm_policy *xfrm_policy_byid(u8, int dir, u32 id, int delete, int *err); 1022struct xfrm_policy *xfrm_policy_byid(u8, int dir, u32 id, int delete, int *err);
1023void xfrm_policy_flush(u8 type, struct xfrm_audit *audit_info); 1023int xfrm_policy_flush(u8 type, struct xfrm_audit *audit_info);
1024u32 xfrm_get_acqseq(void); 1024u32 xfrm_get_acqseq(void);
1025void xfrm_alloc_spi(struct xfrm_state *x, __be32 minspi, __be32 maxspi); 1025void xfrm_alloc_spi(struct xfrm_state *x, __be32 minspi, __be32 maxspi);
1026struct xfrm_state * xfrm_find_acq(u8 mode, u32 reqid, u8 proto, 1026struct xfrm_state * xfrm_find_acq(u8 mode, u32 reqid, u8 proto,
1027 xfrm_address_t *daddr, xfrm_address_t *saddr, 1027 xfrm_address_t *daddr, xfrm_address_t *saddr,
1028 int create, unsigned short family); 1028 int create, unsigned short family);
1029extern void xfrm_policy_flush(u8 type, struct xfrm_audit *audit_info); 1029extern int xfrm_policy_flush(u8 type, struct xfrm_audit *audit_info);
1030extern int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol); 1030extern int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol);
1031extern int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *xdst, 1031extern int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *xdst,
1032 struct flowi *fl, int family, int strict); 1032 struct flowi *fl, int family, int strict);
diff --git a/net/key/af_key.c b/net/key/af_key.c
index d302ddae580c..0f8304b0246b 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -1682,6 +1682,7 @@ static int pfkey_flush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hd
1682 unsigned proto; 1682 unsigned proto;
1683 struct km_event c; 1683 struct km_event c;
1684 struct xfrm_audit audit_info; 1684 struct xfrm_audit audit_info;
1685 int err;
1685 1686
1686 proto = pfkey_satype2proto(hdr->sadb_msg_satype); 1687 proto = pfkey_satype2proto(hdr->sadb_msg_satype);
1687 if (proto == 0) 1688 if (proto == 0)
@@ -1689,7 +1690,9 @@ static int pfkey_flush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hd
1689 1690
1690 audit_info.loginuid = audit_get_loginuid(current->audit_context); 1691 audit_info.loginuid = audit_get_loginuid(current->audit_context);
1691 audit_info.secid = 0; 1692 audit_info.secid = 0;
1692 xfrm_state_flush(proto, &audit_info); 1693 err = xfrm_state_flush(proto, &audit_info);
1694 if (err)
1695 return err;
1693 c.data.proto = proto; 1696 c.data.proto = proto;
1694 c.seq = hdr->sadb_msg_seq; 1697 c.seq = hdr->sadb_msg_seq;
1695 c.pid = hdr->sadb_msg_pid; 1698 c.pid = hdr->sadb_msg_pid;
@@ -2683,10 +2686,13 @@ static int pfkey_spdflush(struct sock *sk, struct sk_buff *skb, struct sadb_msg
2683{ 2686{
2684 struct km_event c; 2687 struct km_event c;
2685 struct xfrm_audit audit_info; 2688 struct xfrm_audit audit_info;
2689 int err;
2686 2690
2687 audit_info.loginuid = audit_get_loginuid(current->audit_context); 2691 audit_info.loginuid = audit_get_loginuid(current->audit_context);
2688 audit_info.secid = 0; 2692 audit_info.secid = 0;
2689 xfrm_policy_flush(XFRM_POLICY_TYPE_MAIN, &audit_info); 2693 err = xfrm_policy_flush(XFRM_POLICY_TYPE_MAIN, &audit_info);
2694 if (err)
2695 return err;
2690 c.data.type = XFRM_POLICY_TYPE_MAIN; 2696 c.data.type = XFRM_POLICY_TYPE_MAIN;
2691 c.event = XFRM_MSG_FLUSHPOLICY; 2697 c.event = XFRM_MSG_FLUSHPOLICY;
2692 c.pid = hdr->sadb_msg_pid; 2698 c.pid = hdr->sadb_msg_pid;
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 64a375178c5f..157bfbd250ba 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -834,11 +834,67 @@ struct xfrm_policy *xfrm_policy_byid(u8 type, int dir, u32 id, int delete,
834} 834}
835EXPORT_SYMBOL(xfrm_policy_byid); 835EXPORT_SYMBOL(xfrm_policy_byid);
836 836
837void xfrm_policy_flush(u8 type, struct xfrm_audit *audit_info) 837#ifdef CONFIG_SECURITY_NETWORK_XFRM
838static inline int
839xfrm_policy_flush_secctx_check(u8 type, struct xfrm_audit *audit_info)
838{ 840{
839 int dir; 841 int dir, err = 0;
842
843 for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {
844 struct xfrm_policy *pol;
845 struct hlist_node *entry;
846 int i;
847
848 hlist_for_each_entry(pol, entry,
849 &xfrm_policy_inexact[dir], bydst) {
850 if (pol->type != type)
851 continue;
852 err = security_xfrm_policy_delete(pol);
853 if (err) {
854 xfrm_audit_log(audit_info->loginuid,
855 audit_info->secid,
856 AUDIT_MAC_IPSEC_DELSPD, 0,
857 pol, NULL);
858 return err;
859 }
860 }
861 for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) {
862 hlist_for_each_entry(pol, entry,
863 xfrm_policy_bydst[dir].table + i,
864 bydst) {
865 if (pol->type != type)
866 continue;
867 err = security_xfrm_policy_delete(pol);
868 if (err) {
869 xfrm_audit_log(audit_info->loginuid,
870 audit_info->secid,
871 AUDIT_MAC_IPSEC_DELSPD,
872 0, pol, NULL);
873 return err;
874 }
875 }
876 }
877 }
878 return err;
879}
880#else
881static inline int
882xfrm_policy_flush_secctx_check(u8 type, struct xfrm_audit *audit_info)
883{
884 return 0;
885}
886#endif
887
888int xfrm_policy_flush(u8 type, struct xfrm_audit *audit_info)
889{
890 int dir, err = 0;
840 891
841 write_lock_bh(&xfrm_policy_lock); 892 write_lock_bh(&xfrm_policy_lock);
893
894 err = xfrm_policy_flush_secctx_check(type, audit_info);
895 if (err)
896 goto out;
897
842 for (dir = 0; dir < XFRM_POLICY_MAX; dir++) { 898 for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {
843 struct xfrm_policy *pol; 899 struct xfrm_policy *pol;
844 struct hlist_node *entry; 900 struct hlist_node *entry;
@@ -891,7 +947,9 @@ void xfrm_policy_flush(u8 type, struct xfrm_audit *audit_info)
891 xfrm_policy_count[dir] -= killed; 947 xfrm_policy_count[dir] -= killed;
892 } 948 }
893 atomic_inc(&flow_cache_genid); 949 atomic_inc(&flow_cache_genid);
950out:
894 write_unlock_bh(&xfrm_policy_lock); 951 write_unlock_bh(&xfrm_policy_lock);
952 return err;
895} 953}
896EXPORT_SYMBOL(xfrm_policy_flush); 954EXPORT_SYMBOL(xfrm_policy_flush);
897 955
@@ -2583,4 +2641,3 @@ restore_state:
2583} 2641}
2584EXPORT_SYMBOL(xfrm_migrate); 2642EXPORT_SYMBOL(xfrm_migrate);
2585#endif 2643#endif
2586
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 372f06eb8bb7..85f3f43a6cca 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -391,12 +391,48 @@ int xfrm_state_delete(struct xfrm_state *x)
391} 391}
392EXPORT_SYMBOL(xfrm_state_delete); 392EXPORT_SYMBOL(xfrm_state_delete);
393 393
394void xfrm_state_flush(u8 proto, struct xfrm_audit *audit_info) 394#ifdef CONFIG_SECURITY_NETWORK_XFRM
395static inline int
396xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info)
395{ 397{
396 int i; 398 int i, err = 0;
397 int err = 0; 399
400 for (i = 0; i <= xfrm_state_hmask; i++) {
401 struct hlist_node *entry;
402 struct xfrm_state *x;
403
404 hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) {
405 if (xfrm_id_proto_match(x->id.proto, proto) &&
406 (err = security_xfrm_state_delete(x)) != 0) {
407 xfrm_audit_log(audit_info->loginuid,
408 audit_info->secid,
409 AUDIT_MAC_IPSEC_DELSA,
410 0, NULL, x);
411
412 return err;
413 }
414 }
415 }
416
417 return err;
418}
419#else
420static inline int
421xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info)
422{
423 return 0;
424}
425#endif
426
427int xfrm_state_flush(u8 proto, struct xfrm_audit *audit_info)
428{
429 int i, err = 0;
398 430
399 spin_lock_bh(&xfrm_state_lock); 431 spin_lock_bh(&xfrm_state_lock);
432 err = xfrm_state_flush_secctx_check(proto, audit_info);
433 if (err)
434 goto out;
435
400 for (i = 0; i <= xfrm_state_hmask; i++) { 436 for (i = 0; i <= xfrm_state_hmask; i++) {
401 struct hlist_node *entry; 437 struct hlist_node *entry;
402 struct xfrm_state *x; 438 struct xfrm_state *x;
@@ -419,8 +455,12 @@ restart:
419 } 455 }
420 } 456 }
421 } 457 }
458 err = 0;
459
460out:
422 spin_unlock_bh(&xfrm_state_lock); 461 spin_unlock_bh(&xfrm_state_lock);
423 wake_up(&km_waitq); 462 wake_up(&km_waitq);
463 return err;
424} 464}
425EXPORT_SYMBOL(xfrm_state_flush); 465EXPORT_SYMBOL(xfrm_state_flush);
426 466
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index b14c7e590c31..c06883bf620e 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -1418,10 +1418,13 @@ static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
1418 struct km_event c; 1418 struct km_event c;
1419 struct xfrm_usersa_flush *p = NLMSG_DATA(nlh); 1419 struct xfrm_usersa_flush *p = NLMSG_DATA(nlh);
1420 struct xfrm_audit audit_info; 1420 struct xfrm_audit audit_info;
1421 int err;
1421 1422
1422 audit_info.loginuid = NETLINK_CB(skb).loginuid; 1423 audit_info.loginuid = NETLINK_CB(skb).loginuid;
1423 audit_info.secid = NETLINK_CB(skb).sid; 1424 audit_info.secid = NETLINK_CB(skb).sid;
1424 xfrm_state_flush(p->proto, &audit_info); 1425 err = xfrm_state_flush(p->proto, &audit_info);
1426 if (err)
1427 return err;
1425 c.data.proto = p->proto; 1428 c.data.proto = p->proto;
1426 c.event = nlh->nlmsg_type; 1429 c.event = nlh->nlmsg_type;
1427 c.seq = nlh->nlmsg_seq; 1430 c.seq = nlh->nlmsg_seq;
@@ -1582,7 +1585,9 @@ static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
1582 1585
1583 audit_info.loginuid = NETLINK_CB(skb).loginuid; 1586 audit_info.loginuid = NETLINK_CB(skb).loginuid;
1584 audit_info.secid = NETLINK_CB(skb).sid; 1587 audit_info.secid = NETLINK_CB(skb).sid;
1585 xfrm_policy_flush(type, &audit_info); 1588 err = xfrm_policy_flush(type, &audit_info);
1589 if (err)
1590 return err;
1586 c.data.type = type; 1591 c.data.type = type;
1587 c.event = nlh->nlmsg_type; 1592 c.event = nlh->nlmsg_type;
1588 c.seq = nlh->nlmsg_seq; 1593 c.seq = nlh->nlmsg_seq;