diff options
author | Venkat Yekkirala <vyekkirala@TrustedCS.com> | 2006-07-25 02:29:07 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-09-22 17:53:24 -0400 |
commit | e0d1caa7b0d5f02e4f34aa09c695d04251310c6c (patch) | |
tree | bf023c17abf6813f2694ebf5fafff82edd6a1023 /net | |
parent | b6340fcd761acf9249b3acbc95c4dc555d9beb07 (diff) |
[MLSXFRM]: Flow based matching of xfrm policy and state
This implements a seemless mechanism for xfrm policy selection and
state matching based on the flow sid. This also includes the necessary
SELinux enforcement pieces.
Signed-off-by: Venkat Yekkirala <vyekkirala@TrustedCS.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/core/flow.c | 7 | ||||
-rw-r--r-- | net/xfrm/xfrm_policy.c | 28 | ||||
-rw-r--r-- | net/xfrm/xfrm_state.c | 12 |
3 files changed, 27 insertions, 20 deletions
diff --git a/net/core/flow.c b/net/core/flow.c index 2191af5f26ac..645241165e6c 100644 --- a/net/core/flow.c +++ b/net/core/flow.c | |||
@@ -32,7 +32,6 @@ struct flow_cache_entry { | |||
32 | u8 dir; | 32 | u8 dir; |
33 | struct flowi key; | 33 | struct flowi key; |
34 | u32 genid; | 34 | u32 genid; |
35 | u32 sk_sid; | ||
36 | void *object; | 35 | void *object; |
37 | atomic_t *object_ref; | 36 | atomic_t *object_ref; |
38 | }; | 37 | }; |
@@ -165,7 +164,7 @@ static int flow_key_compare(struct flowi *key1, struct flowi *key2) | |||
165 | return 0; | 164 | return 0; |
166 | } | 165 | } |
167 | 166 | ||
168 | void *flow_cache_lookup(struct flowi *key, u32 sk_sid, u16 family, u8 dir, | 167 | void *flow_cache_lookup(struct flowi *key, u16 family, u8 dir, |
169 | flow_resolve_t resolver) | 168 | flow_resolve_t resolver) |
170 | { | 169 | { |
171 | struct flow_cache_entry *fle, **head; | 170 | struct flow_cache_entry *fle, **head; |
@@ -189,7 +188,6 @@ void *flow_cache_lookup(struct flowi *key, u32 sk_sid, u16 family, u8 dir, | |||
189 | for (fle = *head; fle; fle = fle->next) { | 188 | for (fle = *head; fle; fle = fle->next) { |
190 | if (fle->family == family && | 189 | if (fle->family == family && |
191 | fle->dir == dir && | 190 | fle->dir == dir && |
192 | fle->sk_sid == sk_sid && | ||
193 | flow_key_compare(key, &fle->key) == 0) { | 191 | flow_key_compare(key, &fle->key) == 0) { |
194 | if (fle->genid == atomic_read(&flow_cache_genid)) { | 192 | if (fle->genid == atomic_read(&flow_cache_genid)) { |
195 | void *ret = fle->object; | 193 | void *ret = fle->object; |
@@ -214,7 +212,6 @@ void *flow_cache_lookup(struct flowi *key, u32 sk_sid, u16 family, u8 dir, | |||
214 | *head = fle; | 212 | *head = fle; |
215 | fle->family = family; | 213 | fle->family = family; |
216 | fle->dir = dir; | 214 | fle->dir = dir; |
217 | fle->sk_sid = sk_sid; | ||
218 | memcpy(&fle->key, key, sizeof(*key)); | 215 | memcpy(&fle->key, key, sizeof(*key)); |
219 | fle->object = NULL; | 216 | fle->object = NULL; |
220 | flow_count(cpu)++; | 217 | flow_count(cpu)++; |
@@ -226,7 +223,7 @@ nocache: | |||
226 | void *obj; | 223 | void *obj; |
227 | atomic_t *obj_ref; | 224 | atomic_t *obj_ref; |
228 | 225 | ||
229 | resolver(key, sk_sid, family, dir, &obj, &obj_ref); | 226 | resolver(key, family, dir, &obj, &obj_ref); |
230 | 227 | ||
231 | if (fle) { | 228 | if (fle) { |
232 | fle->genid = atomic_read(&flow_cache_genid); | 229 | fle->genid = atomic_read(&flow_cache_genid); |
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 3da67ca2c3ce..79405daadc52 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
@@ -597,7 +597,7 @@ EXPORT_SYMBOL(xfrm_policy_walk); | |||
597 | 597 | ||
598 | /* Find policy to apply to this flow. */ | 598 | /* Find policy to apply to this flow. */ |
599 | 599 | ||
600 | static void xfrm_policy_lookup(struct flowi *fl, u32 sk_sid, u16 family, u8 dir, | 600 | static void xfrm_policy_lookup(struct flowi *fl, u16 family, u8 dir, |
601 | void **objp, atomic_t **obj_refp) | 601 | void **objp, atomic_t **obj_refp) |
602 | { | 602 | { |
603 | struct xfrm_policy *pol; | 603 | struct xfrm_policy *pol; |
@@ -613,7 +613,7 @@ static void xfrm_policy_lookup(struct flowi *fl, u32 sk_sid, u16 family, u8 dir, | |||
613 | match = xfrm_selector_match(sel, fl, family); | 613 | match = xfrm_selector_match(sel, fl, family); |
614 | 614 | ||
615 | if (match) { | 615 | if (match) { |
616 | if (!security_xfrm_policy_lookup(pol, sk_sid, dir)) { | 616 | if (!security_xfrm_policy_lookup(pol, fl->secid, dir)) { |
617 | xfrm_pol_hold(pol); | 617 | xfrm_pol_hold(pol); |
618 | break; | 618 | break; |
619 | } | 619 | } |
@@ -641,7 +641,7 @@ static inline int policy_to_flow_dir(int dir) | |||
641 | }; | 641 | }; |
642 | } | 642 | } |
643 | 643 | ||
644 | static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struct flowi *fl, u32 sk_sid) | 644 | static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struct flowi *fl) |
645 | { | 645 | { |
646 | struct xfrm_policy *pol; | 646 | struct xfrm_policy *pol; |
647 | 647 | ||
@@ -652,7 +652,7 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struc | |||
652 | int err = 0; | 652 | int err = 0; |
653 | 653 | ||
654 | if (match) | 654 | if (match) |
655 | err = security_xfrm_policy_lookup(pol, sk_sid, policy_to_flow_dir(dir)); | 655 | err = security_xfrm_policy_lookup(pol, fl->secid, policy_to_flow_dir(dir)); |
656 | 656 | ||
657 | if (match && !err) | 657 | if (match && !err) |
658 | xfrm_pol_hold(pol); | 658 | xfrm_pol_hold(pol); |
@@ -862,19 +862,20 @@ int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, | |||
862 | u32 genid; | 862 | u32 genid; |
863 | u16 family; | 863 | u16 family; |
864 | u8 dir = policy_to_flow_dir(XFRM_POLICY_OUT); | 864 | u8 dir = policy_to_flow_dir(XFRM_POLICY_OUT); |
865 | u32 sk_sid = security_sk_sid(sk, fl, dir); | 865 | |
866 | fl->secid = security_sk_sid(sk, fl, dir); | ||
866 | restart: | 867 | restart: |
867 | genid = atomic_read(&flow_cache_genid); | 868 | genid = atomic_read(&flow_cache_genid); |
868 | policy = NULL; | 869 | policy = NULL; |
869 | if (sk && sk->sk_policy[1]) | 870 | if (sk && sk->sk_policy[1]) |
870 | policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl, sk_sid); | 871 | policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl); |
871 | 872 | ||
872 | if (!policy) { | 873 | if (!policy) { |
873 | /* To accelerate a bit... */ | 874 | /* To accelerate a bit... */ |
874 | if ((dst_orig->flags & DST_NOXFRM) || !xfrm_policy_list[XFRM_POLICY_OUT]) | 875 | if ((dst_orig->flags & DST_NOXFRM) || !xfrm_policy_list[XFRM_POLICY_OUT]) |
875 | return 0; | 876 | return 0; |
876 | 877 | ||
877 | policy = flow_cache_lookup(fl, sk_sid, dst_orig->ops->family, | 878 | policy = flow_cache_lookup(fl, dst_orig->ops->family, |
878 | dir, xfrm_policy_lookup); | 879 | dir, xfrm_policy_lookup); |
879 | } | 880 | } |
880 | 881 | ||
@@ -1032,13 +1033,15 @@ int | |||
1032 | xfrm_decode_session(struct sk_buff *skb, struct flowi *fl, unsigned short family) | 1033 | xfrm_decode_session(struct sk_buff *skb, struct flowi *fl, unsigned short family) |
1033 | { | 1034 | { |
1034 | struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); | 1035 | struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); |
1036 | int err; | ||
1035 | 1037 | ||
1036 | if (unlikely(afinfo == NULL)) | 1038 | if (unlikely(afinfo == NULL)) |
1037 | return -EAFNOSUPPORT; | 1039 | return -EAFNOSUPPORT; |
1038 | 1040 | ||
1039 | afinfo->decode_session(skb, fl); | 1041 | afinfo->decode_session(skb, fl); |
1042 | err = security_xfrm_decode_session(skb, fl); | ||
1040 | xfrm_policy_put_afinfo(afinfo); | 1043 | xfrm_policy_put_afinfo(afinfo); |
1041 | return 0; | 1044 | return err; |
1042 | } | 1045 | } |
1043 | EXPORT_SYMBOL(xfrm_decode_session); | 1046 | EXPORT_SYMBOL(xfrm_decode_session); |
1044 | 1047 | ||
@@ -1058,14 +1061,11 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, | |||
1058 | struct xfrm_policy *pol; | 1061 | struct xfrm_policy *pol; |
1059 | struct flowi fl; | 1062 | struct flowi fl; |
1060 | u8 fl_dir = policy_to_flow_dir(dir); | 1063 | u8 fl_dir = policy_to_flow_dir(dir); |
1061 | u32 sk_sid; | ||
1062 | 1064 | ||
1063 | if (xfrm_decode_session(skb, &fl, family) < 0) | 1065 | if (xfrm_decode_session(skb, &fl, family) < 0) |
1064 | return 0; | 1066 | return 0; |
1065 | nf_nat_decode_session(skb, &fl, family); | 1067 | nf_nat_decode_session(skb, &fl, family); |
1066 | 1068 | ||
1067 | sk_sid = security_sk_sid(sk, &fl, fl_dir); | ||
1068 | |||
1069 | /* First, check used SA against their selectors. */ | 1069 | /* First, check used SA against their selectors. */ |
1070 | if (skb->sp) { | 1070 | if (skb->sp) { |
1071 | int i; | 1071 | int i; |
@@ -1079,10 +1079,10 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, | |||
1079 | 1079 | ||
1080 | pol = NULL; | 1080 | pol = NULL; |
1081 | if (sk && sk->sk_policy[dir]) | 1081 | if (sk && sk->sk_policy[dir]) |
1082 | pol = xfrm_sk_policy_lookup(sk, dir, &fl, sk_sid); | 1082 | pol = xfrm_sk_policy_lookup(sk, dir, &fl); |
1083 | 1083 | ||
1084 | if (!pol) | 1084 | if (!pol) |
1085 | pol = flow_cache_lookup(&fl, sk_sid, family, fl_dir, | 1085 | pol = flow_cache_lookup(&fl, family, fl_dir, |
1086 | xfrm_policy_lookup); | 1086 | xfrm_policy_lookup); |
1087 | 1087 | ||
1088 | if (!pol) | 1088 | if (!pol) |
@@ -1298,6 +1298,8 @@ int xfrm_bundle_ok(struct xfrm_dst *first, struct flowi *fl, int family) | |||
1298 | 1298 | ||
1299 | if (fl && !xfrm_selector_match(&dst->xfrm->sel, fl, family)) | 1299 | if (fl && !xfrm_selector_match(&dst->xfrm->sel, fl, family)) |
1300 | return 0; | 1300 | return 0; |
1301 | if (fl && !security_xfrm_flow_state_match(fl, dst->xfrm)) | ||
1302 | return 0; | ||
1301 | if (dst->xfrm->km.state != XFRM_STATE_VALID) | 1303 | if (dst->xfrm->km.state != XFRM_STATE_VALID) |
1302 | return 0; | 1304 | return 0; |
1303 | 1305 | ||
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 0021aad5db43..be02bd981d12 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
@@ -367,7 +367,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, | |||
367 | */ | 367 | */ |
368 | if (x->km.state == XFRM_STATE_VALID) { | 368 | if (x->km.state == XFRM_STATE_VALID) { |
369 | if (!xfrm_selector_match(&x->sel, fl, family) || | 369 | if (!xfrm_selector_match(&x->sel, fl, family) || |
370 | !xfrm_sec_ctx_match(pol->security, x->security)) | 370 | !security_xfrm_state_pol_flow_match(x, pol, fl)) |
371 | continue; | 371 | continue; |
372 | if (!best || | 372 | if (!best || |
373 | best->km.dying > x->km.dying || | 373 | best->km.dying > x->km.dying || |
@@ -379,7 +379,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, | |||
379 | } else if (x->km.state == XFRM_STATE_ERROR || | 379 | } else if (x->km.state == XFRM_STATE_ERROR || |
380 | x->km.state == XFRM_STATE_EXPIRED) { | 380 | x->km.state == XFRM_STATE_EXPIRED) { |
381 | if (xfrm_selector_match(&x->sel, fl, family) && | 381 | if (xfrm_selector_match(&x->sel, fl, family) && |
382 | xfrm_sec_ctx_match(pol->security, x->security)) | 382 | security_xfrm_state_pol_flow_match(x, pol, fl)) |
383 | error = -ESRCH; | 383 | error = -ESRCH; |
384 | } | 384 | } |
385 | } | 385 | } |
@@ -403,6 +403,14 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, | |||
403 | * to current session. */ | 403 | * to current session. */ |
404 | xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family); | 404 | xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family); |
405 | 405 | ||
406 | error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid); | ||
407 | if (error) { | ||
408 | x->km.state = XFRM_STATE_DEAD; | ||
409 | xfrm_state_put(x); | ||
410 | x = NULL; | ||
411 | goto out; | ||
412 | } | ||
413 | |||
406 | if (km_query(x, tmpl, pol) == 0) { | 414 | if (km_query(x, tmpl, pol) == 0) { |
407 | x->km.state = XFRM_STATE_ACQ; | 415 | x->km.state = XFRM_STATE_ACQ; |
408 | list_add_tail(&x->bydst, xfrm_state_bydst+h); | 416 | list_add_tail(&x->bydst, xfrm_state_bydst+h); |