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/ipv4/ah4.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'net/ipv4/ah4.c') diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index 5fc346d8b56..a989d29b44e 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c @@ -177,9 +177,8 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb) err = ah_mac_digest(ahp, skb, ah->auth_data); if (err) goto out; - err = -EINVAL; if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len)) { - x->stats.integrity_failed++; + err = -EBADMSG; goto out; } } -- cgit v1.2.3-70-g09d2 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/ipv4/ah4.c | 14 ++++++++++---- net/ipv4/esp4.c | 24 +++++++++++++++--------- net/ipv6/ah6.c | 9 +++++++-- net/ipv6/esp6.c | 37 +++++++++++++++++++++++-------------- net/ipv6/mip6.c | 14 ++++++++++---- net/xfrm/xfrm_input.c | 4 ++++ 6 files changed, 69 insertions(+), 33 deletions(-) (limited to 'net/ipv4/ah4.c') diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index a989d29b44e..d76803a3dca 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c @@ -169,6 +169,8 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb) if (ip_clear_mutable_options(iph, &dummy)) goto out; } + + spin_lock(&x->lock); { u8 auth_data[MAX_AH_AUTH_LEN]; @@ -176,12 +178,16 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb) skb_push(skb, ihl); err = ah_mac_digest(ahp, skb, ah->auth_data); if (err) - goto out; - if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len)) { + goto unlock; + if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len)) err = -EBADMSG; - goto out; - } } +unlock: + spin_unlock(&x->lock); + + if (err) + goto out; + skb->network_header += ah_hlen; memcpy(skb_network_header(skb), work_buf, ihl); skb->transport_header = skb->network_header; diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index 3350a7d5066..28ea5c77ca2 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -171,29 +171,31 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb) if (elen <= 0 || (elen & (blksize-1))) goto out; + if ((err = skb_cow_data(skb, 0, &trailer)) < 0) + goto out; + nfrags = err; + + skb->ip_summed = CHECKSUM_NONE; + + spin_lock(&x->lock); + /* If integrity check is required, do this. */ if (esp->auth.icv_full_len) { u8 sum[alen]; err = esp_mac_digest(esp, skb, 0, skb->len - alen); if (err) - goto out; + goto unlock; if (skb_copy_bits(skb, skb->len - alen, sum, alen)) BUG(); if (unlikely(memcmp(esp->auth.work_icv, sum, alen))) { err = -EBADMSG; - goto out; + goto unlock; } } - if ((err = skb_cow_data(skb, 0, &trailer)) < 0) - goto out; - nfrags = err; - - skb->ip_summed = CHECKSUM_NONE; - esph = (struct ip_esp_hdr *)skb->data; /* Get ivec. This can be wrong, check against another impls. */ @@ -206,7 +208,7 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb) err = -ENOMEM; sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC); if (!sg) - goto out; + goto unlock; } sg_init_table(sg, nfrags); skb_to_sgvec(skb, sg, @@ -215,6 +217,10 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb) err = crypto_blkcipher_decrypt(&desc, sg, sg, elen); if (unlikely(sg != &esp->sgbuf[0])) kfree(sg); + +unlock: + spin_unlock(&x->lock); + if (unlikely(err)) goto out; diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index d4b59ecb0b5..1b51d1eedbd 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c @@ -370,6 +370,7 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb) ip6h->flow_lbl[2] = 0; ip6h->hop_limit = 0; + spin_lock(&x->lock); { u8 auth_data[MAX_AH_AUTH_LEN]; @@ -378,13 +379,17 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb) skb_push(skb, hdr_len); err = ah_mac_digest(ahp, skb, ah->auth_data); if (err) - goto free_out; + goto unlock; if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len)) { LIMIT_NETDEBUG(KERN_WARNING "ipsec ah authentication error\n"); err = -EBADMSG; - goto free_out; } } +unlock: + spin_unlock(&x->lock); + + if (err) + goto free_out; skb->network_header += ah_hlen; memcpy(skb_network_header(skb), tmp_hdr, hdr_len); diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index 096974ba642..5bd5292ad9f 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -165,30 +165,32 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb) goto out; } + if ((nfrags = skb_cow_data(skb, 0, &trailer)) < 0) { + ret = -EINVAL; + goto out; + } + + skb->ip_summed = CHECKSUM_NONE; + + spin_lock(&x->lock); + /* If integrity check is required, do this. */ if (esp->auth.icv_full_len) { u8 sum[alen]; ret = esp_mac_digest(esp, skb, 0, skb->len - alen); if (ret) - goto out; + goto unlock; if (skb_copy_bits(skb, skb->len - alen, sum, alen)) BUG(); if (unlikely(memcmp(esp->auth.work_icv, sum, alen))) { ret = -EBADMSG; - goto out; + goto unlock; } } - if ((nfrags = skb_cow_data(skb, 0, &trailer)) < 0) { - ret = -EINVAL; - goto out; - } - - skb->ip_summed = CHECKSUM_NONE; - esph = (struct ip_esp_hdr *)skb->data; iph = ipv6_hdr(skb); @@ -197,15 +199,13 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb) crypto_blkcipher_set_iv(tfm, esph->enc_data, esp->conf.ivlen); { - u8 nexthdr[2]; struct scatterlist *sg = &esp->sgbuf[0]; - u8 padlen; if (unlikely(nfrags > ESP_NUM_FAST_SG)) { sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC); if (!sg) { ret = -ENOMEM; - goto out; + goto unlock; } } sg_init_table(sg, nfrags); @@ -215,8 +215,17 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb) ret = crypto_blkcipher_decrypt(&desc, sg, sg, elen); if (unlikely(sg != &esp->sgbuf[0])) kfree(sg); - if (unlikely(ret)) - goto out; + } + +unlock: + spin_unlock(&x->lock); + + if (unlikely(ret)) + goto out; + + { + u8 nexthdr[2]; + u8 padlen; if (skb_copy_bits(skb, skb->len-alen-2, nexthdr, 2)) BUG(); diff --git a/net/ipv6/mip6.c b/net/ipv6/mip6.c index edfd9cdd721..49d396620ea 100644 --- a/net/ipv6/mip6.c +++ b/net/ipv6/mip6.c @@ -128,12 +128,15 @@ static int mip6_destopt_input(struct xfrm_state *x, struct sk_buff *skb) { struct ipv6hdr *iph = ipv6_hdr(skb); struct ipv6_destopt_hdr *destopt = (struct ipv6_destopt_hdr *)skb->data; + int err = destopt->nexthdr; + spin_lock(&x->lock); if (!ipv6_addr_equal(&iph->saddr, (struct in6_addr *)x->coaddr) && !ipv6_addr_any((struct in6_addr *)x->coaddr)) - return -ENOENT; + err = -ENOENT; + spin_unlock(&x->lock); - return destopt->nexthdr; + return err; } /* Destination Option Header is inserted. @@ -344,12 +347,15 @@ static struct xfrm_type mip6_destopt_type = static int mip6_rthdr_input(struct xfrm_state *x, struct sk_buff *skb) { struct rt2_hdr *rt2 = (struct rt2_hdr *)skb->data; + int err = rt2->rt_hdr.nexthdr; + spin_lock(&x->lock); if (!ipv6_addr_equal(&rt2->addr, (struct in6_addr *)x->coaddr) && !ipv6_addr_any((struct in6_addr *)x->coaddr)) - return -ENOENT; + err = -ENOENT; + spin_unlock(&x->lock); - return rt2->rt_hdr.nexthdr; + return err; } /* Routing Header type 2 is inserted. diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index b7d68eb9434..5cad522e8ef 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-70-g09d2 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 --- include/net/xfrm.h | 33 ++++++++--- net/ipv4/ah4.c | 4 +- net/ipv4/esp4.c | 1 + net/ipv6/ah6.c | 2 +- net/ipv6/esp6.c | 1 + net/ipv6/xfrm6_input.c | 1 + net/xfrm/xfrm_input.c | 3 +- net/xfrm/xfrm_output.c | 2 + net/xfrm/xfrm_policy.c | 14 ++--- net/xfrm/xfrm_state.c | 153 +++++++++++++++++++++++++++++++++++++++++++------ 10 files changed, 180 insertions(+), 34 deletions(-) (limited to 'net/ipv4/ah4.c') diff --git a/include/net/xfrm.h b/include/net/xfrm.h index f333c95c418..5d5580ac010 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -565,26 +565,33 @@ struct xfrm_audit }; #ifdef CONFIG_AUDITSYSCALL -static inline struct audit_buffer *xfrm_audit_start(u32 auid, u32 secid) +static inline struct audit_buffer *xfrm_audit_start(const char *op) { struct audit_buffer *audit_buf = NULL; - char *secctx; - u32 secctx_len; + if (audit_enabled == 0) + return NULL; audit_buf = audit_log_start(current->audit_context, GFP_ATOMIC, - AUDIT_MAC_IPSEC_EVENT); + AUDIT_MAC_IPSEC_EVENT); if (audit_buf == NULL) return NULL; + audit_log_format(audit_buf, "op=%s", op); + return audit_buf; +} - audit_log_format(audit_buf, "auid=%u", auid); +static inline void xfrm_audit_helper_usrinfo(u32 auid, u32 secid, + struct audit_buffer *audit_buf) +{ + char *secctx; + u32 secctx_len; + audit_log_format(audit_buf, " auid=%u", auid); if (secid != 0 && security_secid_to_secctx(secid, &secctx, &secctx_len) == 0) { audit_log_format(audit_buf, " subj=%s", secctx); security_release_secctx(secctx, secctx_len); } else audit_log_task_context(audit_buf); - return audit_buf; } extern void xfrm_audit_policy_add(struct xfrm_policy *xp, int result, @@ -595,11 +602,22 @@ extern void xfrm_audit_state_add(struct xfrm_state *x, int result, u32 auid, u32 secid); extern void xfrm_audit_state_delete(struct xfrm_state *x, int result, u32 auid, u32 secid); +extern void xfrm_audit_state_replay_overflow(struct xfrm_state *x, + struct sk_buff *skb); +extern void xfrm_audit_state_notfound_simple(struct sk_buff *skb, u16 family); +extern void xfrm_audit_state_notfound(struct sk_buff *skb, u16 family, + __be32 net_spi, __be32 net_seq); +extern void xfrm_audit_state_icvfail(struct xfrm_state *x, + struct sk_buff *skb, u8 proto); #else #define xfrm_audit_policy_add(x, r, a, s) do { ; } while (0) #define xfrm_audit_policy_delete(x, r, a, s) do { ; } while (0) #define xfrm_audit_state_add(x, r, a, s) do { ; } while (0) #define xfrm_audit_state_delete(x, r, a, s) do { ; } while (0) +#define xfrm_audit_state_replay_overflow(x, s) do { ; } while (0) +#define xfrm_audit_state_notfound_simple(s, f) do { ; } while (0) +#define xfrm_audit_state_notfound(s, f, sp, sq) do { ; } while (0) +#define xfrm_audit_state_icvfail(x, s, p) do { ; } while (0) #endif /* CONFIG_AUDITSYSCALL */ static inline void xfrm_pol_hold(struct xfrm_policy *policy) @@ -1214,7 +1232,8 @@ extern int xfrm_state_delete(struct xfrm_state *x); extern int xfrm_state_flush(u8 proto, struct xfrm_audit *audit_info); extern void xfrm_sad_getinfo(struct xfrmk_sadinfo *si); extern void xfrm_spd_getinfo(struct xfrmk_spdinfo *si); -extern int xfrm_replay_check(struct xfrm_state *x, __be32 seq); +extern int xfrm_replay_check(struct xfrm_state *x, + struct sk_buff *skb, __be32 seq); extern void xfrm_replay_advance(struct xfrm_state *x, __be32 seq); extern void xfrm_replay_notify(struct xfrm_state *x, int event); extern int xfrm_state_mtu(struct xfrm_state *x, int mtu); diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index d76803a3dca..ec8de0aa20e 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c @@ -179,8 +179,10 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb) err = ah_mac_digest(ahp, skb, ah->auth_data); if (err) goto unlock; - if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len)) + if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len)) { + xfrm_audit_state_icvfail(x, skb, IPPROTO_AH); err = -EBADMSG; + } } unlock: spin_unlock(&x->lock); diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index 28ea5c77ca2..b334c7619c0 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -191,6 +191,7 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb) BUG(); if (unlikely(memcmp(esp->auth.work_icv, sum, alen))) { + xfrm_audit_state_icvfail(x, skb, IPPROTO_ESP); err = -EBADMSG; goto unlock; } diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index 1b51d1eedbd..2d32772c87c 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c @@ -381,7 +381,7 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb) if (err) goto unlock; if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len)) { - LIMIT_NETDEBUG(KERN_WARNING "ipsec ah authentication error\n"); + xfrm_audit_state_icvfail(x, skb, IPPROTO_AH); err = -EBADMSG; } } diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index 5bd5292ad9f..e10f10bfe2c 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -186,6 +186,7 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb) BUG(); if (unlikely(memcmp(esp->auth.work_icv, sum, alen))) { + xfrm_audit_state_icvfail(x, skb, IPPROTO_ESP); ret = -EBADMSG; goto unlock; } diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c index 6644fc6d542..063ce6ed1bd 100644 --- a/net/ipv6/xfrm6_input.c +++ b/net/ipv6/xfrm6_input.c @@ -152,6 +152,7 @@ int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, if (!x) { XFRM_INC_STATS(LINUX_MIB_XFRMINNOSTATES); + xfrm_audit_state_notfound_simple(skb, AF_INET6); goto drop; } diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index 493243fc5fe..1b250f33ad5 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; } diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c index 867484a046a..09514449fe8 100644 --- a/net/xfrm/xfrm_output.c +++ b/net/xfrm/xfrm_output.c @@ -57,6 +57,8 @@ static int xfrm_output_one(struct sk_buff *skb, int err) if (x->type->flags & XFRM_TYPE_REPLAY_PROT) { XFRM_SKB_CB(skb)->seq = ++x->replay.oseq; + if (unlikely(x->replay.oseq == 0)) + xfrm_audit_state_replay_overflow(x, skb); if (xfrm_aevent_is_on()) xfrm_replay_notify(x, XFRM_REPLAY_UPDATE); } diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index abc3e39b115..280f8ded975 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -2407,12 +2407,11 @@ void xfrm_audit_policy_add(struct xfrm_policy *xp, int result, { struct audit_buffer *audit_buf; - if (audit_enabled == 0) - return; - audit_buf = xfrm_audit_start(auid, secid); + audit_buf = xfrm_audit_start("SPD-add"); if (audit_buf == NULL) return; - audit_log_format(audit_buf, " op=SPD-add res=%u", result); + xfrm_audit_helper_usrinfo(auid, secid, audit_buf); + audit_log_format(audit_buf, " res=%u", result); xfrm_audit_common_policyinfo(xp, audit_buf); audit_log_end(audit_buf); } @@ -2423,12 +2422,11 @@ void xfrm_audit_policy_delete(struct xfrm_policy *xp, int result, { struct audit_buffer *audit_buf; - if (audit_enabled == 0) - return; - audit_buf = xfrm_audit_start(auid, secid); + audit_buf = xfrm_audit_start("SPD-delete"); if (audit_buf == NULL) return; - audit_log_format(audit_buf, " op=SPD-delete res=%u", result); + xfrm_audit_helper_usrinfo(auid, secid, audit_buf); + audit_log_format(audit_buf, " res=%u", result); xfrm_audit_common_policyinfo(xp, audit_buf); audit_log_end(audit_buf); } diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 9e57378c51d..6bf876c866d 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -61,6 +61,13 @@ static unsigned int xfrm_state_genid; static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family); static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo); +#ifdef CONFIG_AUDITSYSCALL +static void xfrm_audit_state_replay(struct xfrm_state *x, + struct sk_buff *skb, __be32 net_seq); +#else +#define xfrm_audit_state_replay(x, s, sq) do { ; } while (0) +#endif /* CONFIG_AUDITSYSCALL */ + static inline unsigned int xfrm_dst_hash(xfrm_address_t *daddr, xfrm_address_t *saddr, u32 reqid, @@ -1609,13 +1616,14 @@ static void xfrm_replay_timer_handler(unsigned long data) spin_unlock(&x->lock); } -int xfrm_replay_check(struct xfrm_state *x, __be32 net_seq) +int xfrm_replay_check(struct xfrm_state *x, + struct sk_buff *skb, __be32 net_seq) { u32 diff; u32 seq = ntohl(net_seq); if (unlikely(seq == 0)) - return -EINVAL; + goto err; if (likely(seq > x->replay.seq)) return 0; @@ -1624,14 +1632,18 @@ int xfrm_replay_check(struct xfrm_state *x, __be32 net_seq) if (diff >= min_t(unsigned int, x->props.replay_window, sizeof(x->replay.bitmap) * 8)) { x->stats.replay_window++; - return -EINVAL; + goto err; } if (x->replay.bitmap & (1U << diff)) { x->stats.replay++; - return -EINVAL; + goto err; } return 0; + +err: + xfrm_audit_state_replay(x, skb, net_seq); + return -EINVAL; } EXPORT_SYMBOL(xfrm_replay_check); @@ -1996,8 +2008,8 @@ void __init xfrm_state_init(void) } #ifdef CONFIG_AUDITSYSCALL -static inline void xfrm_audit_common_stateinfo(struct xfrm_state *x, - struct audit_buffer *audit_buf) +static inline void xfrm_audit_helper_sainfo(struct xfrm_state *x, + struct audit_buffer *audit_buf) { struct xfrm_sec_ctx *ctx = x->security; u32 spi = ntohl(x->id.spi); @@ -2024,18 +2036,45 @@ static inline void xfrm_audit_common_stateinfo(struct xfrm_state *x, audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi); } +static inline void xfrm_audit_helper_pktinfo(struct sk_buff *skb, u16 family, + struct audit_buffer *audit_buf) +{ + struct iphdr *iph4; + struct ipv6hdr *iph6; + + switch (family) { + case AF_INET: + iph4 = ip_hdr(skb); + audit_log_format(audit_buf, + " src=" NIPQUAD_FMT " dst=" NIPQUAD_FMT, + NIPQUAD(iph4->saddr), + NIPQUAD(iph4->daddr)); + break; + case AF_INET6: + iph6 = ipv6_hdr(skb); + audit_log_format(audit_buf, + " src=" NIP6_FMT " dst=" NIP6_FMT + " flowlbl=0x%x%x%x", + NIP6(iph6->saddr), + NIP6(iph6->daddr), + iph6->flow_lbl[0] & 0x0f, + iph6->flow_lbl[1], + iph6->flow_lbl[2]); + break; + } +} + void xfrm_audit_state_add(struct xfrm_state *x, int result, u32 auid, u32 secid) { struct audit_buffer *audit_buf; - if (audit_enabled == 0) - return; - audit_buf = xfrm_audit_start(auid, secid); + audit_buf = xfrm_audit_start("SAD-add"); if (audit_buf == NULL) return; - audit_log_format(audit_buf, " op=SAD-add res=%u", result); - xfrm_audit_common_stateinfo(x, audit_buf); + xfrm_audit_helper_usrinfo(auid, secid, audit_buf); + xfrm_audit_helper_sainfo(x, audit_buf); + audit_log_format(audit_buf, " res=%u", result); audit_log_end(audit_buf); } EXPORT_SYMBOL_GPL(xfrm_audit_state_add); @@ -2045,14 +2084,96 @@ void xfrm_audit_state_delete(struct xfrm_state *x, int result, { struct audit_buffer *audit_buf; - if (audit_enabled == 0) - return; - audit_buf = xfrm_audit_start(auid, secid); + audit_buf = xfrm_audit_start("SAD-delete"); if (audit_buf == NULL) return; - audit_log_format(audit_buf, " op=SAD-delete res=%u", result); - xfrm_audit_common_stateinfo(x, audit_buf); + xfrm_audit_helper_usrinfo(auid, secid, audit_buf); + xfrm_audit_helper_sainfo(x, audit_buf); + audit_log_format(audit_buf, " res=%u", result); audit_log_end(audit_buf); } EXPORT_SYMBOL_GPL(xfrm_audit_state_delete); + +void xfrm_audit_state_replay_overflow(struct xfrm_state *x, + struct sk_buff *skb) +{ + struct audit_buffer *audit_buf; + u32 spi; + + audit_buf = xfrm_audit_start("SA-replay-overflow"); + if (audit_buf == NULL) + return; + xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf); + /* don't record the sequence number because it's inherent in this kind + * of audit message */ + spi = ntohl(x->id.spi); + audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi); + audit_log_end(audit_buf); +} +EXPORT_SYMBOL_GPL(xfrm_audit_state_replay_overflow); + +static void xfrm_audit_state_replay(struct xfrm_state *x, + struct sk_buff *skb, __be32 net_seq) +{ + struct audit_buffer *audit_buf; + u32 spi; + + audit_buf = xfrm_audit_start("SA-replayed-pkt"); + if (audit_buf == NULL) + return; + xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf); + spi = ntohl(x->id.spi); + audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u", + spi, spi, ntohl(net_seq)); + audit_log_end(audit_buf); +} + +void xfrm_audit_state_notfound_simple(struct sk_buff *skb, u16 family) +{ + struct audit_buffer *audit_buf; + + audit_buf = xfrm_audit_start("SA-notfound"); + if (audit_buf == NULL) + return; + xfrm_audit_helper_pktinfo(skb, family, audit_buf); + audit_log_end(audit_buf); +} +EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound_simple); + +void xfrm_audit_state_notfound(struct sk_buff *skb, u16 family, + __be32 net_spi, __be32 net_seq) +{ + struct audit_buffer *audit_buf; + u32 spi; + + audit_buf = xfrm_audit_start("SA-notfound"); + if (audit_buf == NULL) + return; + xfrm_audit_helper_pktinfo(skb, family, audit_buf); + spi = ntohl(net_spi); + audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u", + spi, spi, ntohl(net_seq)); + audit_log_end(audit_buf); +} +EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound); + +void xfrm_audit_state_icvfail(struct xfrm_state *x, + struct sk_buff *skb, u8 proto) +{ + struct audit_buffer *audit_buf; + __be32 net_spi; + __be32 net_seq; + + audit_buf = xfrm_audit_start("SA-icv-failure"); + if (audit_buf == NULL) + return; + xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf); + if (xfrm_parse_spi(skb, proto, &net_spi, &net_seq) == 0) { + u32 spi = ntohl(net_spi); + audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u", + spi, spi, ntohl(net_seq)); + } + audit_log_end(audit_buf); +} +EXPORT_SYMBOL_GPL(xfrm_audit_state_icvfail); #endif /* CONFIG_AUDITSYSCALL */ -- cgit v1.2.3-70-g09d2 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/ipv4/ah4.c | 4 +--- net/ipv4/esp4.c | 1 - net/ipv6/ah6.c | 4 +--- net/ipv6/esp6.c | 1 - net/xfrm/xfrm_input.c | 5 ++++- 5 files changed, 6 insertions(+), 9 deletions(-) (limited to 'net/ipv4/ah4.c') diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index ec8de0aa20e..d76803a3dca 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c @@ -179,10 +179,8 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb) err = ah_mac_digest(ahp, skb, ah->auth_data); if (err) goto unlock; - if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len)) { - xfrm_audit_state_icvfail(x, skb, IPPROTO_AH); + if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len)) err = -EBADMSG; - } } unlock: spin_unlock(&x->lock); diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index b334c7619c0..28ea5c77ca2 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -191,7 +191,6 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb) BUG(); if (unlikely(memcmp(esp->auth.work_icv, sum, alen))) { - xfrm_audit_state_icvfail(x, skb, IPPROTO_ESP); err = -EBADMSG; goto unlock; } diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index 2d32772c87c..fb0d07a15e9 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c @@ -380,10 +380,8 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb) err = ah_mac_digest(ahp, skb, ah->auth_data); if (err) goto unlock; - if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len)) { - xfrm_audit_state_icvfail(x, skb, IPPROTO_AH); + if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len)) err = -EBADMSG; - } } unlock: spin_unlock(&x->lock); diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index e10f10bfe2c..5bd5292ad9f 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -186,7 +186,6 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb) BUG(); if (unlikely(memcmp(esp->auth.work_icv, sum, alen))) { - xfrm_audit_state_icvfail(x, skb, IPPROTO_ESP); ret = -EBADMSG; goto unlock; } diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index 1b250f33ad5..039e7019c48 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-70-g09d2