Signed-off-by: Masahide NAKAMURA <[EMAIL PROTECTED]> --- net/ipv4/xfrm4_input.c | 48 +++++++++++++++++++++++++++--------- net/ipv4/xfrm4_output.c | 4 ++- net/ipv6/xfrm6_input.c | 56 ++++++++++++++++++++++++++++++++---------- net/ipv6/xfrm6_output.c | 4 ++- net/xfrm/xfrm_output.c | 19 +++++++++++--- net/xfrm/xfrm_policy.c | 61 +++++++++++++++++++++++++++++++++++++--------- 6 files changed, 148 insertions(+), 44 deletions(-)
diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c index 5e95c8a..956e093 100644 --- a/net/ipv4/xfrm4_input.c +++ b/net/ipv4/xfrm4_input.c @@ -45,36 +45,52 @@ int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi, unsigned int nhoff = offsetof(struct iphdr, protocol); seq = 0; - if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) + if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) { + XFRM_INC_STATS(XFRM_MIB_INHDRERROR); goto drop; + } do { const struct iphdr *iph = ip_hdr(skb); - if (xfrm_nr == XFRM_MAX_DEPTH) + if (xfrm_nr == XFRM_MAX_DEPTH) { + XFRM_INC_STATS(XFRM_MIB_INBUFFERERROR); goto drop; + } x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi, nexthdr, AF_INET); - if (x == NULL) + if (x == NULL) { + XFRM_INC_STATS(XFRM_MIB_INNOSTATES); goto drop; + } spin_lock(&x->lock); - if (unlikely(x->km.state != XFRM_STATE_VALID)) + if (unlikely(x->km.state != XFRM_STATE_VALID)) { + XFRM_INC_STATS(XFRM_MIB_INSTATEINVALID); goto drop_unlock; + } - if ((x->encap ? x->encap->encap_type : 0) != encap_type) + if ((x->encap ? x->encap->encap_type : 0) != encap_type) { + XFRM_INC_STATS(XFRM_MIB_INSTATEMISMATCH); goto drop_unlock; + } - if (x->props.replay_window && xfrm_replay_check(x, seq)) + if (x->props.replay_window && xfrm_replay_check(x, seq)) { + XFRM_INC_STATS(XFRM_MIB_INSEQOUTOFWINDOW); goto drop_unlock; + } - if (xfrm_state_check_expire(x)) + if (xfrm_state_check_expire(x)) { + XFRM_INC_STATS(XFRM_MIB_INSTATEEXPIRED); goto drop_unlock; + } nexthdr = x->type->input(x, skb); - if (nexthdr <= 0) + if (nexthdr <= 0) { + XFRM_INC_STATS(XFRM_MIB_INSTATEPROTOERROR); goto drop_unlock; + } skb_network_header(skb)[nhoff] = nexthdr; @@ -91,8 +107,10 @@ int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi, xfrm_vec[xfrm_nr++] = x; - if (x->outer_mode->input(x, skb)) + if (x->outer_mode->input(x, skb)) { + XFRM_INC_STATS(XFRM_MIB_INSTATEMODEERROR); goto drop; + } if (x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL) { decaps = 1; @@ -100,8 +118,10 @@ int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi, } err = xfrm_parse_spi(skb, nexthdr, &spi, &seq); - if (err < 0) + if (err < 0) { + XFRM_INC_STATS(XFRM_MIB_INHDRERROR); goto drop; + } } while (!err); /* Allocate new secpath or COW existing one. */ @@ -109,14 +129,18 @@ int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi, if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) { struct sec_path *sp; sp = secpath_dup(skb->sp); - if (!sp) + if (!sp) { + XFRM_INC_STATS(XFRM_MIB_INERROR); goto drop; + } if (skb->sp) secpath_put(skb->sp); skb->sp = sp; } - if (xfrm_nr + skb->sp->len > XFRM_MAX_DEPTH) + if (xfrm_nr + skb->sp->len > XFRM_MAX_DEPTH) { + XFRM_INC_STATS(XFRM_MIB_INBUFFERERROR); goto drop; + } memcpy(skb->sp->xvec + skb->sp->len, xfrm_vec, xfrm_nr * sizeof(xfrm_vec[0])); diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c index c4a7156..9d1d7b9 100644 --- a/net/ipv4/xfrm4_output.c +++ b/net/ipv4/xfrm4_output.c @@ -49,8 +49,10 @@ static inline int xfrm4_output_one(struct sk_buff *skb) if (x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL) { err = xfrm4_tunnel_check_size(skb); - if (err) + if (err) { + XFRM_INC_STATS(XFRM_MIB_OUTLENGTHERROR); goto error_nolock; + } } err = xfrm_output(skb); diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c index 5157837..4cf2206 100644 --- a/net/ipv6/xfrm6_input.c +++ b/net/ipv6/xfrm6_input.c @@ -29,32 +29,46 @@ int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi) nhoff = IP6CB(skb)->nhoff; seq = 0; - if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) + if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) { + XFRM_INC_STATS(XFRM_MIB_INHDRERROR); goto drop; + } do { struct ipv6hdr *iph = ipv6_hdr(skb); - if (xfrm_nr == XFRM_MAX_DEPTH) + if (xfrm_nr == XFRM_MAX_DEPTH) { + XFRM_INC_STATS(XFRM_MIB_INBUFFERERROR); goto drop; + } x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi, nexthdr, AF_INET6); - if (x == NULL) + if (x == NULL) { + XFRM_INC_STATS(XFRM_MIB_INNOSTATES); goto drop; + } spin_lock(&x->lock); - if (unlikely(x->km.state != XFRM_STATE_VALID)) + if (unlikely(x->km.state != XFRM_STATE_VALID)) { + XFRM_INC_STATS(XFRM_MIB_INSTATEINVALID); goto drop_unlock; + } - if (x->props.replay_window && xfrm_replay_check(x, seq)) + if (x->props.replay_window && xfrm_replay_check(x, seq)) { + XFRM_INC_STATS(XFRM_MIB_INSEQOUTOFWINDOW); goto drop_unlock; + } - if (xfrm_state_check_expire(x)) + if (xfrm_state_check_expire(x)) { + XFRM_INC_STATS(XFRM_MIB_INSTATEEXPIRED); goto drop_unlock; + } nexthdr = x->type->input(x, skb); - if (nexthdr <= 0) + if (nexthdr <= 0) { + XFRM_INC_STATS(XFRM_MIB_INSTATEPROTOERROR); goto drop_unlock; + } skb_network_header(skb)[nhoff] = nexthdr; @@ -68,31 +82,39 @@ int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi) xfrm_vec[xfrm_nr++] = x; - if (x->outer_mode->input(x, skb)) + if (x->outer_mode->input(x, skb)) { + XFRM_INC_STATS(XFRM_MIB_INSTATEMODEERROR); goto drop; + } if (x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL) { decaps = 1; break; } - if ((err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) < 0) + if ((err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) < 0) { + XFRM_INC_STATS(XFRM_MIB_INHDRERROR); goto drop; + } } while (!err); /* Allocate new secpath or COW existing one. */ if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) { struct sec_path *sp; sp = secpath_dup(skb->sp); - if (!sp) + if (!sp) { + XFRM_INC_STATS(XFRM_MIB_INERROR); goto drop; + } if (skb->sp) secpath_put(skb->sp); skb->sp = sp; } - if (xfrm_nr + skb->sp->len > XFRM_MAX_DEPTH) + if (xfrm_nr + skb->sp->len > XFRM_MAX_DEPTH) { + XFRM_INC_STATS(XFRM_MIB_INBUFFERERROR); goto drop; + } memcpy(skb->sp->xvec + skb->sp->len, xfrm_vec, xfrm_nr * sizeof(xfrm_vec[0])); @@ -217,22 +239,28 @@ int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, break; } - if (!xfrm_vec_one) + if (!xfrm_vec_one) { + XFRM_INC_STATS(XFRM_MIB_INNOSTATES); goto drop; + } /* Allocate new secpath or COW existing one. */ if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) { struct sec_path *sp; sp = secpath_dup(skb->sp); - if (!sp) + if (!sp) { + XFRM_INC_STATS(XFRM_MIB_INERROR); goto drop; + } if (skb->sp) secpath_put(skb->sp); skb->sp = sp; } - if (1 + skb->sp->len > XFRM_MAX_DEPTH) + if (1 + skb->sp->len > XFRM_MAX_DEPTH) { + XFRM_INC_STATS(XFRM_MIB_INBUFFERERROR); goto drop; + } skb->sp->xvec[skb->sp->len] = xfrm_vec_one; skb->sp->len ++; diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c index 6569767..6dfc74d 100644 --- a/net/ipv6/xfrm6_output.c +++ b/net/ipv6/xfrm6_output.c @@ -52,8 +52,10 @@ static inline int xfrm6_output_one(struct sk_buff *skb) if (x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL) { err = xfrm6_tunnel_check_size(skb); - if (err) + if (err) { + XFRM_INC_STATS(XFRM_MIB_OUTLENGTHERROR); goto error_nolock; + } } err = xfrm_output(skb); diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c index f4bfd6c..39e40ac 100644 --- a/net/xfrm/xfrm_output.c +++ b/net/xfrm/xfrm_output.c @@ -32,9 +32,13 @@ static int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *skb) static int xfrm_state_check(struct xfrm_state *x, struct sk_buff *skb) { int err = xfrm_state_check_expire(x); - if (err < 0) + if (err < 0) { + XFRM_INC_STATS(XFRM_MIB_OUTSTATEEXPIRED); goto err; + } err = xfrm_state_check_space(x, skb); + if (err) + XFRM_INC_STATS(XFRM_MIB_OUTLENGTHERROR); err: return err; } @@ -47,8 +51,10 @@ int xfrm_output(struct sk_buff *skb) if (skb->ip_summed == CHECKSUM_PARTIAL) { err = skb_checksum_help(skb); - if (err) + if (err) { + XFRM_INC_STATS(XFRM_MIB_OUTERROR); goto error_nolock; + } } do { @@ -64,8 +70,10 @@ int xfrm_output(struct sk_buff *skb) } err = x->outer_mode->output(x, skb); - if (err) + if (err) { + XFRM_INC_STATS(XFRM_MIB_OUTSTATEMODEERROR); goto error; + } x->curlft.bytes += skb->len; x->curlft.packets++; @@ -73,10 +81,13 @@ int xfrm_output(struct sk_buff *skb) spin_unlock_bh(&x->lock); err = x->type->output(x, skb); - if (err) + if (err) { + XFRM_INC_STATS(XFRM_MIB_OUTSTATEPROTOERROR); goto error_nolock; + } if (!(skb->dst = dst_pop(dst))) { + XFRM_INC_STATS(XFRM_MIB_OUTERROR); err = -EHOSTUNREACH; goto error_nolock; } diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index e770998..2f6a1ec 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -1326,8 +1326,10 @@ restart: if (sk && sk->sk_policy[XFRM_POLICY_OUT]) { policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl); - if (IS_ERR(policy)) + if (IS_ERR(policy)) { + XFRM_INC_STATS(XFRM_MIB_OUTPOLERROR); return PTR_ERR(policy); + } } if (!policy) { @@ -1338,8 +1340,10 @@ restart: policy = flow_cache_lookup(fl, dst_orig->ops->family, dir, xfrm_policy_lookup); - if (IS_ERR(policy)) + if (IS_ERR(policy)) { + XFRM_INC_STATS(XFRM_MIB_OUTPOLERROR); return PTR_ERR(policy); + } } if (!policy) @@ -1354,6 +1358,7 @@ restart: switch (policy->action) { case XFRM_POLICY_BLOCK: /* Prohibit the flow */ + XFRM_INC_STATS(XFRM_MIB_OUTPOLBLOCK); err = -EPERM; goto error; @@ -1373,6 +1378,7 @@ restart: */ dst = xfrm_find_bundle(fl, policy, family); if (IS_ERR(dst)) { + XFRM_INC_STATS(XFRM_MIB_OUTBUNDLEERROR); err = PTR_ERR(dst); goto error; } @@ -1387,10 +1393,12 @@ restart: XFRM_POLICY_OUT); if (pols[1]) { if (IS_ERR(pols[1])) { + XFRM_INC_STATS(XFRM_MIB_OUTPOLERROR); err = PTR_ERR(pols[1]); goto error; } if (pols[1]->action == XFRM_POLICY_BLOCK) { + XFRM_INC_STATS(XFRM_MIB_OUTPOLBLOCK); err = -EPERM; goto error; } @@ -1436,6 +1444,7 @@ restart: nx = xfrm_tmpl_resolve(pols, npols, fl, xfrm, family); if (nx == -EAGAIN && signal_pending(current)) { + XFRM_INC_STATS(XFRM_MIB_OUTNOSTATES); err = -ERESTART; goto error; } @@ -1446,8 +1455,10 @@ restart: } err = nx; } - if (err < 0) + if (err < 0) { + XFRM_INC_STATS(XFRM_MIB_OUTNOSTATES); goto error; + } } if (nx == 0) { /* Flow passes not transformed. */ @@ -1462,6 +1473,7 @@ restart: int i; for (i=0; i<nx; i++) xfrm_state_put(xfrm[i]); + XFRM_INC_STATS(XFRM_MIB_OUTBUNDLEERROR); goto error; } @@ -1482,6 +1494,7 @@ restart: if (dst) dst_free(dst); + XFRM_INC_STATS(XFRM_MIB_OUTBUNDLEERROR); err = -EHOSTUNREACH; goto error; } @@ -1494,6 +1507,7 @@ restart: write_unlock_bh(&policy->lock); if (dst) dst_free(dst); + XFRM_INC_STATS(XFRM_MIB_OUTBUNDLEERROR); goto error; } @@ -1635,8 +1649,11 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, u8 fl_dir = policy_to_flow_dir(dir); int xerr_idx = -1; - if (xfrm_decode_session(skb, &fl, family) < 0) + if (xfrm_decode_session(skb, &fl, family) < 0) { + XFRM_INC_STATS(XFRM_MIB_INHDRERROR); return 0; + } + nf_nat_decode_session(skb, &fl, family); /* First, check used SA against their selectors. */ @@ -1645,28 +1662,35 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, for (i=skb->sp->len-1; i>=0; i--) { struct xfrm_state *x = skb->sp->xvec[i]; - if (!xfrm_selector_match(&x->sel, &fl, family)) + if (!xfrm_selector_match(&x->sel, &fl, family)) { + XFRM_INC_STATS(XFRM_MIB_INSTATEMISMATCH); return 0; + } } } pol = NULL; if (sk && sk->sk_policy[dir]) { pol = xfrm_sk_policy_lookup(sk, dir, &fl); - if (IS_ERR(pol)) + if (IS_ERR(pol)) { + XFRM_INC_STATS(XFRM_MIB_INPOLERROR); return 0; + } } if (!pol) pol = flow_cache_lookup(&fl, family, fl_dir, xfrm_policy_lookup); - if (IS_ERR(pol)) + if (IS_ERR(pol)) { + XFRM_INC_STATS(XFRM_MIB_INPOLERROR); return 0; + } if (!pol) { if (skb->sp && secpath_has_nontransport(skb->sp, 0, &xerr_idx)) { xfrm_secpath_reject(xerr_idx, skb, &fl); + XFRM_INC_STATS(XFRM_MIB_INNOPOLS); return 0; } return 1; @@ -1682,8 +1706,10 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, &fl, family, XFRM_POLICY_IN); if (pols[1]) { - if (IS_ERR(pols[1])) + if (IS_ERR(pols[1])) { + XFRM_INC_STATS(XFRM_MIB_INPOLERROR); return 0; + } pols[1]->curlft.use_time = get_seconds(); npols ++; } @@ -1704,10 +1730,14 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, for (pi = 0; pi < npols; pi++) { if (pols[pi] != pol && - pols[pi]->action != XFRM_POLICY_ALLOW) + pols[pi]->action != XFRM_POLICY_ALLOW) { + XFRM_INC_STATS(XFRM_MIB_INPOLBLOCK); goto reject; - if (ti + pols[pi]->xfrm_nr >= XFRM_MAX_DEPTH) + } + if (ti + pols[pi]->xfrm_nr >= XFRM_MAX_DEPTH) { + XFRM_INC_STATS(XFRM_MIB_INBUFFERERROR); goto reject_error; + } for (i = 0; i < pols[pi]->xfrm_nr; i++) tpp[ti++] = &pols[pi]->xfrm_vec[i]; } @@ -1729,16 +1759,20 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, if (k < -1) /* "-2 - errored_index" returned */ xerr_idx = -(2+k); + XFRM_INC_STATS(XFRM_MIB_INTMPLMISMATCH); goto reject; } } - if (secpath_has_nontransport(sp, k, &xerr_idx)) + if (secpath_has_nontransport(sp, k, &xerr_idx)) { + XFRM_INC_STATS(XFRM_MIB_INTMPLMISMATCH); goto reject; + } xfrm_pols_put(pols, npols); return 1; } + XFRM_INC_STATS(XFRM_MIB_INPOLBLOCK); reject: xfrm_secpath_reject(xerr_idx, skb, &fl); @@ -1752,8 +1786,11 @@ int __xfrm_route_forward(struct sk_buff *skb, unsigned short family) { struct flowi fl; - if (xfrm_decode_session(skb, &fl, family) < 0) + if (xfrm_decode_session(skb, &fl, family) < 0) { + /* XXX: we should have something like FWDHDRERROR here. */ + XFRM_INC_STATS(XFRM_MIB_INHDRERROR); return 0; + } return xfrm_lookup(&skb->dst, &fl, NULL, 0) == 0; } -- 1.4.4.2 - To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html