[redhat-lspp] [RFC] [SELXFRM 3/4] Add support to xfrm subsystem
Venkat Yekkirala
vyekkirala at TrustedCS.com
Sat Jun 10 21:38:08 UTC 2006
This patch adds/enhances controls for SELinux/MLS handling of xfrms both on
the inbound and on the outbound. It also includes the security context to be
used by IKE, in the acquire messages sent to the IKE daemons.
Signed-off-by: Venkat Yekkirala <vyekkirala at TrustedCS.com>
---
key/af_key.c | 24 +++++++++++++++++++++++-
xfrm/xfrm_policy.c | 28 +++++++++++++++-------------
xfrm/xfrm_state.c | 12 ++++++++++--
xfrm/xfrm_user.c | 2 +-
4 files changed, 49 insertions(+), 17 deletions(-)
diff -purN -X linux-2.6.16.i686.lspp34/Documentation/dontdiff
linux-2.6.16.i686.lspp34/net/key/af_key.c
linux-2.6.16.i686.ipsec/net/key/af_key.c
--- linux-2.6.16.i686.lspp34/net/key/af_key.c 2006-06-09
09:01:32.000000000 -0500
+++ linux-2.6.16.i686.ipsec/net/key/af_key.c 2006-06-08
18:16:52.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)
@@ -2704,6 +2704,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)
@@ -2719,6 +2722,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;
@@ -2814,6 +2822,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);
}
diff -purN -X linux-2.6.16.i686.lspp34/Documentation/dontdiff
linux-2.6.16.i686.lspp34/net/xfrm/xfrm_policy.c
linux-2.6.16.i686.ipsec/net/xfrm/xfrm_policy.c
--- linux-2.6.16.i686.lspp34/net/xfrm/xfrm_policy.c 2006-06-09
09:01:33.000000000 -0500
+++ linux-2.6.16.i686.ipsec/net/xfrm/xfrm_policy.c 2006-06-08
18:16:52.000000000 -0500
@@ -520,7 +520,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;
@@ -536,7 +536,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;
}
@@ -564,7 +564,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;
@@ -575,7 +575,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);
@@ -785,19 +785,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);
}
@@ -955,13 +956,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);
@@ -981,14 +984,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;
@@ -1002,10 +1002,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)
@@ -1200,6 +1200,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;
diff -purN -X linux-2.6.16.i686.lspp34/Documentation/dontdiff
linux-2.6.16.i686.lspp34/net/xfrm/xfrm_state.c
linux-2.6.16.i686.ipsec/net/xfrm/xfrm_state.c
--- linux-2.6.16.i686.lspp34/net/xfrm/xfrm_state.c 2006-06-09
09:01:33.000000000 -0500
+++ linux-2.6.16.i686.ipsec/net/xfrm/xfrm_state.c 2006-06-08
18:16:52.000000000 -0500
@@ -366,7 +366,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 ||
@@ -378,7 +378,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;
}
}
@@ -402,6 +402,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);
diff -purN -X linux-2.6.16.i686.lspp34/Documentation/dontdiff
linux-2.6.16.i686.lspp34/net/xfrm/xfrm_user.c
linux-2.6.16.i686.ipsec/net/xfrm/xfrm_user.c
--- linux-2.6.16.i686.lspp34/net/xfrm/xfrm_user.c 2006-06-09
09:01:33.000000000 -0500
+++ linux-2.6.16.i686.ipsec/net/xfrm/xfrm_user.c 2006-06-08
18:16:52.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