Skip to contentSkip to conversation

ipsec: fix IPv4 AH alignment on 32 bits

RFC PATCH In review Nicolas Dichtel 4 participants 11 messages Jan 13, 2011 – Feb 28, 2011

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

RFC PATCH 1/1 ipsec: fix IPv4 AH alignment on 32 bits

Hi,

here is a patch to fix alignment of IPv4 AH. Note that this break compatiblity for some algorithms (like SHA256) with old kernels ... but upstream cannot use SHA256 on IPv4, for example, with a target that is RFC compliant.

I don't know what is the best way to fix this.

Regards,
Nicolas

Quoted 1 line

From 14bbe173eed25cf59e3e54222eb7de1a5578e54e Mon Sep 17 00:00:00 2001

From: Dang Hongwu <[email protected]>
Date: Wed, 22 Dec 2010 11:38:47 -0500
Subject: [PATCH] ipsec: fix IPv4 AH alignment on 32 bits

The Linux IPv4 AH stack aligns the AH header on a 64 bit boundary (like in IPv6). This is not RFC compliant (see RFC4302, Section 3.3.3.2.1), it should be aligned on 32 bits.

For most of the authentication algorithms, the ICV size is 96 bits. The AH header alignment on 32 or 64 bits gives the same results.

However for SHA-256-128 for instance, the wrong 64 bit alignment results in adding useless padding in IPv4 AH, which is forbidden by the RFC.

---
 include/net/xfrm.h |    1 +
 net/ipv4/ah4.c     |    8 ++++----
 2 files changed, 5 insertions(+), 4 deletions(-)
include/net/xfrm.h +1 -0
index bcfb6b2..525d882 100644
@@ -36,6 +36,7 @@
 #define XFRM_PROTO_ROUTING	IPPROTO_ROUTING
 #define XFRM_PROTO_DSTOPTS	IPPROTO_DSTOPTS
 
+#define XFRM_ALIGN4(len)	(((len) + 3) & ~3)
 #define XFRM_ALIGN8(len)	(((len) + 7) & ~7)
 #define MODULE_ALIAS_XFRM_MODE(family, encap) \
 	MODULE_ALIAS("xfrm-mode-" __stringify(family) "-" __stringify(encap))
net/ipv4/ah4.c +4 -4
index 86961be..95561d6 100644
@@ -201,7 +201,7 @@ static int ah_output(struct xfrm_state *x, struct sk_buff *skb)
 	top_iph->ttl = 0;
 	top_iph->check = 0;
 
-	ah->hdrlen  = (XFRM_ALIGN8(sizeof(*ah) + ahp->icv_trunc_len) >> 2) - 2;
+	ah->hdrlen  = (XFRM_ALIGN4(sizeof(*ah) + ahp->icv_trunc_len) >> 2) - 2;
 
 	ah->reserved = 0;
 	ah->spi = x->id.spi;
@@ -299,8 +299,8 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb)
 	nexthdr = ah->nexthdr;
 	ah_hlen = (ah->hdrlen + 2) << 2;
 
-	if (ah_hlen != XFRM_ALIGN8(sizeof(*ah) + ahp->icv_full_len) &&
-	    ah_hlen != XFRM_ALIGN8(sizeof(*ah) + ahp->icv_trunc_len))
+	if (ah_hlen != XFRM_ALIGN4(sizeof(*ah) + ahp->icv_full_len) &&
+	    ah_hlen != XFRM_ALIGN4(sizeof(*ah) + ahp->icv_trunc_len))
 		goto out;
 
 	if (!pskb_may_pull(skb, ah_hlen))
@@ -450,7 +450,7 @@ static int ah_init_state(struct xfrm_state *x)
 
 	BUG_ON(ahp->icv_trunc_len > MAX_AH_AUTH_LEN);
 
