[redhat-lspp] [RFC][MLSXFRM 03/04] Add controls to xfrm subsystem

Venkat Yekkirala vyekkirala at trustedcs.com
Tue Jun 13 22:09:30 UTC 2006


This patch adds/modifies SELinux access checks for security associations on
the inbound, on the outbound as well as during policy lookups, taking into
account the security context of the flow, the SA, and the policy rule.
It also includes the security context to be used by IKE, in the acquire
messages sent to the IKE daemons so that the daemons could include the
security context in the negotiation resulting in a unique security association
for the security context. Code also has been cleaned up to reflect the inclusion
(also in this patch set) of sid in the flow key itself.

Signed-off-by: Venkat Yekkirala <vyekkirala at TrustedCS.com>

---

NOTE: Policy for an inbound packet is now looked up based on the security context of
the SA (if any) used by the packet; formerly the lookup was based on the socket's security
context. This was done since a socket's security context could match multiple policy rules.
The socket's access to the SA is now checked in selinux_xfrm_sock_rcv_skb().

Also, on the outbound, the flow's security context must also now match the SA's since multiple
SAs could now match a policy rule, not all of which could be used by the flow. Also now the
security context of the SAs in a bundle have to match the flow for the flow to use the bundle.

net/key/af_key.c       |   24 +++++++++++++++++++++++-
net/xfrm/xfrm_policy.c |   28 +++++++++++++++-------------
net/xfrm/xfrm_state.c  |   12 ++++++++++--
net/xfrm/xfrm_user.c   |    2 +-
4 files changed, 49 insertions(+), 17 deletions(-)

--- linux-2.6.16.vanilla/net/key/af_key.c	2006-06-12 17:49:42.000000000 -0500
+++ linux-2.6.16/net/key/af_key.c	2006-06-13 08:40:48.000000000 -0500
@@ -1079,7 +1079,7 @@ static struct xfrm_state * pfkey_msg2xfr
 		if (!uctx)
 			goto out;
 
-		err = security_xfrm_state_alloc(x, uctx);
+		err = security_xfrm_state_alloc(x, uctx, NULL, 0);
 		kfree(uctx);
 
 		if (err)
