aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVenkat Yekkirala <vyekkirala@TrustedCS.com>2006-07-25 02:29:07 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2006-09-22 17:53:24 -0400
commite0d1caa7b0d5f02e4f34aa09c695d04251310c6c (patch)
treebf023c17abf6813f2694ebf5fafff82edd6a1023
parentb6340fcd761acf9249b3acbc95c4dc555d9beb07 (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.h106
-rw-r--r--include/net/flow.h4
-rw-r--r--net/core/flow.c7
-rw-r--r--net/xfrm/xfrm_policy.c28
-rw-r--r--net/xfrm/xfrm_state.c12
-rw-r--r--security/dummy.c23
-rw-r--r--security/selinux/hooks.c7
-rw-r--r--security/selinux/include/xfrm.h23
-rw-r--r--security/selinux/xfrm.c199
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
35struct ctl_table; 36struct 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
3053static inline int security_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx) 3077static 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
3083static 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
3058static inline int security_xfrm_state_delete(struct xfrm_state *x) 3091static 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
3068static inline int security_xfrm_policy_lookup(struct xfrm_policy *xp, u32 sk_sid, u8 dir) 3101static 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
3106static 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
3112static 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
3117static 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 */
3073static inline int security_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm_user_sec_ctx *sec_ctx) 3122static 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
3092static inline int security_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx) 3141static inline int security_xfrm_state_alloc(struct xfrm_state *x,
3142 struct xfrm_user_sec_ctx *sec_ctx)
3143{
3144 return 0;
3145}
3146
3147static 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
3106static inline int security_xfrm_policy_lookup(struct xfrm_policy *xp, u32 sk_sid, u8 dir) 3162static 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
3167static 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
3173static inline int security_xfrm_flow_state_match(struct flowi *fl,
3174 struct xfrm_state *xfrm)
3175{
3176 return 1;
3177}
3178
3179static 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
88struct sock; 88struct sock;
89typedef void (*flow_resolve_t)(struct flowi *key, u32 sk_sid, u16 family, u8 dir, 89typedef 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
92extern void *flow_cache_lookup(struct flowi *key, u32 sk_sid, u16 family, u8 dir, 92extern void *flow_cache_lookup(struct flowi *key, u16 family, u8 dir,
93 flow_resolve_t resolver); 93 flow_resolve_t resolver);
94extern void flow_cache_flush(void); 94extern void flow_cache_flush(void);
95extern atomic_t flow_cache_genid; 95extern 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
168void *flow_cache_lookup(struct flowi *key, u32 sk_sid, u16 family, u8 dir, 167void *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
600static void xfrm_policy_lookup(struct flowi *fl, u32 sk_sid, u16 family, u8 dir, 600static 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
644static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struct flowi *fl, u32 sk_sid) 644static 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);
866restart: 867restart:
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
1032xfrm_decode_session(struct sk_buff *skb, struct flowi *fl, unsigned short family) 1033xfrm_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}
1043EXPORT_SYMBOL(xfrm_decode_session); 1046EXPORT_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
838static int dummy_xfrm_state_alloc_security(struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx) 838static 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
858static 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
864static int dummy_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm)
865{
866 return 1;
867}
868
869static 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 */
857static int dummy_register_security (const char *name, struct security_operations *ops) 875static 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);
3472out: 3472out:
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);
3724out: 3724out:
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 *
10int selinux_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new); 11int selinux_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new);
11void selinux_xfrm_policy_free(struct xfrm_policy *xp); 12void selinux_xfrm_policy_free(struct xfrm_policy *xp);
12int selinux_xfrm_policy_delete(struct xfrm_policy *xp); 13int selinux_xfrm_policy_delete(struct xfrm_policy *xp);
13int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx); 14int selinux_xfrm_state_alloc(struct xfrm_state *x,
15 struct xfrm_user_sec_ctx *sec_ctx, struct xfrm_sec_ctx *pol, u32 secid);
14void selinux_xfrm_state_free(struct xfrm_state *x); 16void selinux_xfrm_state_free(struct xfrm_state *x);
15int selinux_xfrm_state_delete(struct xfrm_state *x); 17int selinux_xfrm_state_delete(struct xfrm_state *x);
16int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 sk_sid, u8 dir); 18int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir);
19int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x,
20 struct xfrm_policy *xp, struct flowi *fl);
21int selinux_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm);
22int 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
42int selinux_xfrm_sock_rcv_skb(u32 sid, struct sk_buff *skb); 49int selinux_xfrm_sock_rcv_skb(u32 sid, struct sk_buff *skb,
43int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb); 50 struct avc_audit_data *ad);
51int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb,
52 struct avc_audit_data *ad);
44u32 selinux_socket_getpeer_stream(struct sock *sk); 53u32 selinux_socket_getpeer_stream(struct sock *sk);
45u32 selinux_socket_getpeer_dgram(struct sk_buff *skb); 54u32 selinux_socket_getpeer_dgram(struct sk_buff *skb);
46#else 55#else
47static inline int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb) 56static 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
52static inline int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb) 62static 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 */
73int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 sk_sid, u8 dir) 78int 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
104int 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
136int 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
161int 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 */
100static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp, struct xfrm_user_sec_ctx *uctx) 196static 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
251from_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
144out: 281out:
145 *ctxp = NULL; 282 *ctxp = NULL;
146 kfree(ctx); 283 kfree(ctx);
284out2:
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 */
220int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *uctx) 359int 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 */
332int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb) 472int 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
360accept:
361 return 0;
362 495
363drop:
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 */
374int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb) 506int 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);
395out: 528out:
396 return rc; 529 return rc;
397} 530}