-	x->props.header_len = XFRM_ALIGN8(sizeof(struct ip_auth_hdr) +
+	x->props.header_len = XFRM_ALIGN4(sizeof(struct ip_auth_hdr) +
 					  ahp->icv_trunc_len);
 	if (x->props.mode == XFRM_MODE_TUNNEL)
 		x->props.header_len += sizeof(struct iphdr);
Signature · 1 line
1.5.6.5
maintainer
#1 lore raw

From: Nicolas Dichtel <[email protected]>
Date: Thu, 13 Jan 2011 18:20:19 +0100

Quoted 6 lines

here is a patch to fix alignment of IPv4 AH. Note that this break compatiblity for some algorithms (like SHA256) with old kernels ... but upstream cannot use SHA256 on IPv4, for example, with a target that is RFC compliant.

I don't know what is the best way to fix this.

We cannot just start rejecting the old 8-byte alignment on input if Linux has been using an 8-byte alignment since day one.

If you want this change to be considered seriously, you need to relax the AH4 input check.

maintainer
#2 lore raw
Quoted 6 lines · David Miller

We cannot just start rejecting the old 8-byte alignment on input if Linux has been using an 8-byte alignment since day one.

If you want this change to be considered seriously, you need to relax the AH4 input check.

I second your sentiment. However, in this particular case it would appear that our old implementation was also overly strict in rejecting 32-bit alignment so even if we relax it now it still wouldn't work with an old implementation once we reduce the padding on output (unless you traffic was one-way only).

So perhaps an SA configuration flag is needed?

Cheers,

Signature · 3 lines
Email: Herbert Xu <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
#3 lore raw
Quoted 5 lines · Herbert Xu
Quoted 4 lines · David Miller

We cannot just start rejecting the old 8-byte alignment on input if Linux has been using an 8-byte alignment since day one.

Quoted 8 lines
Quoted 2 lines

If you want this change to be considered seriously, you need to relax the AH4 input check.

I second your sentiment. However, in this particular case it would appear that our old implementation was also overly strict in rejecting 32-bit alignment so even if we relax it now it still wouldn't work with an old implementation once we reduce the padding on output (unless you traffic was one-way only).

Yes, this was my initial problem.

Quoted 2 lines

So perhaps an SA configuration flag is needed?

I agree. If David is ok, I will update the patch.

Regards,
Nicolas

maintainer
#4 lore raw

From: Nicolas Dichtel <[email protected]>
Date: Fri, 28 Jan 2011 09:51:40 +0100

Quoted 3 lines · Herbert Xu
Quoted 1 line

So perhaps an SA configuration flag is needed?

I agree. If David is ok, I will update the patch.

Sounds good to me.

#5 lore raw

PATCH 1/1 ipsec: allow to align IPv4 AH on 32 bits

Quoted 8 lines · David Miller

From: Nicolas Dichtel<[email protected]>
Date: Fri, 28 Jan 2011 09:51:40 +0100

Quoted 3 lines · Herbert Xu
Quoted 1 line

So perhaps an SA configuration flag is needed?

I agree. If David is ok, I will update the patch.

Sounds good to me.

Here is the new patch.

The patch for iproute2 in the next email.

Regards,
Nicolas

Quoted 1 line

From 1772aa5401b24f4cb4cc10b038becdeb2c687531 Mon Sep 17 00:00:00 2001

From: Dang Hongwu <[email protected]>
Date: Wed, 22 Dec 2010 11:38:47 -0500
Subject: [PATCH] ipsec: allow to align IPv4 AH on 32 bits

The Linux IPv4 AH stack aligns the AH header on a 64 bit boundary (like in IPv6). This is not RFC compliant (see RFC4302, Section 3.3.3.2.1), it should be aligned on 32 bits.

For most of the authentication algorithms, the ICV size is 96 bits. The AH header alignment on 32 or 64 bits gives the same results.

However for SHA-256-128 for instance, the wrong 64 bit alignment results in adding useless padding in IPv4 AH, which is forbidden by the RFC.

To avoid breaking backward compatibility, we use a new flag (XFRM_STATE_ALIGN4) do change original behavior.

Initial patch from Dang Hongwu <[email protected]> and Christophe Gouault <[email protected]>.

---
 include/linux/xfrm.h |    1 +
 include/net/xfrm.h   |    1 +
 net/ipv4/ah4.c       |   25 +++++++++++++++++++------
 3 files changed, 21 insertions(+), 6 deletions(-)
include/linux/xfrm.h +1 -0
index 930fdd2..b93d6f5 100644
@@ -350,6 +350,7 @@ struct xfrm_usersa_info {
 #define XFRM_STATE_WILDRECV	8
 #define XFRM_STATE_ICMP		16
 #define XFRM_STATE_AF_UNSPEC	32
+#define XFRM_STATE_ALIGN4	64
 };
 
 struct xfrm_usersa_id {
include/net/xfrm.h +1 -0
index b9f385d..1f6e8a0 100644
@@ -36,6 +36,7 @@
 #define XFRM_PROTO_ROUTING	IPPROTO_ROUTING
 #define XFRM_PROTO_DSTOPTS	IPPROTO_DSTOPTS
 
+#define XFRM_ALIGN4(len)	(((len) + 3) & ~3)
 #define XFRM_ALIGN8(len)	(((len) + 7) & ~7)
 #define MODULE_ALIAS_XFRM_MODE(family, encap) \
 	MODULE_ALIAS("xfrm-mode-" __stringify(family) "-" __stringify(encap))
net/ipv4/ah4.c +19 -6
index 86961be..325053d 100644
@@ -201,7 +201,10 @@ static int ah_output(struct xfrm_state *x, struct sk_buff *skb)
 	top_iph->ttl = 0;
 	top_iph->check = 0;
 
-	ah->hdrlen  = (XFRM_ALIGN8(sizeof(*ah) + ahp->icv_trunc_len) >> 2) - 2;
+	if (x->props.flags & XFRM_STATE_ALIGN4)
+		ah->hdrlen  = (XFRM_ALIGN4(sizeof(*ah) + ahp->icv_trunc_len) >> 2) - 2;
+	else
+		ah->hdrlen  = (XFRM_ALIGN8(sizeof(*ah) + ahp->icv_trunc_len) >> 2) - 2;
 
 	ah->reserved = 0;
 	ah->spi = x->id.spi;
@@ -299,9 +302,15 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb)
 	nexthdr = ah->nexthdr;
 	ah_hlen = (ah->hdrlen + 2) << 2;
 
-	if (ah_hlen != XFRM_ALIGN8(sizeof(*ah) + ahp->icv_full_len) &&
-	    ah_hlen != XFRM_ALIGN8(sizeof(*ah) + ahp->icv_trunc_len))
-		goto out;
+	if (x->props.flags & XFRM_STATE_ALIGN4) {
+		if (ah_hlen != XFRM_ALIGN4(sizeof(*ah) + ahp->icv_full_len) &&
+		    ah_hlen != XFRM_ALIGN4(sizeof(*ah) + ahp->icv_trunc_len))
+			goto out;
+	} else {
+		if (ah_hlen != XFRM_ALIGN8(sizeof(*ah) + ahp->icv_full_len) &&
+		    ah_hlen != XFRM_ALIGN8(sizeof(*ah) + ahp->icv_trunc_len))
+			goto out;
+	}
 
 	if (!pskb_may_pull(skb, ah_hlen))
 		goto out;
@@ -450,8 +459,12 @@ static int ah_init_state(struct xfrm_state *x)
 
 	BUG_ON(ahp->icv_trunc_len > MAX_AH_AUTH_LEN);
 
-	x->props.header_len = XFRM_ALIGN8(sizeof(struct ip_auth_hdr) +
-					  ahp->icv_trunc_len);
+	if (x->props.flags & XFRM_STATE_ALIGN4)
+		x->props.header_len = XFRM_ALIGN4(sizeof(struct ip_auth_hdr) +
+						  ahp->icv_trunc_len);
+	else
+		x->props.header_len = XFRM_ALIGN8(sizeof(struct ip_auth_hdr) +
+						  ahp->icv_trunc_len);
 	if (x->props.mode == XFRM_MODE_TUNNEL)
 		x->props.header_len += sizeof(struct iphdr);
 	x->data = ahp;
Signature · 1 line
1.5.6.5
maintainer Applied
#6 lore raw

Re: [PATCH] ipsec: allow to align IPv4 AH on 32 bits

From: Nicolas Dichtel <[email protected]>
Date: Wed, 02 Feb 2011 17:29:02 +0100

Quoted 11 lines · David Miller
Quoted 8 lines

From: Nicolas Dichtel<[email protected]>
Date: Fri, 28 Jan 2011 09:51:40 +0100

Quoted 3 lines · Herbert Xu
Quoted 1 line

So perhaps an SA configuration flag is needed?

I agree. If David is ok, I will update the patch.

Sounds good to me.

Here is the new patch.

I've applied this to net-next-2.6, thanks.

#7 lore raw

PATCH 1/1 iproute2: allow to specify truncation bits on auth algo

In reply to David Miller
Quoted 8 lines · David Miller

From: Nicolas Dichtel<[email protected]>
Date: Fri, 28 Jan 2011 09:51:40 +0100

Quoted 3 lines · Herbert Xu
Quoted 1 line

So perhaps an SA configuration flag is needed?

I agree. If David is ok, I will update the patch.

Sounds good to me.

And the patch for iproute2.

Regards,
Nicolas

Quoted 1 line

From e0d84548d363cfa46a03719bc318ef52fa5ca98f Mon Sep 17 00:00:00 2001

From: Nicolas Dichtel <[email protected]>
Date: Thu, 23 Dec 2010 06:48:12 -0500
Subject: [PATCH] iproute2: allow to specify truncation bits on auth algo

Attribute XFRMA_ALG_AUTH_TRUNC can be used to specify truncation bits, so we add a new algo type: auth-trunc.

---
 ip/ipxfrm.c     |   28 +++++++++++++++++++++++++++-
 ip/xfrm_state.c |   50 +++++++++++++++++++++++++++++++++-----------------
 2 files changed, 60 insertions(+), 18 deletions(-)
ip/ipxfrm.c +27 -1
index ba7360f..591f7bf 100644
@@ -155,6 +155,7 @@ const char *strxf_xfrmproto(__u8 proto)
 static const struct typeent algo_types[]= {
 	{ "enc", XFRMA_ALG_CRYPT }, { "auth", XFRMA_ALG_AUTH },
 	{ "comp", XFRMA_ALG_COMP }, { "aead", XFRMA_ALG_AEAD },
+	{ "auth-trunc", XFRMA_ALG_AUTH_TRUNC },
 	{ NULL, -1 }
 };
 
@@ -570,6 +571,25 @@ static void xfrm_aead_print(struct xfrm_algo_aead *algo, int len,
 	fprintf(fp, "%s", _SL_);
 }
 
+static void xfrm_auth_trunc_print(struct xfrm_algo_auth *algo, int len,
+				  FILE *fp, const char *prefix)
+{
+	struct {
+		struct xfrm_algo algo;
+		char key[algo->alg_key_len / 8];
+	} base;
+
+	memcpy(base.algo.alg_name, algo->alg_name, sizeof(base.algo.alg_name));
+	base.algo.alg_key_len = algo->alg_key_len;
+	memcpy(base.algo.alg_key, algo->alg_key, algo->alg_key_len / 8);
+
+	__xfrm_algo_print(&base.algo, XFRMA_ALG_AUTH_TRUNC, len, fp, prefix, 0);
+
+	fprintf(fp, " %d", algo->alg_trunc_len);
+
+	fprintf(fp, "%s", _SL_);
+}
+
 static void xfrm_tmpl_print(struct xfrm_user_tmpl *tmpls, int len,
 			    __u16 family, FILE *fp, const char *prefix)
 {
@@ -677,12 +697,18 @@ void xfrm_xfrma_print(struct rtattr *tb[], __u16 family,
 		fprintf(fp, "\tmark %d/0x%x\n", m->v, m->m);
 	}
 
-	if (tb[XFRMA_ALG_AUTH]) {
+	if (tb[XFRMA_ALG_AUTH] && !tb[XFRMA_ALG_AUTH_TRUNC]) {
 		struct rtattr *rta = tb[XFRMA_ALG_AUTH];
 		xfrm_algo_print((struct xfrm_algo *) RTA_DATA(rta),
 				XFRMA_ALG_AUTH, RTA_PAYLOAD(rta), fp, prefix);
 	}
 
+	if (tb[XFRMA_ALG_AUTH_TRUNC]) {
+		struct rtattr *rta = tb[XFRMA_ALG_AUTH_TRUNC];
+		xfrm_auth_trunc_print((struct xfrm_algo_auth *) RTA_DATA(rta),
+				      RTA_PAYLOAD(rta), fp, prefix);
+	}
+
 	if (tb[XFRMA_ALG_AEAD]) {
 		struct rtattr *rta = tb[XFRMA_ALG_AEAD];
 		xfrm_aead_print((struct xfrm_algo_aead *)RTA_DATA(rta),
ip/xfrm_state.c +33 -17

95 lines not on this page · raw message

Signature · 1 line
1.5.6.5
#8 lore raw

Re: [PATCH] iproute2: allow to specify truncation bits on auth algo

Quoted 10 lines · Nicolas Dichtel
Quoted 8 lines · David Miller

From: Nicolas Dichtel<[email protected]>
Date: Fri, 28 Jan 2011 09:51:40 +0100

Quoted 3 lines · Herbert Xu
Quoted 1 line

So perhaps an SA configuration flag is needed?

I agree. If David is ok, I will update the patch.

Sounds good to me.

And the patch for iproute2.

Sorry, two patches were mixed :(

Here is the right one.

Regards,
Nicolas

Quoted 1 line

From fe61b9c3564b2f9504bca652cdea80ff3b5a2743 Mon Sep 17 00:00:00 2001

From: Nicolas Dichtel <[email protected]>
Date: Tue, 1 Feb 2011 07:29:54 -0500
Subject: [PATCH] iproute2: add support of flag XFRM_STATE_ALIGN4

---
 include/linux/xfrm.h |    1 +
 ip/ipxfrm.c          |    1 +
 ip/xfrm_state.c      |    4 +++-
 3 files changed, 5 insertions(+), 1 deletions(-)
include/linux/xfrm.h +1 -0
index 07f2b63..8b2d220 100644
@@ -349,6 +349,7 @@ struct xfrm_usersa_info {
 #define XFRM_STATE_WILDRECV	8
 #define XFRM_STATE_ICMP		16
 #define XFRM_STATE_AF_UNSPEC	32
+#define XFRM_STATE_ALIGN4	64
 };
 
 struct xfrm_usersa_id {
ip/ipxfrm.c +1 -0
index 9753822..ba7360f 100644
@@ -828,6 +828,7 @@ void xfrm_state_info_print(struct xfrm_usersa_info *xsinfo,
 		XFRM_FLAG_PRINT(fp, flags, XFRM_STATE_WILDRECV, "wildrecv");
 		XFRM_FLAG_PRINT(fp, flags, XFRM_STATE_ICMP, "icmp");
 		XFRM_FLAG_PRINT(fp, flags, XFRM_STATE_AF_UNSPEC, "af-unspec");
+		XFRM_FLAG_PRINT(fp, flags, XFRM_STATE_ALIGN4, "align4");
 		if (flags)
 			fprintf(fp, "%x", flags);
 	}
ip/xfrm_state.c +3 -1
index 38d4039..e8c7c96 100644
@@ -83,7 +83,7 @@ static void usage(void)
  	//fprintf(stderr, "REQID - number(default=0)\n");
 
 	fprintf(stderr, "FLAG-LIST := [ FLAG-LIST ] FLAG\n");
-	fprintf(stderr, "FLAG := [ noecn | decap-dscp | nopmtudisc | wildrecv | icmp | af-unspec ]\n");
+	fprintf(stderr, "FLAG := [ noecn | decap-dscp | nopmtudisc | wildrecv | icmp | af-unspec | align4 ]\n");
 
         fprintf(stderr, "ENCAP := ENCAP-TYPE SPORT DPORT OADDR\n");
         fprintf(stderr, "ENCAP-TYPE := espinudp | espinudp-nonike\n");
@@ -214,6 +214,8 @@ static int xfrm_state_flag_parse(__u8 *flags, int *argcp, char ***argvp)
 				*flags |= XFRM_STATE_ICMP;
 			else if (strcmp(*argv, "af-unspec") == 0)
 				*flags |= XFRM_STATE_AF_UNSPEC;
+			else if (strcmp(*argv, "align4") == 0)
+				*flags |= XFRM_STATE_ALIGN4;
 			else {
 				PREV_ARG(); /* back track */
 				break;
Signature · 1 line
1.5.6.5
#9 lore raw

Re: [PATCH] iproute2: allow to specify truncation bits on auth algo

Hi,

what is the status of this patch? It has been set to 'Superseded' in the patchwork tool (http://patchwork.ozlabs.org/patch/81486/).
Kernel headers have been updated in iproute2, should I resend the patch?

Regards,
Nicolas

Quoted 18 lines · Nicolas Dichtel
Quoted 10 lines · Nicolas Dichtel
Quoted 8 lines · David Miller

From: Nicolas Dichtel<[email protected]>
Date: Fri, 28 Jan 2011 09:51:40 +0100

Quoted 3 lines · Herbert Xu
Quoted 1 line

So perhaps an SA configuration flag is needed?

I agree. If David is ok, I will update the patch.

Sounds good to me.

And the patch for iproute2.

Sorry, two patches were mixed :(

Here is the right one.

Regards,
Nicolas

#10 lore raw

Re: [PATCH] iproute2: allow to specify truncation bits on auth algo

It is in net-next branch of iproute