aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorPaul Moore <paul.moore@hp.com>2007-12-21 17:58:11 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 18:00:01 -0500
commitafeb14b49098ba7a51c96e083a4105a0301f94c4 (patch)
tree2675451596adbea8aa261704c356d074136abbbd /net
parentdfd4f0ae2e111e2b93c295938c0e64ebbb69ae6e (diff)
[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 <paul.moore@hp.com> Acked-by: James Morris <jmorris@namei.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/ah4.c4
-rw-r--r--net/ipv4/esp4.c1
-rw-r--r--net/ipv6/ah6.c2
-rw-r--r--net/ipv6/esp6.c1
-rw-r--r--net/ipv6/xfrm6_input.c1
-rw-r--r--net/xfrm/xfrm_input.c3
-rw-r--r--net/xfrm/xfrm_output.c2
-rw-r--r--net/xfrm/xfrm_policy.c14
-rw-r--r--net/xfrm/xfrm_state.c153
9 files changed, 154 insertions, 27 deletions
diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
index d76803a3dcae..ec8de0aa20ec 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)
179 err = ah_mac_digest(ahp, skb, ah->auth_data); 179 err = ah_mac_digest(ahp, skb, ah->auth_data);
180 if (err) 180 if (err)
181 goto unlock; 181 goto unlock;
182 if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len)) 182 if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len)) {
183 xfrm_audit_state_icvfail(x, skb, IPPROTO_AH);
183 err = -EBADMSG; 184 err = -EBADMSG;
185 }
184 } 186 }
185unlock: 187unlock:
186 spin_unlock(&x->lock); 188 spin_unlock(&x->lock);
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
index 28ea5c77ca23..b334c7619c08 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)
191 BUG(); 191 BUG();
192 192
193 if (unlikely(memcmp(esp->auth.work_icv, sum, alen))) { 193 if (unlikely(memcmp(esp->auth.work_icv, sum, alen))) {
194 xfrm_audit_state_icvfail(x, skb, IPPROTO_ESP);
194 err = -EBADMSG; 195 err = -EBADMSG;
195 goto unlock; 196 goto unlock;
196 } 197 }
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
index 1b51d1eedbde..2d32772c87c3 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)
381 if (err) 381 if (err)
382 goto unlock; 382 goto unlock;
383 if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len)) { 383 if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len)) {
384 LIMIT_NETDEBUG(KERN_WARNING "ipsec ah authentication error\n"); 384 xfrm_audit_state_icvfail(x, skb, IPPROTO_AH);
385 err = -EBADMSG; 385 err = -EBADMSG;
386 } 386 }
387 } 387 }
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index 5bd5292ad9fa..e10f10bfe2c9 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)
186 BUG(); 186 BUG();
187 187
188 if (unlikely(memcmp(esp->auth.work_icv, sum, alen))) { 188 if (unlikely(memcmp(esp->auth.work_icv, sum, alen))) {
189 xfrm_audit_state_icvfail(x, skb, IPPROTO_ESP);
189 ret = -EBADMSG; 190 ret = -EBADMSG;
190 goto unlock; 191 goto unlock;
191 } 192 }
diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c
index 6644fc6d5427..063ce6ed1bd0 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,
152 152
153 if (!x) { 153 if (!x) {
154 XFRM_INC_STATS(LINUX_MIB_XFRMINNOSTATES); 154 XFRM_INC_STATS(LINUX_MIB_XFRMINNOSTATES);
155 xfrm_audit_state_notfound_simple(skb, AF_INET6);
155 goto drop; 156 goto drop;
156 } 157 }
157 158
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)
147 x = xfrm_state_lookup(daddr, spi, nexthdr, family); 147 x = xfrm_state_lookup(daddr, spi, nexthdr, family);
148 if (x == NULL) { 148 if (x == NULL) {
149 XFRM_INC_STATS(LINUX_MIB_XFRMINNOSTATES); 149 XFRM_INC_STATS(LINUX_MIB_XFRMINNOSTATES);
150 xfrm_audit_state_notfound(skb, family, spi, seq);
150 goto drop; 151 goto drop;
151 } 152 }
152 153
@@ -163,7 +164,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
163 goto drop_unlock; 164 goto drop_unlock;
164 } 165 }
165 166
166 if (x->props.replay_window && xfrm_replay_check(x, seq)) { 167 if (x->props.replay_window && xfrm_replay_check(x, skb, seq)) {
167 XFRM_INC_STATS(LINUX_MIB_XFRMINSEQOUTOFWINDOW); 168 XFRM_INC_STATS(LINUX_MIB_XFRMINSEQOUTOFWINDOW);
168 goto drop_unlock; 169 goto drop_unlock;
169 } 170 }
diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c
index 867484a046af..09514449fe8a 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)
57 57
58 if (x->type->flags & XFRM_TYPE_REPLAY_PROT) { 58 if (x->type->flags & XFRM_TYPE_REPLAY_PROT) {
59 XFRM_SKB_CB(skb)->seq = ++x->replay.oseq; 59 XFRM_SKB_CB(skb)->seq = ++x->replay.oseq;
60 if (unlikely(x->replay.oseq == 0))
61 xfrm_audit_state_replay_overflow(x, skb);
60 if (xfrm_aevent_is_on()) 62 if (xfrm_aevent_is_on())
61 xfrm_replay_notify(x, XFRM_REPLAY_UPDATE); 63 xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
62 } 64 }
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index abc3e39b115b..280f8ded975c 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,
2407{ 2407{
2408 struct audit_buffer *audit_buf; 2408 struct audit_buffer *audit_buf;
2409 2409
2410 if (audit_enabled == 0) 2410 audit_buf = xfrm_audit_start("SPD-add");
2411 return;
2412 audit_buf = xfrm_audit_start(auid, secid);
2413 if (audit_buf == NULL) 2411 if (audit_buf == NULL)
2414 return; 2412 return;
2415 audit_log_format(audit_buf, " op=SPD-add res=%u", result); 2413 xfrm_audit_helper_usrinfo(auid, secid, audit_buf);
2414 audit_log_format(audit_buf, " res=%u", result);
2416 xfrm_audit_common_policyinfo(xp, audit_buf); 2415 xfrm_audit_common_policyinfo(xp, audit_buf);
2417 audit_log_end(audit_buf); 2416 audit_log_end(audit_buf);
2418} 2417}
@@ -2423,12 +2422,11 @@ void xfrm_audit_policy_delete(struct xfrm_policy *xp, int result,
2423{ 2422{
2424 struct audit_buffer *audit_buf; 2423 struct audit_buffer *audit_buf;
2425 2424
2426 if (audit_enabled == 0) 2425 audit_buf = xfrm_audit_start("SPD-delete");
2427 return;
2428 audit_buf = xfrm_audit_start(auid, secid);
2429 if (audit_buf == NULL) 2426 if (audit_buf == NULL)
2430 return; 2427 return;
2431 audit_log_format(audit_buf, " op=SPD-delete res=%u", result); 2428 xfrm_audit_helper_usrinfo(auid, secid, audit_buf);
2429 audit_log_format(audit_buf, " res=%u", result);
2432 xfrm_audit_common_policyinfo(xp, audit_buf); 2430 xfrm_audit_common_policyinfo(xp, audit_buf);
2433 audit_log_end(audit_buf); 2431 audit_log_end(audit_buf);
2434} 2432}
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 9e57378c51df..6bf876c866df 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -61,6 +61,13 @@ static unsigned int xfrm_state_genid;
61static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family); 61static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family);
62static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo); 62static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo);
63 63
64#ifdef CONFIG_AUDITSYSCALL
65static void xfrm_audit_state_replay(struct xfrm_state *x,
66 struct sk_buff *skb, __be32 net_seq);
67#else
68#define xfrm_audit_state_replay(x, s, sq) do { ; } while (0)
69#endif /* CONFIG_AUDITSYSCALL */
70
64static inline unsigned int xfrm_dst_hash(xfrm_address_t *daddr, 71static inline unsigned int xfrm_dst_hash(xfrm_address_t *daddr,
65 xfrm_address_t *saddr, 72 xfrm_address_t *saddr,
66 u32 reqid, 73 u32 reqid,
@@ -1609,13 +1616,14 @@ static void xfrm_replay_timer_handler(unsigned long data)
1609 spin_unlock(&x->lock); 1616 spin_unlock(&x->lock);
1610} 1617}
1611 1618
1612int xfrm_replay_check(struct xfrm_state *x, __be32 net_seq) 1619int xfrm_replay_check(struct xfrm_state *x,
1620 struct sk_buff *skb, __be32 net_seq)
1613{ 1621{
1614 u32 diff; 1622 u32 diff;
1615 u32 seq = ntohl(net_seq); 1623 u32 seq = ntohl(net_seq);
1616 1624
1617 if (unlikely(seq == 0)) 1625 if (unlikely(seq == 0))
1618 return -EINVAL; 1626 goto err;
1619 1627
1620 if (likely(seq > x->replay.seq)) 1628 if (likely(seq > x->replay.seq))
1621 return 0; 1629 return 0;
@@ -1624,14 +1632,18 @@ int xfrm_replay_check(struct xfrm_state *x, __be32 net_seq)
1624 if (diff >= min_t(unsigned int, x->props.replay_window, 1632 if (diff >= min_t(unsigned int, x->props.replay_window,
1625 sizeof(x->replay.bitmap) * 8)) { 1633 sizeof(x->replay.bitmap) * 8)) {
1626 x->stats.replay_window++; 1634 x->stats.replay_window++;
1627 return -EINVAL; 1635 goto err;
1628 } 1636 }
1629 1637
1630 if (x->replay.bitmap & (1U << diff)) { 1638 if (x->replay.bitmap & (1U << diff)) {
1631 x->stats.replay++; 1639 x->stats.replay++;
1632 return -EINVAL; 1640 goto err;
1633 } 1641 }
1634 return 0; 1642 return 0;
1643
1644err:
1645 xfrm_audit_state_replay(x, skb, net_seq);
1646 return -EINVAL;
1635} 1647}
1636EXPORT_SYMBOL(xfrm_replay_check); 1648EXPORT_SYMBOL(xfrm_replay_check);
1637 1649
@@ -1996,8 +2008,8 @@ void __init xfrm_state_init(void)
1996} 2008}
1997 2009
1998#ifdef CONFIG_AUDITSYSCALL 2010#ifdef CONFIG_AUDITSYSCALL
1999static inline void xfrm_audit_common_stateinfo(struct xfrm_state *x, 2011static inline void xfrm_audit_helper_sainfo(struct xfrm_state *x,
2000 struct audit_buffer *audit_buf) 2012 struct audit_buffer *audit_buf)
2001{ 2013{
2002 struct xfrm_sec_ctx *ctx = x->security; 2014 struct xfrm_sec_ctx *ctx = x->security;
2003 u32 spi = ntohl(x->id.spi); 2015 u32 spi = ntohl(x->id.spi);
@@ -2024,18 +2036,45 @@ static inline void xfrm_audit_common_stateinfo(struct xfrm_state *x,
2024 audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi); 2036 audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi);
2025} 2037}
2026 2038
2039static inline void xfrm_audit_helper_pktinfo(struct sk_buff *skb, u16 family,
2040 struct audit_buffer *audit_buf)
2041{
2042 struct iphdr *iph4;
2043 struct ipv6hdr *iph6;
2044
2045 switch (family) {
2046 case AF_INET:
2047 iph4 = ip_hdr(skb);
2048 audit_log_format(audit_buf,
2049 " src=" NIPQUAD_FMT " dst=" NIPQUAD_FMT,
2050 NIPQUAD(iph4->saddr),
2051 NIPQUAD(iph4->daddr));
2052 break;
2053 case AF_INET6:
2054 iph6 = ipv6_hdr(skb);
2055 audit_log_format(audit_buf,
2056 " src=" NIP6_FMT " dst=" NIP6_FMT
2057 " flowlbl=0x%x%x%x",
2058 NIP6(iph6->saddr),
2059 NIP6(iph6->daddr),
2060 iph6->flow_lbl[0] & 0x0f,
2061 iph6->flow_lbl[1],
2062 iph6->flow_lbl[2]);
2063 break;
2064 }
2065}
2066
2027void xfrm_audit_state_add(struct xfrm_state *x, int result, 2067void xfrm_audit_state_add(struct xfrm_state *x, int result,
2028 u32 auid, u32 secid) 2068 u32 auid, u32 secid)
2029{ 2069{
2030 struct audit_buffer *audit_buf; 2070 struct audit_buffer *audit_buf;
2031 2071
2032 if (audit_enabled == 0) 2072 audit_buf = xfrm_audit_start("SAD-add");
2033 return;
2034 audit_buf = xfrm_audit_start(auid, secid);
2035 if (audit_buf == NULL) 2073 if (audit_buf == NULL)
2036 return; 2074 return;
2037 audit_log_format(audit_buf, " op=SAD-add res=%u", result); 2075 xfrm_audit_helper_usrinfo(auid, secid, audit_buf);
2038 xfrm_audit_common_stateinfo(x, audit_buf); 2076 xfrm_audit_helper_sainfo(x, audit_buf);
2077 audit_log_format(audit_buf, " res=%u", result);
2039 audit_log_end(audit_buf); 2078 audit_log_end(audit_buf);
2040} 2079}
2041EXPORT_SYMBOL_GPL(xfrm_audit_state_add); 2080EXPORT_SYMBOL_GPL(xfrm_audit_state_add);
@@ -2045,14 +2084,96 @@ void xfrm_audit_state_delete(struct xfrm_state *x, int result,
2045{ 2084{
2046 struct audit_buffer *audit_buf; 2085 struct audit_buffer *audit_buf;
2047 2086
2048 if (audit_enabled == 0) 2087 audit_buf = xfrm_audit_start("SAD-delete");
2049 return;
2050 audit_buf = xfrm_audit_start(auid, secid);
2051 if (audit_buf == NULL) 2088 if (audit_buf == NULL)
2052 return; 2089 return;
2053 audit_log_format(audit_buf, " op=SAD-delete res=%u", result); 2090 xfrm_audit_helper_usrinfo(auid, secid, audit_buf);
2054 xfrm_audit_common_stateinfo(x, audit_buf); 2091 xfrm_audit_helper_sainfo(x, audit_buf);
2092 audit_log_format(audit_buf, " res=%u", result);
2055 audit_log_end(audit_buf); 2093 audit_log_end(audit_buf);
2056} 2094}
2057EXPORT_SYMBOL_GPL(xfrm_audit_state_delete); 2095EXPORT_SYMBOL_GPL(xfrm_audit_state_delete);
2096
2097void xfrm_audit_state_replay_overflow(struct xfrm_state *x,
2098 struct sk_buff *skb)
2099{
2100 struct audit_buffer *audit_buf;
2101 u32 spi;
2102
2103 audit_buf = xfrm_audit_start("SA-replay-overflow");
2104 if (audit_buf == NULL)
2105 return;
2106 xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
2107 /* don't record the sequence number because it's inherent in this kind
2108 * of audit message */
2109 spi = ntohl(x->id.spi);
2110 audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi);
2111 audit_log_end(audit_buf);
2112}
2113EXPORT_SYMBOL_GPL(xfrm_audit_state_replay_overflow);
2114
2115static void xfrm_audit_state_replay(struct xfrm_state *x,
2116 struct sk_buff *skb, __be32 net_seq)
2117{
2118 struct audit_buffer *audit_buf;
2119 u32 spi;
2120
2121 audit_buf = xfrm_audit_start("SA-replayed-pkt");
2122 if (audit_buf == NULL)
2123 return;
2124 xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
2125 spi = ntohl(x->id.spi);
2126 audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
2127 spi, spi, ntohl(net_seq));
2128 audit_log_end(audit_buf);
2129}
2130
2131void xfrm_audit_state_notfound_simple(struct sk_buff *skb, u16 family)
2132{
2133 struct audit_buffer *audit_buf;
2134
2135 audit_buf = xfrm_audit_start("SA-notfound");
2136 if (audit_buf == NULL)
2137 return;
2138 xfrm_audit_helper_pktinfo(skb, family, audit_buf);
2139 audit_log_end(audit_buf);
2140}
2141EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound_simple);
2142
2143void xfrm_audit_state_notfound(struct sk_buff *skb, u16 family,
2144 __be32 net_spi, __be32 net_seq)
2145{
2146 struct audit_buffer *audit_buf;
2147 u32 spi;
2148
2149 audit_buf = xfrm_audit_start("SA-notfound");
2150 if (audit_buf == NULL)
2151 return;
2152 xfrm_audit_helper_pktinfo(skb, family, audit_buf);
2153 spi = ntohl(net_spi);
2154 audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
2155 spi, spi, ntohl(net_seq));
2156 audit_log_end(audit_buf);
2157}
2158EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound);
2159
2160void xfrm_audit_state_icvfail(struct xfrm_state *x,
2161 struct sk_buff *skb, u8 proto)
2162{
2163 struct audit_buffer *audit_buf;
2164 __be32 net_spi;
2165 __be32 net_seq;
2166
2167 audit_buf = xfrm_audit_start("SA-icv-failure");
2168 if (audit_buf == NULL)
2169 return;
2170 xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
2171 if (xfrm_parse_spi(skb, proto, &net_spi, &net_seq) == 0) {
2172 u32 spi = ntohl(net_spi);
2173 audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
2174 spi, spi, ntohl(net_seq));
2175 }
2176 audit_log_end(audit_buf);
2177}
2178EXPORT_SYMBOL_GPL(xfrm_audit_state_icvfail);
2058#endif /* CONFIG_AUDITSYSCALL */ 2179#endif /* CONFIG_AUDITSYSCALL */