From 227620e295090629fcb2c46ad3828222ab65438d Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 13 Nov 2007 21:41:28 -0800 Subject: [IPSEC]: Separate inner/outer mode processing on input With inter-family transforms the inner mode differs from the outer mode. Attempting to handle both sides from the same function means that it needs to handle both IPv4 and IPv6 which creates duplication and confusion. This patch separates the two parts on the input path so that each function deals with one family only. In particular, the functions xfrm4_extract_inut/xfrm6_extract_inut moves the pertinent fields from the IPv4/IPv6 IP headers into a neutral format stored in skb->cb. This is then used by the inner mode input functions to modify the inner IP header. In this way the input function no longer has to know about the outer address family. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/xfrm/xfrm_input.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'net/xfrm/xfrm_input.c') diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index cb97fda1b6df..4c803f7e74e5 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c @@ -81,6 +81,19 @@ int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq) } EXPORT_SYMBOL(xfrm_parse_spi); +int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb) +{ + int err; + + err = x->outer_mode->afinfo->extract_input(x, skb); + if (err) + return err; + + skb->protocol = x->inner_mode->afinfo->eth_proto; + return x->inner_mode->input2(x, skb); +} +EXPORT_SYMBOL(xfrm_prepare_input); + void __init xfrm_input_init(void) { secpath_cachep = kmem_cache_create("secpath_cache", -- cgit v1.2.3 From 716062fd4c2f88a33ab409f62a1e7397ad0a7e33 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 13 Nov 2007 21:44:23 -0800 Subject: [IPSEC]: Merge most of the input path As part of the work on asynchronous cryptographic operations, we need to be able to resume from the spot where they occur. As such, it helps if we isolate them to one spot. This patch moves most of the remaining family-specific processing into the common input code. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/xfrm/xfrm_input.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) (limited to 'net/xfrm/xfrm_input.c') diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index 4c803f7e74e5..b980095be935 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c @@ -9,6 +9,8 @@ #include #include +#include +#include #include #include @@ -94,6 +96,117 @@ int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb) } EXPORT_SYMBOL(xfrm_prepare_input); +int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) +{ + int err; + __be32 seq; + struct xfrm_state *xfrm_vec[XFRM_MAX_DEPTH]; + struct xfrm_state *x; + int xfrm_nr = 0; + int decaps = 0; + unsigned int nhoff = XFRM_SPI_SKB_CB(skb)->nhoff; + unsigned int daddroff = XFRM_SPI_SKB_CB(skb)->daddroff; + + seq = 0; + if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) + goto drop; + + do { + if (xfrm_nr == XFRM_MAX_DEPTH) + goto drop; + + x = xfrm_state_lookup((xfrm_address_t *) + (skb_network_header(skb) + daddroff), + spi, nexthdr, AF_INET); + if (x == NULL) + goto drop; + + spin_lock(&x->lock); + if (unlikely(x->km.state != XFRM_STATE_VALID)) + goto drop_unlock; + + if ((x->encap ? x->encap->encap_type : 0) != encap_type) + goto drop_unlock; + + if (x->props.replay_window && xfrm_replay_check(x, seq)) + goto drop_unlock; + + if (xfrm_state_check_expire(x)) + goto drop_unlock; + + nexthdr = x->type->input(x, skb); + if (nexthdr <= 0) + goto drop_unlock; + + skb_network_header(skb)[nhoff] = nexthdr; + + /* only the first xfrm gets the encap type */ + encap_type = 0; + + if (x->props.replay_window) + xfrm_replay_advance(x, seq); + + x->curlft.bytes += skb->len; + x->curlft.packets++; + + spin_unlock(&x->lock); + + xfrm_vec[xfrm_nr++] = x; + + if (x->inner_mode->input(x, skb)) + goto drop; + + if (x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL) { + decaps = 1; + break; + } + + err = xfrm_parse_spi(skb, nexthdr, &spi, &seq); + if (err < 0) + 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) + goto drop; + if (skb->sp) + secpath_put(skb->sp); + skb->sp = sp; + } + if (xfrm_nr + skb->sp->len > XFRM_MAX_DEPTH) + goto drop; + + memcpy(skb->sp->xvec + skb->sp->len, xfrm_vec, + xfrm_nr * sizeof(xfrm_vec[0])); + skb->sp->len += xfrm_nr; + + nf_reset(skb); + + if (decaps) { + dst_release(skb->dst); + skb->dst = NULL; + netif_rx(skb); + return 0; + } else { + return x->inner_mode->afinfo->transport_finish(skb, 0); + } + +drop_unlock: + spin_unlock(&x->lock); + xfrm_state_put(x); +drop: + while (--xfrm_nr >= 0) + xfrm_state_put(xfrm_vec[xfrm_nr]); + + kfree_skb(skb); + return 0; +} +EXPORT_SYMBOL(xfrm_input); + void __init xfrm_input_init(void) { secpath_cachep = kmem_cache_create("secpath_cache", -- cgit v1.2.3 From b2aa5e9d43a38dcdfa0878ed750cf32f98460278 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 13 Nov 2007 21:44:55 -0800 Subject: [IPSEC]: Store xfrm states in security path directly As it is xfrm_input first collects a list of xfrm states on the stack before storing them in the packet's security path just before it returns. For async crypto, this construction presents an obstacle since we may need to leave the loop after each transform. In fact, it's much easier to just skip the stack completely and always store to the security path. This is proven by the fact that this patch actually shrinks the code. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/xfrm/xfrm_input.c | 42 +++++++++++++++--------------------------- 1 file changed, 15 insertions(+), 27 deletions(-) (limited to 'net/xfrm/xfrm_input.c') diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index b980095be935..587f3474ed3d 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c @@ -100,19 +100,29 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) { int err; __be32 seq; - struct xfrm_state *xfrm_vec[XFRM_MAX_DEPTH]; struct xfrm_state *x; - int xfrm_nr = 0; int decaps = 0; unsigned int nhoff = XFRM_SPI_SKB_CB(skb)->nhoff; unsigned int daddroff = XFRM_SPI_SKB_CB(skb)->daddroff; + /* 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) + goto drop; + if (skb->sp) + secpath_put(skb->sp); + skb->sp = sp; + } + seq = 0; if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) goto drop; do { - if (xfrm_nr == XFRM_MAX_DEPTH) + if (skb->sp->len == XFRM_MAX_DEPTH) goto drop; x = xfrm_state_lookup((xfrm_address_t *) @@ -121,6 +131,8 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) if (x == NULL) goto drop; + skb->sp->xvec[skb->sp->len++] = x; + spin_lock(&x->lock); if (unlikely(x->km.state != XFRM_STATE_VALID)) goto drop_unlock; @@ -151,8 +163,6 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) spin_unlock(&x->lock); - xfrm_vec[xfrm_nr++] = x; - if (x->inner_mode->input(x, skb)) goto drop; @@ -166,24 +176,6 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) 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) - goto drop; - if (skb->sp) - secpath_put(skb->sp); - skb->sp = sp; - } - if (xfrm_nr + skb->sp->len > XFRM_MAX_DEPTH) - goto drop; - - memcpy(skb->sp->xvec + skb->sp->len, xfrm_vec, - xfrm_nr * sizeof(xfrm_vec[0])); - skb->sp->len += xfrm_nr; - nf_reset(skb); if (decaps) { @@ -197,11 +189,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) drop_unlock: spin_unlock(&x->lock); - xfrm_state_put(x); drop: - while (--xfrm_nr >= 0) - xfrm_state_put(xfrm_vec[xfrm_nr]); - kfree_skb(skb); return 0; } -- cgit v1.2.3 From 668dc8af3150f837f7f0461001bbbc0ce25d7bdf Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 16 Dec 2007 15:55:02 -0800 Subject: [IPSEC]: Move integrity stat collection into xfrm_input Similar to the moving out of the replay processing on the output, this patch moves the integrity stat collectin from x->type->input into xfrm_input. This would eventually allow transforms such as AH/ESP to be lockless. The error value EBADMSG (currently unused in the crypto layer) is used to indicate a failed integrity check. In future this error can be directly returned by the crypto layer once we switch to aead algorithms. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/xfrm/xfrm_input.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'net/xfrm/xfrm_input.c') diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index 587f3474ed3d..b7d68eb9434c 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c @@ -147,8 +147,11 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) goto drop_unlock; nexthdr = x->type->input(x, skb); - if (nexthdr <= 0) + if (nexthdr <= 0) { + if (nexthdr == -EBADMSG) + x->stats.integrity_failed++; goto drop_unlock; + } skb_network_header(skb)[nhoff] = nexthdr; -- cgit v1.2.3 From 0ebea8ef3559b545c37b016f44e84c3b33e47c39 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 13 Nov 2007 21:45:58 -0800 Subject: [IPSEC]: Move state lock into x->type->input This patch releases the lock on the state before calling x->type->input. It also adds the lock to the spots where they're currently needed. Most of those places (all except mip6) are expected to disappear with async crypto. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/xfrm/xfrm_input.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'net/xfrm/xfrm_input.c') diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index b7d68eb9434c..5cad522e8ef6 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c @@ -146,7 +146,11 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) if (xfrm_state_check_expire(x)) goto drop_unlock; + spin_unlock(&x->lock); + nexthdr = x->type->input(x, skb); + + spin_lock(&x->lock); if (nexthdr <= 0) { if (nexthdr == -EBADMSG) x->stats.integrity_failed++; -- cgit v1.2.3 From 60d5fcfb19d8a958fc563e52240cd05ec23f36c9 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 19 Nov 2007 18:47:58 -0800 Subject: [IPSEC]: Remove nhoff from xfrm_input The nhoff field isn't actually necessary in xfrm_input. For tunnel mode transforms we now throw away the output IP header so it makes no sense to fill in the nexthdr field. For transport mode we can now let the function transport_finish do the setting and it knows where the nexthdr field is. The only other thing that needs the nexthdr field to be set is the header extraction code. However, we can simply move the protocol extraction out of the generic header extraction. We want to minimise the amount of info we have to carry around between transforms as this simplifies the resumption process for async crypto. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/xfrm/xfrm_input.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'net/xfrm/xfrm_input.c') diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index 5cad522e8ef6..cce9d4586045 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c @@ -102,7 +102,6 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) __be32 seq; struct xfrm_state *x; int decaps = 0; - unsigned int nhoff = XFRM_SPI_SKB_CB(skb)->nhoff; unsigned int daddroff = XFRM_SPI_SKB_CB(skb)->daddroff; /* Allocate new secpath or COW existing one. */ @@ -157,8 +156,6 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) goto drop_unlock; } - skb_network_header(skb)[nhoff] = nexthdr; - /* only the first xfrm gets the encap type */ encap_type = 0; @@ -170,6 +167,8 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) spin_unlock(&x->lock); + XFRM_MODE_SKB_CB(skb)->protocol = nexthdr; + if (x->inner_mode->input(x, skb)) goto drop; -- cgit v1.2.3 From 1bf06cd2e338fd6fc29169d30eaf0df982338285 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 19 Nov 2007 18:50:17 -0800 Subject: [IPSEC]: Add async resume support on input This patch adds support for async resumptions on input. To do so, the transform would return -EINPROGRESS and subsequently invoke the function xfrm_input_resume to resume processing. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/xfrm/xfrm_input.c | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) (limited to 'net/xfrm/xfrm_input.c') diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index cce9d4586045..96f42c1d2e8e 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c @@ -101,8 +101,17 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) int err; __be32 seq; struct xfrm_state *x; + xfrm_address_t *daddr; int decaps = 0; - unsigned int daddroff = XFRM_SPI_SKB_CB(skb)->daddroff; + int async = 0; + + /* A negative encap_type indicates async resumption. */ + if (encap_type < 0) { + async = 1; + x = skb->sp->xvec[skb->sp->len - 1]; + seq = XFRM_SKB_CB(skb)->seq; + goto resume; + } /* Allocate new secpath or COW existing one. */ if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) { @@ -116,6 +125,9 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) skb->sp = sp; } + daddr = (xfrm_address_t *)(skb_network_header(skb) + + XFRM_SPI_SKB_CB(skb)->daddroff); + seq = 0; if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) goto drop; @@ -124,9 +136,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) if (skb->sp->len == XFRM_MAX_DEPTH) goto drop; - x = xfrm_state_lookup((xfrm_address_t *) - (skb_network_header(skb) + daddroff), - spi, nexthdr, AF_INET); + x = xfrm_state_lookup(daddr, spi, nexthdr, AF_INET); if (x == NULL) goto drop; @@ -147,8 +157,14 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) spin_unlock(&x->lock); + XFRM_SKB_CB(skb)->seq = seq; + nexthdr = x->type->input(x, skb); + if (nexthdr == -EINPROGRESS) + return 0; + +resume: spin_lock(&x->lock); if (nexthdr <= 0) { if (nexthdr == -EBADMSG) @@ -177,6 +193,12 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) break; } + /* + * We need the inner address. However, we only get here for + * transport mode so the outer address is identical. + */ + daddr = &x->id.daddr; + err = xfrm_parse_spi(skb, nexthdr, &spi, &seq); if (err < 0) goto drop; @@ -190,7 +212,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) netif_rx(skb); return 0; } else { - return x->inner_mode->afinfo->transport_finish(skb, 0); + return x->inner_mode->afinfo->transport_finish(skb, async); } drop_unlock: @@ -201,6 +223,12 @@ drop: } EXPORT_SYMBOL(xfrm_input); +int xfrm_input_resume(struct sk_buff *skb, int nexthdr) +{ + return xfrm_input(skb, nexthdr, 0, -1); +} +EXPORT_SYMBOL(xfrm_input_resume); + void __init xfrm_input_init(void) { secpath_cachep = kmem_cache_create("secpath_cache", -- cgit v1.2.3 From 2fcb45b6b87914f072314e5b5d9c196f45984683 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 3 Dec 2007 22:54:12 -0800 Subject: [IPSEC]: Use the correct family for input state lookup When merging the input paths of IPsec I accidentally left a hard-coded AF_INET for the state lookup call. This broke IPv6 obviously. This patch fixes by getting the input callers to specify the family through skb->cb. Credit goes to Kazunori Miyazawa for diagnosing this and providing an initial patch. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/xfrm/xfrm_input.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'net/xfrm/xfrm_input.c') diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index 96f42c1d2e8e..8b2b1b59133e 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c @@ -102,6 +102,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) __be32 seq; struct xfrm_state *x; xfrm_address_t *daddr; + unsigned int family; int decaps = 0; int async = 0; @@ -127,6 +128,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) daddr = (xfrm_address_t *)(skb_network_header(skb) + XFRM_SPI_SKB_CB(skb)->daddroff); + family = XFRM_SPI_SKB_CB(skb)->family; seq = 0; if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) @@ -136,7 +138,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) if (skb->sp->len == XFRM_MAX_DEPTH) goto drop; - x = xfrm_state_lookup(daddr, spi, nexthdr, AF_INET); + x = xfrm_state_lookup(daddr, spi, nexthdr, family); if (x == NULL) goto drop; @@ -198,6 +200,7 @@ resume: * transport mode so the outer address is identical. */ daddr = &x->id.daddr; + family = x->outer_mode->afinfo->family; err = xfrm_parse_spi(skb, nexthdr, &spi, &seq); if (err < 0) -- cgit v1.2.3 From 005011211f559113686938c2c252b8ee1ab855b5 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 11 Dec 2007 01:53:43 -0800 Subject: [IPSEC]: Add xfrm_input_state helper This patch adds the xfrm_input_state helper function which returns the current xfrm state being processed on the input path given an sk_buff. This is currently only used by xfrm_input but will be used by ESP upon asynchronous resumption. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/xfrm/xfrm_input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/xfrm/xfrm_input.c') diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index 8b2b1b59133e..8624cbdb2a1e 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c @@ -109,7 +109,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) /* A negative encap_type indicates async resumption. */ if (encap_type < 0) { async = 1; - x = skb->sp->xvec[skb->sp->len - 1]; + x = xfrm_input_state(skb); seq = XFRM_SKB_CB(skb)->seq; goto resume; } -- cgit v1.2.3 From 0aa647746e5602e608220c10e51f49709a030f5d Mon Sep 17 00:00:00 2001 From: Masahide NAKAMURA Date: Thu, 20 Dec 2007 20:43:36 -0800 Subject: [XFRM]: Support to increment packet dropping statistics. Signed-off-by: Masahide NAKAMURA Signed-off-by: David S. Miller --- net/xfrm/xfrm_input.c | 41 +++++++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 10 deletions(-) (limited to 'net/xfrm/xfrm_input.c') diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index 8624cbdb2a1e..493243fc5fe5 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c @@ -119,8 +119,10 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) struct sec_path *sp; sp = secpath_dup(skb->sp); - if (!sp) + if (!sp) { + XFRM_INC_STATS(LINUX_MIB_XFRMINERROR); goto drop; + } if (skb->sp) secpath_put(skb->sp); skb->sp = sp; @@ -131,31 +133,45 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) family = XFRM_SPI_SKB_CB(skb)->family; 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(LINUX_MIB_XFRMINHDRERROR); goto drop; + } do { - if (skb->sp->len == XFRM_MAX_DEPTH) + if (skb->sp->len == XFRM_MAX_DEPTH) { + XFRM_INC_STATS(LINUX_MIB_XFRMINBUFFERERROR); goto drop; + } x = xfrm_state_lookup(daddr, spi, nexthdr, family); - if (x == NULL) + if (x == NULL) { + XFRM_INC_STATS(LINUX_MIB_XFRMINNOSTATES); goto drop; + } skb->sp->xvec[skb->sp->len++] = x; spin_lock(&x->lock); - if (unlikely(x->km.state != XFRM_STATE_VALID)) + if (unlikely(x->km.state != XFRM_STATE_VALID)) { + XFRM_INC_STATS(LINUX_MIB_XFRMINSTATEINVALID); 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(LINUX_MIB_XFRMINSTATEINVALID); 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(LINUX_MIB_XFRMINSEQOUTOFWINDOW); goto drop_unlock; + } - if (xfrm_state_check_expire(x)) + if (xfrm_state_check_expire(x)) { + XFRM_INC_STATS(LINUX_MIB_XFRMINSTATEEXPIRED); goto drop_unlock; + } spin_unlock(&x->lock); @@ -171,6 +187,7 @@ resume: if (nexthdr <= 0) { if (nexthdr == -EBADMSG) x->stats.integrity_failed++; + XFRM_INC_STATS(LINUX_MIB_XFRMINSTATEPROTOERROR); goto drop_unlock; } @@ -187,8 +204,10 @@ resume: XFRM_MODE_SKB_CB(skb)->protocol = nexthdr; - if (x->inner_mode->input(x, skb)) + if (x->inner_mode->input(x, skb)) { + XFRM_INC_STATS(LINUX_MIB_XFRMINSTATEMODEERROR); goto drop; + } if (x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL) { decaps = 1; @@ -203,8 +222,10 @@ resume: family = x->outer_mode->afinfo->family; err = xfrm_parse_spi(skb, nexthdr, &spi, &seq); - if (err < 0) + if (err < 0) { + XFRM_INC_STATS(LINUX_MIB_XFRMINHDRERROR); goto drop; + } } while (!err); nf_reset(skb); -- cgit v1.2.3 From afeb14b49098ba7a51c96e083a4105a0301f94c4 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Fri, 21 Dec 2007 14:58:11 -0800 Subject: [XFRM]: RFC4303 compliant auditing This patch adds a number of new IPsec audit events to meet the auditing requirements of RFC4303. This includes audit hooks for the following events: * Could not find a valid SA [sections 2.1, 3.4.2] . xfrm_audit_state_notfound() . xfrm_audit_state_notfound_simple() * Sequence number overflow [section 3.3.3] . xfrm_audit_state_replay_overflow() * Replayed packet [section 3.4.3] . xfrm_audit_state_replay() * Integrity check failure [sections 3.4.4.1, 3.4.4.2] . xfrm_audit_state_icvfail() While RFC4304 deals only with ESP most of the changes in this patch apply to IPsec in general, i.e. both AH and ESP. The one case, integrity check failure, where ESP specific code had to be modified the same was done to the AH code for the sake of consistency. Signed-off-by: Paul Moore Acked-by: James Morris Signed-off-by: David S. Miller --- net/xfrm/xfrm_input.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net/xfrm/xfrm_input.c') diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index 493243fc5fe5..1b250f33ad5b 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c @@ -147,6 +147,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) x = xfrm_state_lookup(daddr, spi, nexthdr, family); if (x == NULL) { XFRM_INC_STATS(LINUX_MIB_XFRMINNOSTATES); + xfrm_audit_state_notfound(skb, family, spi, seq); goto drop; } @@ -163,7 +164,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) goto drop_unlock; } - if (x->props.replay_window && xfrm_replay_check(x, seq)) { + if (x->props.replay_window && xfrm_replay_check(x, skb, seq)) { XFRM_INC_STATS(LINUX_MIB_XFRMINSEQOUTOFWINDOW); goto drop_unlock; } -- cgit v1.2.3 From 9dd3245a2ac1834797191072705015e6a12f55bf Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 30 Dec 2007 21:10:30 -0800 Subject: [IPSEC]: Move all calls to xfrm_audit_state_icvfail to xfrm_input Let's nip the code duplication in the bud :) Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/xfrm/xfrm_input.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'net/xfrm/xfrm_input.c') diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index 1b250f33ad5b..039e7019c48a 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c @@ -186,8 +186,11 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) resume: spin_lock(&x->lock); if (nexthdr <= 0) { - if (nexthdr == -EBADMSG) + if (nexthdr == -EBADMSG) { + xfrm_audit_state_icvfail(x, skb, + x->type->proto); x->stats.integrity_failed++; + } XFRM_INC_STATS(LINUX_MIB_XFRMINSTATEPROTOERROR); goto drop_unlock; } -- cgit v1.2.3