@@ -2709,6 +2709,9 @@ static int pfkey_send_acquire(struct xfr
 #endif
 	int sockaddr_size;
 	int size;
+	struct sadb_x_sec_ctx *sec_ctx;
+	struct xfrm_sec_ctx *xfrm_ctx;
+	int ctx_size = 0;
 	
 	sockaddr_size = pfkey_sockaddr_size(x->props.family);
 	if (!sockaddr_size)
@@ -2724,6 +2727,11 @@ static int pfkey_send_acquire(struct xfr
 	else if (x->id.proto == IPPROTO_ESP)
 		size += count_esp_combs(t);
 
+	if ((xfrm_ctx = x->security)) {
+		ctx_size = PFKEY_ALIGN8(xfrm_ctx->ctx_len);
+		size +=  sizeof(struct sadb_x_sec_ctx) + ctx_size;
+	}
+
 	skb =  alloc_skb(size + 16, GFP_ATOMIC);
 	if (skb == NULL)
 		return -ENOMEM;
@@ -2819,6 +2827,20 @@ static int pfkey_send_acquire(struct xfr
 	else if (x->id.proto == IPPROTO_ESP)
 		dump_esp_combs(skb, t);
 
+	/* security context */
+	if (xfrm_ctx) {
+		sec_ctx = (struct sadb_x_sec_ctx *) skb_put(skb,
+				sizeof(struct sadb_x_sec_ctx) + ctx_size);
+		sec_ctx->sadb_x_sec_len =
+		  (sizeof(struct sadb_x_sec_ctx) + ctx_size) / sizeof(uint64_t);
+		sec_ctx->sadb_x_sec_exttype = SADB_X_EXT_SEC_CTX;
+		sec_ctx->sadb_x_ctx_doi = xfrm_ctx->ctx_doi;
+		sec_ctx->sadb_x_ctx_alg = xfrm_ctx->ctx_alg;
+		sec_ctx->sadb_x_ctx_len = xfrm_ctx->ctx_len;
+		memcpy(sec_ctx + 1, xfrm_ctx->ctx_str,
+		       xfrm_ctx->ctx_len);
+	}
+
 	return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL);
 }
 
--- linux-2.6.16.vanilla/net/xfrm/xfrm_policy.c	2006-06-12 17:49:42.000000000 -0500
+++ linux-2.6.16/net/xfrm/xfrm_policy.c	2006-06-13 08:40:48.000000000 -0500
@@ -599,7 +599,7 @@ EXPORT_SYMBOL(xfrm_policy_walk);
 
 /* Find policy to apply to this flow. */
 
-static void xfrm_policy_lookup(struct flowi *fl, u32 sk_sid, u16 family, u8 dir,
+static void xfrm_policy_lookup(struct flowi *fl, u16 family, u8 dir,
 			       void **objp, atomic_t **obj_refp)
 {
 	struct xfrm_policy *pol;
@@ -615,7 +615,7 @@ static void xfrm_policy_lookup(struct fl
 		match = xfrm_selector_match(sel, fl, family);
 
 		if (match) {
- 			if (!security_xfrm_policy_lookup(pol, sk_sid, dir)) {
+ 			if (!security_xfrm_policy_lookup(pol, fl->sid, dir)) {
 				xfrm_pol_hold(pol);
 				break;
 			}
@@ -643,7 +643,7 @@ static inline int policy_to_flow_dir(int
 	};
 }
 
-static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struct flowi *fl, u32 sk_sid)
+static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struct flowi *fl)
 {
 	struct xfrm_policy *pol;
 
@@ -654,7 +654,7 @@ static struct xfrm_policy *xfrm_sk_polic
  		int err = 0;
 
 		if (match)
-		  err = security_xfrm_policy_lookup(pol, sk_sid, policy_to_flow_dir(dir));
+		  err = security_xfrm_policy_lookup(pol, fl->sid, policy_to_flow_dir(dir));
 
  		if (match && !err)
 			xfrm_pol_hold(pol);
@@ -864,19 +864,20 @@ int xfrm_lookup(struct dst_entry **dst_p
 	u32 genid;
 	u16 family;
 	u8 dir = policy_to_flow_dir(XFRM_POLICY_OUT);
-	u32 sk_sid = security_sk_sid(sk, fl, dir);
+
+	fl->sid = security_sk_sid(sk, fl, dir);
 restart:
 	genid = atomic_read(&flow_cache_genid);
 	policy = NULL;
 	if (sk && sk->sk_policy[1])
-		policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl, sk_sid);
+		policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl);
 
 	if (!policy) {
 		/* To accelerate a bit...  */
 		if ((dst_orig->flags & DST_NOXFRM) || !xfrm_policy_list[XFRM_POLICY_OUT])
 			return 0;
 
-		policy = flow_cache_lookup(fl, sk_sid, dst_orig->ops->family,
+		policy = flow_cache_lookup(fl, dst_orig->ops->family,
 					   dir, xfrm_policy_lookup);
 	}
 
@@ -1034,13 +1035,15 @@ int
 xfrm_decode_session(struct sk_buff *skb, struct flowi *fl, unsigned short family)
 {
 	struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
+	int err;
 
 	if (unlikely(afinfo == NULL))
 		return -EAFNOSUPPORT;
 
 	afinfo->decode_session(skb, fl);
+	err = security_xfrm_decode_session(skb, fl);
 	xfrm_policy_put_afinfo(afinfo);
-	return 0;
+	return err;
 }
 EXPORT_SYMBOL(xfrm_decode_session);
 
@@ -1060,14 +1063,11 @@ int __xfrm_policy_check(struct sock *sk,
 	struct xfrm_policy *pol;
 	struct flowi fl;
 	u8 fl_dir = policy_to_flow_dir(dir);
-	u32 sk_sid;
 
 	if (xfrm_decode_session(skb, &fl, family) < 0)
 		return 0;
 	nf_nat_decode_session(skb, &fl, family);
 
-	sk_sid = security_sk_sid(sk, &fl, fl_dir);
-
 	/* First, check used SA against their selectors. */
 	if (skb->sp) {
 		int i;
@@ -1081,10 +1081,10 @@ int __xfrm_policy_check(struct sock *sk,
 
 	pol = NULL;
 	if (sk && sk->sk_policy[dir])
-		pol = xfrm_sk_policy_lookup(sk, dir, &fl, sk_sid);
+		pol = xfrm_sk_policy_lookup(sk, dir, &fl);
 
 	if (!pol)
-		pol = flow_cache_lookup(&fl, sk_sid, family, fl_dir,
+		pol = flow_cache_lookup(&fl, family, fl_dir,
 					xfrm_policy_lookup);
 
 	if (!pol)
@@ -1279,6 +1279,8 @@ int xfrm_bundle_ok(struct xfrm_dst *firs
 
 		if (fl && !xfrm_selector_match(&dst->xfrm->sel, fl, family))
 			return 0;
+		if (fl && !security_xfrm_flow_state_match(fl, dst->xfrm))
+			return 0;
 		if (dst->xfrm->km.state != XFRM_STATE_VALID)
 			return 0;
 
--- linux-2.6.16.vanilla/net/xfrm/xfrm_state.c	2006-06-12 17:49:42.000000000 -0500
+++ linux-2.6.16/net/xfrm/xfrm_state.c	2006-06-13 08:40:48.000000000 -0500
@@ -368,7 +368,7 @@ xfrm_state_find(xfrm_address_t *daddr, x
 			 */
 			if (x->km.state == XFRM_STATE_VALID) {
 				if (!xfrm_selector_match(&x->sel, fl, family) ||
-				    !xfrm_sec_ctx_match(pol->security, x->security))
+				    !security_xfrm_state_pol_flow_match(x, pol, fl))
 					continue;
 				if (!best ||
 				    best->km.dying > x->km.dying ||
@@ -380,7 +380,7 @@ xfrm_state_find(xfrm_address_t *daddr, x
 			} else if (x->km.state == XFRM_STATE_ERROR ||
 				   x->km.state == XFRM_STATE_EXPIRED) {
  				if (xfrm_selector_match(&x->sel, fl, family) &&
-				    xfrm_sec_ctx_match(pol->security, x->security))
+				    security_xfrm_state_pol_flow_match(x, pol, fl))
 					error = -ESRCH;
 			}
 		}
@@ -404,6 +404,14 @@ xfrm_state_find(xfrm_address_t *daddr, x
 		 * to current session. */
 		xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family);
 
+		error = security_xfrm_state_alloc(x, NULL, pol->security, fl->sid);
+		if (error) {
+			x->km.state = XFRM_STATE_DEAD;
+			xfrm_state_put(x);
+			x = NULL;
+			goto out;
+		}
+
 		if (km_query(x, tmpl, pol) == 0) {
 			x->km.state = XFRM_STATE_ACQ;
 			list_add_tail(&x->bydst, xfrm_state_bydst+h);
--- linux-2.6.16.vanilla/net/xfrm/xfrm_user.c	2006-06-12 17:49:42.000000000 -0500
+++ linux-2.6.16/net/xfrm/xfrm_user.c	2006-06-13 08:40:48.000000000 -0500
@@ -255,7 +255,7 @@ static int attach_sec_ctx(struct xfrm_st
 		return 0;
 
 	uctx = RTA_DATA(u_arg);
-	return security_xfrm_state_alloc(x, uctx);
+	return security_xfrm_state_alloc(x, uctx, NULL, 0);
 }
 
 static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p)




More information about the redhat-lspp mailing list