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 | |
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>
-rw-r--r-- | include/linux/security.h | 106 | ||||
-rw-r--r-- | include/net/flow.h | 4 | ||||
-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 | ||||
-rw-r--r-- | security/dummy.c | 23 | ||||
-rw-r--r-- | security/selinux/hooks.c | 7 | ||||
-rw-r--r-- | security/selinux/include/xfrm.h | 23 | ||||
-rw-r--r-- | security/selinux/xfrm.c | 199 |
9 files changed, 329 insertions, 80 deletions
diff --git a/include/linux/security.h b/include/linux/security.h index 4d7fb59996b0..2c4921d79d19 100644 --- a/include/linux/security.h +++ b/include/linux/security.h | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/msg.h> | 31 | #include <linux/msg.h> |
32 | #include <linux/sched.h> | 32 | #include <linux/sched.h> |
33 | #include <linux/key.h> | 33 | #include <linux/key.h> |
34 | #include <linux/xfrm.h> | ||
34 | 35 | ||
35 | struct ctl_table; | 36 | struct ctl_table; |
36 | 37 | ||
@@ -825,9 +826,8 @@ struct swap_info_struct; | |||
825 | * used by the XFRM system. | 826 | * used by the XFRM system. |
826 | * @sec_ctx contains the security context information being provided by | 827 | * @sec_ctx contains the security context information being provided by |
827 | * the user-level policy update program (e.g., setkey). | 828 | * the user-level policy update program (e.g., setkey). |
828 | * Allocate a security structure to the xp->security field. | 829 | * Allocate a security structure to the xp->security field; the security |
829 | * The security field is initialized to NULL when the xfrm_policy is | 830 | * field is initialized to NULL when the xfrm_policy is allocated. |
830 | * allocated. | ||
831 | * Return 0 if operation was successful (memory to allocate, legal context) | 831 | * Return 0 if operation was successful (memory to allocate, legal context) |
832 | * @xfrm_policy_clone_security: | 832 | * @xfrm_policy_clone_security: |
833 | * @old contains an existing xfrm_policy in the SPD. | 833 | * @old contains an existing xfrm_policy in the SPD. |
@@ -846,9 +846,14 @@ struct swap_info_struct; | |||
846 | * Database by the XFRM system. | 846 | * Database by the XFRM system. |
847 | * @sec_ctx contains the security context information being provided by | 847 | * @sec_ctx contains the security context information being provided by |
848 | * the user-level SA generation program (e.g., setkey or racoon). | 848 | * the user-level SA generation program (e.g., setkey or racoon). |
849 | * Allocate a security structure to the x->security field. The | 849 | * @polsec contains the security context information associated with a xfrm |
850 | * security field is initialized to NULL when the xfrm_state is | 850 | * policy rule from which to take the base context. polsec must be NULL |
851 | * allocated. | 851 | * when sec_ctx is specified. |
852 | * @secid contains the secid from which to take the mls portion of the context. | ||
853 | * Allocate a security structure to the x->security field; the security | ||
854 | * field is initialized to NULL when the xfrm_state is allocated. Set the | ||
855 | * context to correspond to either sec_ctx or polsec, with the mls portion | ||
856 | * taken from secid in the latter case. | ||
852 | * Return 0 if operation was successful (memory to allocate, legal context). | 857 | * Return 0 if operation was successful (memory to allocate, legal context). |
853 | * @xfrm_state_free_security: | 858 | * @xfrm_state_free_security: |
854 | * @x contains the xfrm_state. | 859 | * @x contains the xfrm_state. |
@@ -859,13 +864,26 @@ struct swap_info_struct; | |||
859 | * @xfrm_policy_lookup: | 864 | * @xfrm_policy_lookup: |
860 | * @xp contains the xfrm_policy for which the access control is being | 865 | * @xp contains the xfrm_policy for which the access control is being |
861 | * checked. | 866 | * checked. |
862 | * @sk_sid contains the sock security label that is used to authorize | 867 | * @fl_secid contains the flow security label that is used to authorize |
863 | * access to the policy xp. | 868 | * access to the policy xp. |
864 | * @dir contains the direction of the flow (input or output). | 869 | * @dir contains the direction of the flow (input or output). |
865 | * Check permission when a sock selects a xfrm_policy for processing | 870 | * Check permission when a flow selects a xfrm_policy for processing |
866 | * XFRMs on a packet. The hook is called when selecting either a | 871 | * XFRMs on a packet. The hook is called when selecting either a |
867 | * per-socket policy or a generic xfrm policy. | 872 | * per-socket policy or a generic xfrm policy. |
868 | * Return 0 if permission is granted. | 873 | * Return 0 if permission is granted. |
874 | * @xfrm_state_pol_flow_match: | ||
875 | * @x contains the state to match. | ||
876 | * @xp contains the policy to check for a match. | ||
877 | * @fl contains the flow to check for a match. | ||
878 | * Return 1 if there is a match. | ||
879 | * @xfrm_flow_state_match: | ||
880 | * @fl contains the flow key to match. | ||
881 | * @xfrm points to the xfrm_state to match. | ||
882 | * Return 1 if there is a match. | ||
883 | * @xfrm_decode_session: | ||
884 | * @skb points to skb to decode. | ||
885 | * @fl points to the flow key to set. | ||
886 | * Return 0 if successful decoding. | ||
869 | * | 887 | * |
870 | * Security hooks affecting all Key Management operations | 888 | * Security hooks affecting all Key Management operations |
871 | * | 889 | * |
@@ -1343,10 +1361,16 @@ struct security_operations { | |||
1343 | int (*xfrm_policy_clone_security) (struct xfrm_policy *old, struct xfrm_policy *new); | 1361 | int (*xfrm_policy_clone_security) (struct xfrm_policy *old, struct xfrm_policy *new); |
1344 | void (*xfrm_policy_free_security) (struct xfrm_policy *xp); | 1362 | void (*xfrm_policy_free_security) (struct xfrm_policy *xp); |
1345 | int (*xfrm_policy_delete_security) (struct xfrm_policy *xp); | 1363 | int (*xfrm_policy_delete_security) (struct xfrm_policy *xp); |
1346 | int (*xfrm_state_alloc_security) (struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx); | 1364 | int (*xfrm_state_alloc_security) (struct xfrm_state *x, |
1365 | struct xfrm_user_sec_ctx *sec_ctx, struct xfrm_sec_ctx *polsec, | ||
1366 | u32 secid); | ||
1347 | void (*xfrm_state_free_security) (struct xfrm_state *x); | 1367 | void (*xfrm_state_free_security) (struct xfrm_state *x); |
1348 | int (*xfrm_state_delete_security) (struct xfrm_state *x); | 1368 | int (*xfrm_state_delete_security) (struct xfrm_state *x); |
1349 | int (*xfrm_policy_lookup)(struct xfrm_policy *xp, u32 sk_sid, u8 dir); | 1369 | int (*xfrm_policy_lookup)(struct xfrm_policy *xp, u32 fl_secid, u8 dir); |
1370 | int (*xfrm_state_pol_flow_match)(struct xfrm_state *x, | ||
1371 | struct xfrm_policy *xp, struct flowi *fl); | ||
1372 | int (*xfrm_flow_state_match)(struct flowi *fl, struct xfrm_state *xfrm); | ||
1373 | int (*xfrm_decode_session)(struct sk_buff *skb, struct flowi *fl); | ||
1350 | #endif /* CONFIG_SECURITY_NETWORK_XFRM */ | 1374 | #endif /* CONFIG_SECURITY_NETWORK_XFRM */ |
1351 | 1375 | ||
1352 | /* key management security hooks */ | 1376 | /* key management security hooks */ |
@@ -3050,9 +3074,18 @@ static inline int security_xfrm_policy_delete(struct xfrm_policy *xp) | |||
3050 | return security_ops->xfrm_policy_delete_security(xp); | 3074 | return security_ops->xfrm_policy_delete_security(xp); |
3051 | } | 3075 | } |
3052 | 3076 | ||
3053 | static inline int security_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx) | 3077 | static inline int security_xfrm_state_alloc(struct xfrm_state *x, |
3078 | struct xfrm_user_sec_ctx *sec_ctx) | ||
3079 | { | ||
3080 | return security_ops->xfrm_state_alloc_security(x, sec_ctx, NULL, 0); | ||
3081 | } | ||
3082 | |||
3083 | static inline int security_xfrm_state_alloc_acquire(struct xfrm_state *x, | ||
3084 | struct xfrm_sec_ctx *polsec, u32 secid) | ||
3054 | { | 3085 | { |
3055 | return security_ops->xfrm_state_alloc_security(x, sec_ctx); | 3086 | if (!polsec) |
3087 | return 0; | ||
3088 | return security_ops->xfrm_state_alloc_security(x, NULL, polsec, secid); | ||
3056 | } | 3089 | } |
3057 | 3090 | ||
3058 | static inline int security_xfrm_state_delete(struct xfrm_state *x) | 3091 | static inline int security_xfrm_state_delete(struct xfrm_state *x) |
@@ -3065,9 +3098,25 @@ static inline void security_xfrm_state_free(struct xfrm_state *x) | |||
3065 | security_ops->xfrm_state_free_security(x); | 3098 | security_ops->xfrm_state_free_security(x); |
3066 | } | 3099 | } |
3067 | 3100 | ||
3068 | static inline int security_xfrm_policy_lookup(struct xfrm_policy *xp, u32 sk_sid, u8 dir) | 3101 | static inline int security_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir) |
3102 | { | ||
3103 | return security_ops->xfrm_policy_lookup(xp, fl_secid, dir); | ||
3104 | } | ||
3105 | |||
3106 | static inline int security_xfrm_state_pol_flow_match(struct xfrm_state *x, | ||
3107 | struct xfrm_policy *xp, struct flowi *fl) | ||
3108 | { | ||
3109 | return security_ops->xfrm_state_pol_flow_match(x, xp, fl); | ||
3110 | } | ||
3111 | |||
3112 | static inline int security_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm) | ||
3113 | { | ||
3114 | return security_ops->xfrm_flow_state_match(fl, xfrm); | ||
3115 | } | ||
3116 | |||
3117 | static inline int security_xfrm_decode_session(struct sk_buff *skb, struct flowi *fl) | ||
3069 | { | 3118 | { |
3070 | return security_ops->xfrm_policy_lookup(xp, sk_sid, dir); | 3119 | return security_ops->xfrm_decode_session(skb, fl); |
3071 | } | 3120 | } |
3072 | #else /* CONFIG_SECURITY_NETWORK_XFRM */ | 3121 | #else /* CONFIG_SECURITY_NETWORK_XFRM */ |
3073 | static inline int security_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm_user_sec_ctx *sec_ctx) | 3122 | static inline int security_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm_user_sec_ctx *sec_ctx) |
@@ -3089,7 +3138,14 @@ static inline int security_xfrm_policy_delete(struct xfrm_policy *xp) | |||
3089 | return 0; | 3138 | return 0; |
3090 | } | 3139 | } |
3091 | 3140 | ||
3092 | static inline int security_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx) | 3141 | static inline int security_xfrm_state_alloc(struct xfrm_state *x, |
3142 | struct xfrm_user_sec_ctx *sec_ctx) | ||
3143 | { | ||
3144 | return 0; | ||
3145 | } | ||
3146 | |||
3147 | static inline int security_xfrm_state_alloc_acquire(struct xfrm_state *x, | ||
3148 | struct xfrm_sec_ctx *polsec, u32 secid) | ||
3093 | { | 3149 | { |
3094 | return 0; | 3150 | return 0; |
3095 | } | 3151 | } |
@@ -3103,10 +3159,28 @@ static inline int security_xfrm_state_delete(struct xfrm_state *x) | |||
3103 | return 0; | 3159 | return 0; |
3104 | } | 3160 | } |
3105 | 3161 | ||
3106 | static inline int security_xfrm_policy_lookup(struct xfrm_policy *xp, u32 sk_sid, u8 dir) | 3162 | static inline int security_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir) |
3107 | { | 3163 | { |
3108 | return 0; | 3164 | return 0; |
3109 | } | 3165 | } |
3166 | |||
3167 | static inline int security_xfrm_state_pol_flow_match(struct xfrm_state *x, | ||
3168 | struct xfrm_policy *xp, struct flowi *fl) | ||
3169 | { | ||
3170 | return 1; | ||
3171 | } | ||
3172 | |||
3173 | static inline int security_xfrm_flow_state_match(struct flowi *fl, | ||
3174 | struct xfrm_state *xfrm) | ||
3175 | { | ||
3176 | return 1; | ||
3177 | } | ||
3178 | |||
3179 | static inline int security_xfrm_decode_session(struct sk_buff *skb, struct flowi *fl) | ||
3180 | { | ||
3181 | return 0; | ||
3182 | } | ||
3183 | |||
3110 | #endif /* CONFIG_SECURITY_NETWORK_XFRM */ | 3184 | #endif /* CONFIG_SECURITY_NETWORK_XFRM */ |
3111 | 3185 | ||
3112 | #ifdef CONFIG_KEYS | 3186 | #ifdef CONFIG_KEYS |
diff --git a/include/net/flow.h b/include/net/flow.h index 1cee5a83433a..21d988b2058a 100644 --- a/include/net/flow.h +++ b/include/net/flow.h | |||
@@ -86,10 +86,10 @@ struct flowi { | |||
86 | #define FLOW_DIR_FWD 2 | 86 | #define FLOW_DIR_FWD 2 |
87 | 87 | ||
88 | struct sock; | 88 | struct sock; |
89 | typedef void (*flow_resolve_t)(struct flowi *key, u32 sk_sid, u16 family, u8 dir, | 89 | typedef void (*flow_resolve_t)(struct flowi *key, u16 family, u8 dir, |
90 | void **objp, atomic_t **obj_refp); | 90 | void **objp, atomic_t **obj_refp); |
91 | 91 | ||
92 | extern void *flow_cache_lookup(struct flowi *key, u32 sk_sid, u16 family, u8 dir, | 92 | extern void *flow_cache_lookup(struct flowi *key, u16 family, u8 dir, |
93 | flow_resolve_t resolver); | 93 | flow_resolve_t resolver); |
94 | extern void flow_cache_flush(void); | 94 | extern void flow_cache_flush(void); |
95 | extern atomic_t flow_cache_genid; | 95 | extern atomic_t flow_cache_genid; |
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); |
diff --git a/security/dummy.c b/security/dummy.c index bd3bc5faa9a8..c1f10654871e 100644 --- a/security/dummy.c +++ b/security/dummy.c | |||
@@ -835,7 +835,8 @@ static int dummy_xfrm_policy_delete_security(struct xfrm_policy *xp) | |||
835 | return 0; | 835 | return 0; |
836 | } | 836 | } |
837 | 837 | ||
838 | static int dummy_xfrm_state_alloc_security(struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx) | 838 | static int dummy_xfrm_state_alloc_security(struct xfrm_state *x, |
839 | struct xfrm_user_sec_ctx *sec_ctx, struct xfrm_sec_ctx *pol, u32 secid) | ||
839 | { | 840 | { |
840 | return 0; | 841 | return 0; |
841 | } | 842 | } |
@@ -853,6 +854,23 @@ static int dummy_xfrm_policy_lookup(struct xfrm_policy *xp, u32 sk_sid, u8 dir) | |||
853 | { | 854 | { |
854 | return 0; | 855 | return 0; |
855 | } | 856 | } |
857 | |||
858 | static int dummy_xfrm_state_pol_flow_match(struct xfrm_state *x, | ||
859 | struct xfrm_policy *xp, struct flowi *fl) | ||
860 | { | ||
861 | return 1; | ||
862 | } | ||
863 | |||
864 | static int dummy_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm) | ||
865 | { | ||
866 | return 1; | ||
867 | } | ||
868 | |||
869 | static int dummy_xfrm_decode_session(struct sk_buff *skb, struct flowi *fl) | ||
870 | { | ||
871 | return 0; | ||
872 | } | ||
873 | |||
856 | #endif /* CONFIG_SECURITY_NETWORK_XFRM */ | 874 | #endif /* CONFIG_SECURITY_NETWORK_XFRM */ |
857 | static int dummy_register_security (const char *name, struct security_operations *ops) | 875 | static int dummy_register_security (const char *name, struct security_operations *ops) |
858 | { | 876 | { |
@@ -1076,6 +1094,9 @@ void security_fixup_ops (struct security_operations *ops) | |||
1076 | set_to_dummy_if_null(ops, xfrm_state_free_security); | 1094 | set_to_dummy_if_null(ops, xfrm_state_free_security); |
1077 | set_to_dummy_if_null(ops, xfrm_state_delete_security); | 1095 | set_to_dummy_if_null(ops, xfrm_state_delete_security); |
1078 | set_to_dummy_if_null(ops, xfrm_policy_lookup); | 1096 | set_to_dummy_if_null(ops, xfrm_policy_lookup); |
1097 | set_to_dummy_if_null(ops, xfrm_state_pol_flow_match); | ||
1098 | set_to_dummy_if_null(ops, xfrm_flow_state_match); | ||
1099 | set_to_dummy_if_null(ops, xfrm_decode_session); | ||
1079 | #endif /* CONFIG_SECURITY_NETWORK_XFRM */ | 1100 | #endif /* CONFIG_SECURITY_NETWORK_XFRM */ |
1080 | #ifdef CONFIG_KEYS | 1101 | #ifdef CONFIG_KEYS |
1081 | set_to_dummy_if_null(ops, key_alloc); | 1102 | set_to_dummy_if_null(ops, key_alloc); |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index d67abf77584a..5c189da07bc9 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -3468,7 +3468,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
3468 | if (err) | 3468 | if (err) |
3469 | goto out; | 3469 | goto out; |
3470 | 3470 | ||
3471 | err = selinux_xfrm_sock_rcv_skb(sock_sid, skb); | 3471 | err = selinux_xfrm_sock_rcv_skb(sock_sid, skb, &ad); |
3472 | out: | 3472 | out: |
3473 | return err; | 3473 | return err; |
3474 | } | 3474 | } |
@@ -3720,7 +3720,7 @@ static unsigned int selinux_ip_postroute_last(unsigned int hooknum, | |||
3720 | if (err) | 3720 | if (err) |
3721 | goto out; | 3721 | goto out; |
3722 | 3722 | ||
3723 | err = selinux_xfrm_postroute_last(isec->sid, skb); | 3723 | err = selinux_xfrm_postroute_last(isec->sid, skb, &ad); |
3724 | out: | 3724 | out: |
3725 | return err ? NF_DROP : NF_ACCEPT; | 3725 | return err ? NF_DROP : NF_ACCEPT; |
3726 | } | 3726 | } |
@@ -4633,6 +4633,9 @@ static struct security_operations selinux_ops = { | |||
4633 | .xfrm_state_free_security = selinux_xfrm_state_free, | 4633 | .xfrm_state_free_security = selinux_xfrm_state_free, |
4634 | .xfrm_state_delete_security = selinux_xfrm_state_delete, | 4634 | .xfrm_state_delete_security = selinux_xfrm_state_delete, |
4635 | .xfrm_policy_lookup = selinux_xfrm_policy_lookup, | 4635 | .xfrm_policy_lookup = selinux_xfrm_policy_lookup, |
4636 | .xfrm_state_pol_flow_match = selinux_xfrm_state_pol_flow_match, | ||
4637 | .xfrm_flow_state_match = selinux_xfrm_flow_state_match, | ||
4638 | .xfrm_decode_session = selinux_xfrm_decode_session, | ||
4636 | #endif | 4639 | #endif |
4637 | 4640 | ||
4638 | #ifdef CONFIG_KEYS | 4641 | #ifdef CONFIG_KEYS |
diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h index c96498a10eb8..f51a3e84bd9b 100644 --- a/security/selinux/include/xfrm.h +++ b/security/selinux/include/xfrm.h | |||
@@ -2,6 +2,7 @@ | |||
2 | * SELinux support for the XFRM LSM hooks | 2 | * SELinux support for the XFRM LSM hooks |
3 | * | 3 | * |
4 | * Author : Trent Jaeger, <jaegert@us.ibm.com> | 4 | * Author : Trent Jaeger, <jaegert@us.ibm.com> |
5 | * Updated : Venkat Yekkirala, <vyekkirala@TrustedCS.com> | ||
5 | */ | 6 | */ |
6 | #ifndef _SELINUX_XFRM_H_ | 7 | #ifndef _SELINUX_XFRM_H_ |
7 | #define _SELINUX_XFRM_H_ | 8 | #define _SELINUX_XFRM_H_ |
@@ -10,10 +11,16 @@ int selinux_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm_user_sec_ctx * | |||
10 | int selinux_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new); | 11 | int selinux_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new); |
11 | void selinux_xfrm_policy_free(struct xfrm_policy *xp); | 12 | void selinux_xfrm_policy_free(struct xfrm_policy *xp); |
12 | int selinux_xfrm_policy_delete(struct xfrm_policy *xp); | 13 | int selinux_xfrm_policy_delete(struct xfrm_policy *xp); |
13 | int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx); | 14 | int selinux_xfrm_state_alloc(struct xfrm_state *x, |
15 | struct xfrm_user_sec_ctx *sec_ctx, struct xfrm_sec_ctx *pol, u32 secid); | ||
14 | void selinux_xfrm_state_free(struct xfrm_state *x); | 16 | void selinux_xfrm_state_free(struct xfrm_state *x); |
15 | int selinux_xfrm_state_delete(struct xfrm_state *x); | 17 | int selinux_xfrm_state_delete(struct xfrm_state *x); |
16 | int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 sk_sid, u8 dir); | 18 | int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir); |
19 | int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, | ||
20 | struct xfrm_policy *xp, struct flowi *fl); | ||
21 | int selinux_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm); | ||
22 | int selinux_xfrm_decode_session(struct sk_buff *skb, struct flowi *fl); | ||
23 | |||
17 | 24 | ||
18 | /* | 25 | /* |
19 | * Extract the security blob from the sock (it's actually on the socket) | 26 | * Extract the security blob from the sock (it's actually on the socket) |
@@ -39,17 +46,21 @@ static inline u32 selinux_no_sk_sid(struct flowi *fl) | |||
39 | } | 46 | } |
40 | 47 | ||
41 | #ifdef CONFIG_SECURITY_NETWORK_XFRM | 48 | #ifdef CONFIG_SECURITY_NETWORK_XFRM |
42 | int selinux_xfrm_sock_rcv_skb(u32 sid, struct sk_buff *skb); | 49 | int selinux_xfrm_sock_rcv_skb(u32 sid, struct sk_buff *skb, |
43 | int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb); | 50 | struct avc_audit_data *ad); |
51 | int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, | ||
52 | struct avc_audit_data *ad); | ||
44 | u32 selinux_socket_getpeer_stream(struct sock *sk); | 53 | u32 selinux_socket_getpeer_stream(struct sock *sk); |
45 | u32 selinux_socket_getpeer_dgram(struct sk_buff *skb); | 54 | u32 selinux_socket_getpeer_dgram(struct sk_buff *skb); |
46 | #else | 55 | #else |
47 | static inline int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb) | 56 | static inline int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, |
57 | struct avc_audit_data *ad) | ||
48 | { | 58 | { |
49 | return 0; | 59 | return 0; |
50 | } | 60 | } |
51 | 61 | ||
52 | static inline int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb) | 62 | static inline int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, |
63 | struct avc_audit_data *ad) | ||
53 | { | 64 | { |
54 | return 0; | 65 | return 0; |
55 | } | 66 | } |
diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c index 6c985ced8102..a502b0540e3d 100644 --- a/security/selinux/xfrm.c +++ b/security/selinux/xfrm.c | |||
@@ -6,7 +6,12 @@ | |||
6 | * Authors: Serge Hallyn <sergeh@us.ibm.com> | 6 | * Authors: Serge Hallyn <sergeh@us.ibm.com> |
7 | * Trent Jaeger <jaegert@us.ibm.com> | 7 | * Trent Jaeger <jaegert@us.ibm.com> |
8 | * | 8 | * |
9 | * Updated: Venkat Yekkirala <vyekkirala@TrustedCS.com> | ||
10 | * | ||
11 | * Granular IPSec Associations for use in MLS environments. | ||
12 | * | ||
9 | * Copyright (C) 2005 International Business Machines Corporation | 13 | * Copyright (C) 2005 International Business Machines Corporation |
14 | * Copyright (C) 2006 Trusted Computer Solutions, Inc. | ||
10 | * | 15 | * |
11 | * This program is free software; you can redistribute it and/or modify | 16 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License version 2, | 17 | * it under the terms of the GNU General Public License version 2, |
@@ -67,10 +72,10 @@ static inline int selinux_authorizable_xfrm(struct xfrm_state *x) | |||
67 | } | 72 | } |
68 | 73 | ||
69 | /* | 74 | /* |
70 | * LSM hook implementation that authorizes that a socket can be used | 75 | * LSM hook implementation that authorizes that a flow can use |
71 | * with the corresponding xfrm_sec_ctx and direction. | 76 | * a xfrm policy rule. |
72 | */ | 77 | */ |
73 | int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 sk_sid, u8 dir) | 78 | int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir) |
74 | { | 79 | { |
75 | int rc = 0; | 80 | int rc = 0; |
76 | u32 sel_sid = SECINITSID_UNLABELED; | 81 | u32 sel_sid = SECINITSID_UNLABELED; |
@@ -84,27 +89,129 @@ int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 sk_sid, u8 dir) | |||
84 | sel_sid = ctx->ctx_sid; | 89 | sel_sid = ctx->ctx_sid; |
85 | } | 90 | } |
86 | 91 | ||
87 | rc = avc_has_perm(sk_sid, sel_sid, SECCLASS_ASSOCIATION, | 92 | rc = avc_has_perm(fl_secid, sel_sid, SECCLASS_ASSOCIATION, |
88 | ((dir == FLOW_DIR_IN) ? ASSOCIATION__RECVFROM : | 93 | ASSOCIATION__POLMATCH, |
89 | ((dir == FLOW_DIR_OUT) ? ASSOCIATION__SENDTO : | ||
90 | (ASSOCIATION__SENDTO | ASSOCIATION__RECVFROM))), | ||
91 | NULL); | 94 | NULL); |
92 | 95 | ||
93 | return rc; | 96 | return rc; |
94 | } | 97 | } |
95 | 98 | ||
96 | /* | 99 | /* |
100 | * LSM hook implementation that authorizes that a state matches | ||
101 | * the given policy, flow combo. | ||
102 | */ | ||
103 | |||
104 | int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy *xp, | ||
105 | struct flowi *fl) | ||
106 | { | ||
107 | u32 state_sid; | ||
108 | u32 pol_sid; | ||
109 | int err; | ||
110 | |||
111 | if (x->security) | ||
112 | state_sid = x->security->ctx_sid; | ||
113 | else | ||
114 | state_sid = SECINITSID_UNLABELED; | ||
115 | |||
116 | if (xp->security) | ||
117 | pol_sid = xp->security->ctx_sid; | ||
118 | else | ||
119 | pol_sid = SECINITSID_UNLABELED; | ||
120 | |||
121 | err = avc_has_perm(state_sid, pol_sid, SECCLASS_ASSOCIATION, | ||
122 | ASSOCIATION__POLMATCH, | ||
123 | NULL); | ||
124 | |||
125 | if (err) | ||
126 | return 0; | ||
127 | |||
128 | return selinux_xfrm_flow_state_match(fl, x); | ||
129 | } | ||
130 | |||
131 | /* | ||
132 | * LSM hook implementation that authorizes that a particular outgoing flow | ||
133 | * can use a given security association. | ||
134 | */ | ||
135 | |||
136 | int selinux_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm) | ||
137 | { | ||
138 | int rc = 0; | ||
139 | u32 sel_sid = SECINITSID_UNLABELED; | ||
140 | struct xfrm_sec_ctx *ctx; | ||
141 | |||
142 | /* Context sid is either set to label or ANY_ASSOC */ | ||
143 | if ((ctx = xfrm->security)) { | ||
144 | if (!selinux_authorizable_ctx(ctx)) | ||
145 | return 0; | ||
146 | |||
147 | sel_sid = ctx->ctx_sid; | ||
148 | } | ||
149 | |||
150 | rc = avc_has_perm(fl->secid, sel_sid, SECCLASS_ASSOCIATION, | ||
151 | ASSOCIATION__SENDTO, | ||
152 | NULL)? 0:1; | ||
153 | |||
154 | return rc; | ||
155 | } | ||
156 | |||
157 | /* | ||
158 | * LSM hook implementation that determines the sid for the session. | ||
159 | */ | ||
160 | |||
161 | int selinux_xfrm_decode_session(struct sk_buff *skb, struct flowi *fl) | ||
162 | { | ||
163 | struct sec_path *sp; | ||
164 | |||
165 | fl->secid = SECSID_NULL; | ||
166 | |||
167 | if (skb == NULL) | ||
168 | return 0; | ||
169 | |||
170 | sp = skb->sp; | ||
171 | if (sp) { | ||
172 | int i, sid_set = 0; | ||
173 | |||
174 | for (i = sp->len-1; i >= 0; i--) { | ||
175 | struct xfrm_state *x = sp->xvec[i]; | ||
176 | if (selinux_authorizable_xfrm(x)) { | ||
177 | struct xfrm_sec_ctx *ctx = x->security; | ||
178 | |||
179 | if (!sid_set) { | ||
180 | fl->secid = ctx->ctx_sid; | ||
181 | sid_set = 1; | ||
182 | } | ||
183 | else if (fl->secid != ctx->ctx_sid) | ||
184 | return -EINVAL; | ||
185 | } | ||
186 | } | ||
187 | } | ||
188 | |||
189 | return 0; | ||
190 | } | ||
191 | |||
192 | /* | ||
97 | * Security blob allocation for xfrm_policy and xfrm_state | 193 | * Security blob allocation for xfrm_policy and xfrm_state |
98 | * CTX does not have a meaningful value on input | 194 | * CTX does not have a meaningful value on input |
99 | */ | 195 | */ |
100 | static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp, struct xfrm_user_sec_ctx *uctx) | 196 | static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp, |
197 | struct xfrm_user_sec_ctx *uctx, struct xfrm_sec_ctx *pol, u32 sid) | ||
101 | { | 198 | { |
102 | int rc = 0; | 199 | int rc = 0; |
103 | struct task_security_struct *tsec = current->security; | 200 | struct task_security_struct *tsec = current->security; |
104 | struct xfrm_sec_ctx *ctx; | 201 | struct xfrm_sec_ctx *ctx = NULL; |
202 | char *ctx_str = NULL; | ||
203 | u32 str_len; | ||
204 | u32 ctx_sid; | ||
205 | |||
206 | BUG_ON(uctx && pol); | ||
207 | |||
208 | if (pol) | ||
209 | goto from_policy; | ||
105 | 210 | ||
106 | BUG_ON(!uctx); | 211 | BUG_ON(!uctx); |
107 | BUG_ON(uctx->ctx_doi != XFRM_SC_ALG_SELINUX); | 212 | |
213 | if (uctx->ctx_doi != XFRM_SC_ALG_SELINUX) | ||
214 | return -EINVAL; | ||
108 | 215 | ||
109 | if (uctx->ctx_len >= PAGE_SIZE) | 216 | if (uctx->ctx_len >= PAGE_SIZE) |
110 | return -ENOMEM; | 217 | return -ENOMEM; |
@@ -141,9 +248,41 @@ static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp, struct xfrm_us | |||
141 | 248 | ||
142 | return rc; | 249 | return rc; |
143 | 250 | ||
251 | from_policy: | ||
252 | BUG_ON(!pol); | ||
253 | rc = security_sid_mls_copy(pol->ctx_sid, sid, &ctx_sid); | ||
254 | if (rc) | ||
255 | goto out; | ||
256 | |||
257 | rc = security_sid_to_context(ctx_sid, &ctx_str, &str_len); | ||
258 | if (rc) | ||
259 | goto out; | ||
260 | |||
261 | *ctxp = ctx = kmalloc(sizeof(*ctx) + | ||
262 | str_len, | ||
263 | GFP_ATOMIC); | ||
264 | |||
265 | if (!ctx) { | ||
266 | rc = -ENOMEM; | ||
267 | goto out; | ||
268 | } | ||
269 | |||
270 | |||
271 | ctx->ctx_doi = XFRM_SC_DOI_LSM; | ||
272 | ctx->ctx_alg = XFRM_SC_ALG_SELINUX; | ||
273 | ctx->ctx_sid = ctx_sid; | ||
274 | ctx->ctx_len = str_len; | ||
275 | memcpy(ctx->ctx_str, | ||
276 | ctx_str, | ||
277 | str_len); | ||
278 | |||
279 | goto out2; | ||
280 | |||
144 | out: | 281 | out: |
145 | *ctxp = NULL; | 282 | *ctxp = NULL; |
146 | kfree(ctx); | 283 | kfree(ctx); |
284 | out2: | ||
285 | kfree(ctx_str); | ||
147 | return rc; | 286 | return rc; |
148 | } | 287 | } |
149 | 288 | ||
@@ -157,7 +296,7 @@ int selinux_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm_user_sec_ctx * | |||
157 | 296 | ||
158 | BUG_ON(!xp); | 297 | BUG_ON(!xp); |
159 | 298 | ||
160 | err = selinux_xfrm_sec_ctx_alloc(&xp->security, uctx); | 299 | err = selinux_xfrm_sec_ctx_alloc(&xp->security, uctx, NULL, 0); |
161 | return err; | 300 | return err; |
162 | } | 301 | } |
163 | 302 | ||
@@ -217,13 +356,14 @@ int selinux_xfrm_policy_delete(struct xfrm_policy *xp) | |||
217 | * LSM hook implementation that allocs and transfers sec_ctx spec to | 356 | * LSM hook implementation that allocs and transfers sec_ctx spec to |
218 | * xfrm_state. | 357 | * xfrm_state. |
219 | */ | 358 | */ |
220 | int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *uctx) | 359 | int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *uctx, |
360 | struct xfrm_sec_ctx *pol, u32 secid) | ||
221 | { | 361 | { |
222 | int err; | 362 | int err; |
223 | 363 | ||
224 | BUG_ON(!x); | 364 | BUG_ON(!x); |
225 | 365 | ||
226 | err = selinux_xfrm_sec_ctx_alloc(&x->security, uctx); | 366 | err = selinux_xfrm_sec_ctx_alloc(&x->security, uctx, pol, secid); |
227 | return err; | 367 | return err; |
228 | } | 368 | } |
229 | 369 | ||
@@ -329,38 +469,30 @@ int selinux_xfrm_state_delete(struct xfrm_state *x) | |||
329 | * we need to check for unlabelled access since this may not have | 469 | * we need to check for unlabelled access since this may not have |
330 | * gone thru the IPSec process. | 470 | * gone thru the IPSec process. |
331 | */ | 471 | */ |
332 | int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb) | 472 | int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, |
473 | struct avc_audit_data *ad) | ||
333 | { | 474 | { |
334 | int i, rc = 0; | 475 | int i, rc = 0; |
335 | struct sec_path *sp; | 476 | struct sec_path *sp; |
477 | u32 sel_sid = SECINITSID_UNLABELED; | ||
336 | 478 | ||
337 | sp = skb->sp; | 479 | sp = skb->sp; |
338 | 480 | ||
339 | if (sp) { | 481 | if (sp) { |
340 | /* | ||
341 | * __xfrm_policy_check does not approve unless xfrm_policy_ok | ||
342 | * says that spi's match for policy and the socket. | ||
343 | * | ||
344 | * Only need to verify the existence of an authorizable sp. | ||
345 | */ | ||
346 | for (i = 0; i < sp->len; i++) { | 482 | for (i = 0; i < sp->len; i++) { |
347 | struct xfrm_state *x = sp->xvec[i]; | 483 | struct xfrm_state *x = sp->xvec[i]; |
348 | 484 | ||
349 | if (x && selinux_authorizable_xfrm(x)) | 485 | if (x && selinux_authorizable_xfrm(x)) { |
350 | goto accept; | 486 | struct xfrm_sec_ctx *ctx = x->security; |
487 | sel_sid = ctx->ctx_sid; | ||
488 | break; | ||
489 | } | ||
351 | } | 490 | } |
352 | } | 491 | } |
353 | 492 | ||
354 | /* check SELinux sock for unlabelled access */ | 493 | rc = avc_has_perm(isec_sid, sel_sid, SECCLASS_ASSOCIATION, |
355 | rc = avc_has_perm(isec_sid, SECINITSID_UNLABELED, SECCLASS_ASSOCIATION, | 494 | ASSOCIATION__RECVFROM, ad); |
356 | ASSOCIATION__RECVFROM, NULL); | ||
357 | if (rc) | ||
358 | goto drop; | ||
359 | |||
360 | accept: | ||
361 | return 0; | ||
362 | 495 | ||
363 | drop: | ||
364 | return rc; | 496 | return rc; |
365 | } | 497 | } |
366 | 498 | ||
@@ -371,7 +503,8 @@ drop: | |||
371 | * If we do have a authorizable security association, then it has already been | 503 | * If we do have a authorizable security association, then it has already been |
372 | * checked in xfrm_policy_lookup hook. | 504 | * checked in xfrm_policy_lookup hook. |
373 | */ | 505 | */ |
374 | int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb) | 506 | int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, |
507 | struct avc_audit_data *ad) | ||
375 | { | 508 | { |
376 | struct dst_entry *dst; | 509 | struct dst_entry *dst; |
377 | int rc = 0; | 510 | int rc = 0; |
@@ -391,7 +524,7 @@ int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb) | |||
391 | } | 524 | } |
392 | 525 | ||
393 | rc = avc_has_perm(isec_sid, SECINITSID_UNLABELED, SECCLASS_ASSOCIATION, | 526 | rc = avc_has_perm(isec_sid, SECINITSID_UNLABELED, SECCLASS_ASSOCIATION, |
394 | ASSOCIATION__SENDTO, NULL); | 527 | ASSOCIATION__SENDTO, ad); |
395 | out: | 528 | out: |
396 | return rc; | 529 | return rc; |
397 | } | 530 | } |