Skip to contentSkip to conversation

XFRM auditing patch rebased

PATCH Applied Paul Moore 2 participants 5 messages Dec 21, 2007

Subsystems (3)
lore
Share & tools
lore

Paul Moore

author
#0 lore raw

cover XFRM auditing patch rebased

Based on the net-2.6.25 tree from about an hour ago. The first patch was dropped because it is already applied.

Signature · 2 lines
paul moore
linux security @ hp
author
#1 lore raw

PATCH 1/2 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.

---

 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(-)
include/net/xfrm.h +26 -7
index 2ed25e7..9141bbd 100644
@@ -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);
net/ipv4/ah4.c +3 -1
index d76803a..ec8de0a 100644
@@ -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);
net/ipv4/esp4.c +1 -0
index 28ea5c7..b334c76 100644
@@ -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;
 		}
net/ipv6/ah6.c +1 -1
index 1b51d1e..2d32772 100644
@@ -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;
 		}
 	}
net/ipv6/esp6.c +1 -0
index 5bd5292..e10f10b 100644
@@ -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;
 		}
net/ipv6/xfrm6_input.c +1 -0
index 6644fc6..063ce6e 100644
@@ -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;
 	}
 
net/xfrm/xfrm_input.c +2 -1
index 493243f..1b250f3 100644
@@ -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;
 		}
net/xfrm/xfrm_output.c +2 -0
index 867484a..0951444 100644
@@ -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);
 		}
net/xfrm/xfrm_policy.c +6 -8
index abc3e39..280f8de 100644
@@ -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);
 }
net/xfrm/xfrm_state.c +137 -16

210 lines not on this page · raw message

maintainer Applied
#2 lore raw

Re: [PATCH 1/2] XFRM: RFC4303 compliant auditing

From: Paul Moore <[email protected]>
Date: Fri, 21 Dec 2007 09:14:55 -0500

Quoted 16 lines

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()

Quoted 6 lines

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.

Applied.

author
#3 lore raw

PATCH 2/2 XFRM: Drop packets when replay counter would overflow

In reply to Paul Moore

According to RFC4303, section 3.3.3 we need to drop outgoing packets which cause the replay counter to overflow:

3.3.3. Sequence Number Generation

The sender's counter is initialized to 0 when an SA is established. The sender increments the sequence number (or ESN) counter for this SA and inserts the low-order 32 bits of the value into the Sequence Number field. Thus, the first packet sent using a given SA will contain a sequence number of 1.

If anti-replay is enabled (the default), the sender checks to ensure that the counter has not cycled before inserting the new value in the Sequence Number field. In other words, the sender MUST NOT send a packet on an SA if doing so would cause the sequence number to cycle. An attempt to transmit a packet that would result in sequence number overflow is an auditable event. The audit log entry for this event SHOULD include the SPI value, current date/time, Source Address, Destination Address, and (in IPv6) the cleartext Flow ID.

---

 net/xfrm/xfrm_output.c |    5 ++++-
 1 files changed, 4 insertions(+), 1 deletions(-)
net/xfrm/xfrm_output.c +4 -1
index 0951444..d73003c 100644
@@ -57,8 +57,11 @@ 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))
+			if (unlikely(x->replay.oseq == 0)) {
+				x->replay.oseq--;
 				xfrm_audit_state_replay_overflow(x, skb);
+				goto error;
+			}
 			if (xfrm_aevent_is_on())
 				xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
 		}
maintainer Applied
#4 lore raw

Re: [PATCH 2/2] XFRM: Drop packets when replay counter would overflow

From: Paul Moore <[email protected]>
Date: Fri, 21 Dec 2007 09:15:00 -0500

Quoted 20 lines

According to RFC4303, section 3.3.3 we need to drop outgoing packets which cause the replay counter to overflow:

3.3.3. Sequence Number Generation

The sender's counter is initialized to 0 when an SA is established. The sender increments the sequence number (or ESN) counter for this SA and inserts the low-order 32 bits of the value into the Sequence Number field. Thus, the first packet sent using a given SA will contain a sequence number of 1.

If anti-replay is enabled (the default), the sender checks to ensure that the counter has not cycled before inserting the new value in the Sequence Number field. In other words, the sender MUST NOT send a packet on an SA if doing so would cause the sequence number to cycle. An attempt to transmit a packet that would result in sequence number overflow is an auditable event. The audit log entry for this event SHOULD include the SPI value, current date/time, Source Address, Destination Address, and (in IPv6) the cleartext Flow ID.

Quoted 1 line

Applied.