2010-12-07 10:29:01

by Martin Willi

[permalink] [raw]
Subject: [PATCH 0/3] xfrm: ESP Traffic Flow Confidentiality padding (v2)

The following patchset adds Traffic Flow Confidentiality padding. The
first patch introduces a new Netlink XFRM attribute to configure TFC via
userspace. Patch two and three implement the padding logic in IPv4 and
IPv6 ESP. Padding is always done using the RFC4303 format an is clamped
to the PMTU.

Changes from v1:
- Always clamp padding length to never exceed PMTU
- Remove XFRM_TFC_PMTU flag, use USHRT_MAX padding length instead
- Remove ESPv2 padding fallback due to the concerns from Herbert
- Keep the existing ESP padlen field, as we don't mangle ESP padding

I've kept the currently unused flags in the XFRM attribute to implement
ESPv2 fallback or other extensions in the future without changing the ABI.

Martin Willi (3):
xfrm: Add Traffic Flow Confidentiality padding XFRM attribute
xfrm: Traffic Flow Confidentiality for IPv4 ESP
xfrm: Traffic Flow Confidentiality for IPv6 ESP

include/linux/xfrm.h | 6 ++++++
include/net/xfrm.h | 1 +
net/ipv4/esp4.c | 33 +++++++++++++++++++++++++--------
net/ipv6/esp6.c | 33 +++++++++++++++++++++++++--------
net/xfrm/xfrm_user.c | 16 ++++++++++++++--
5 files changed, 71 insertions(+), 18 deletions(-)



2010-12-07 10:29:29

by Martin Willi

[permalink] [raw]
Subject: [PATCH 2/3] xfrm: Traffic Flow Confidentiality for IPv4 ESP

Add TFC padding to all packets smaller than the boundary configured
on the xfrm state. If the boundary is larger than the PMTU, limit
padding to the PMTU.

Signed-off-by: Martin Willi <[email protected]>
---
net/ipv4/esp4.c | 33 +++++++++++++++++++++++++--------
1 files changed, 25 insertions(+), 8 deletions(-)

diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
index 14ca1f1..e7784e8 100644
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -23,6 +23,8 @@ struct esp_skb_cb {

#define ESP_SKB_CB(__skb) ((struct esp_skb_cb *)&((__skb)->cb[0]))

+static u32 esp4_get_mtu(struct xfrm_state *x, int mtu);
+
/*
* Allocate an AEAD request structure with extra space for SG and IV.
*
@@ -117,25 +119,36 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
int blksize;
int clen;
int alen;
+ int plen;
+ int tfclen;
int nfrags;

/* skb is pure payload to encrypt */

err = -ENOMEM;

- /* Round to block size */
- clen = skb->len;
-
esp = x->data;
aead = esp->aead;
alen = crypto_aead_authsize(aead);

+ tfclen = 0;
+ if (x->tfc.pad && x->props.mode == XFRM_MODE_TUNNEL) {
+ struct xfrm_dst *dst = (struct xfrm_dst *)skb_dst(skb);
+ u32 mtu, padto;
+
+ mtu = esp4_get_mtu(x, dst->child_mtu_cached);
+ padto = min_t(u32, x->tfc.pad, mtu);
+ if (skb->len < padto)
+ tfclen = padto - skb->len;
+ }
blksize = ALIGN(crypto_aead_blocksize(aead), 4);
- clen = ALIGN(clen + 2, blksize);
+ clen = ALIGN(skb->len + 2 + tfclen, blksize);
if (esp->padlen)
clen = ALIGN(clen, esp->padlen);
+ plen = clen - skb->len - tfclen;

- if ((err = skb_cow_data(skb, clen - skb->len + alen, &trailer)) < 0)
+ err = skb_cow_data(skb, tfclen + plen + alen, &trailer);
+ if (err < 0)
goto error;
nfrags = err;

@@ -150,13 +163,17 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb)

/* Fill padding... */
tail = skb_tail_pointer(trailer);
+ if (tfclen) {
+ memset(tail, 0, tfclen);
+ tail += tfclen;
+ }
do {
int i;
- for (i=0; i<clen-skb->len - 2; i++)
+ for (i = 0; i < plen - 2; i++)
tail[i] = i + 1;
} while (0);
- tail[clen - skb->len - 2] = (clen - skb->len) - 2;
- tail[clen - skb->len - 1] = *skb_mac_header(skb);
+ tail[plen - 2] = plen - 2;
+ tail[plen - 1] = *skb_mac_header(skb);
pskb_put(skb, trailer, clen - skb->len + alen);

skb_push(skb, -skb_network_offset(skb));
--
1.7.1

2010-12-07 10:29:29

by Martin Willi

[permalink] [raw]
Subject: [PATCH 3/3] xfrm: Traffic Flow Confidentiality for IPv6 ESP

Add TFC padding to all packets smaller than the boundary configured
on the xfrm state. If the boundary is larger than the PMTU, limit
padding to the PMTU.

Signed-off-by: Martin Willi <[email protected]>
---
net/ipv6/esp6.c | 33 +++++++++++++++++++++++++--------
1 files changed, 25 insertions(+), 8 deletions(-)

diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index ee9b93b..8b493b0 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -49,6 +49,8 @@ struct esp_skb_cb {

#define ESP_SKB_CB(__skb) ((struct esp_skb_cb *)&((__skb)->cb[0]))

+static u32 esp6_get_mtu(struct xfrm_state *x, int mtu);
+
/*
* Allocate an AEAD request structure with extra space for SG and IV.
*
@@ -140,6 +142,8 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb)
int blksize;
int clen;
int alen;
+ int plen;
+ int tfclen;
int nfrags;
u8 *iv;
u8 *tail;
@@ -148,18 +152,27 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb)
/* skb is pure payload to encrypt */
err = -ENOMEM;

- /* Round to block size */
- clen = skb->len;
-
aead = esp->aead;
alen = crypto_aead_authsize(aead);

+ tfclen = 0;
+ if (x->tfc.pad && x->props.mode == XFRM_MODE_TUNNEL) {
+ struct xfrm_dst *dst = (struct xfrm_dst *)skb_dst(skb);
+ u32 mtu, padto;
+
+ mtu = esp6_get_mtu(x, dst->child_mtu_cached);
+ padto = min_t(u32, x->tfc.pad, mtu);
+ if (skb->len < padto)
+ tfclen = padto - skb->len;
+ }
blksize = ALIGN(crypto_aead_blocksize(aead), 4);
- clen = ALIGN(clen + 2, blksize);
+ clen = ALIGN(skb->len + 2 + tfclen, blksize);
if (esp->padlen)
clen = ALIGN(clen, esp->padlen);
+ plen = clen - skb->len - tfclen;

- if ((err = skb_cow_data(skb, clen - skb->len + alen, &trailer)) < 0)
+ err = skb_cow_data(skb, tfclen + plen + alen, &trailer);
+ if (err < 0)
goto error;
nfrags = err;

@@ -174,13 +187,17 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb)

/* Fill padding... */
tail = skb_tail_pointer(trailer);
+ if (tfclen) {
+ memset(tail, 0, tfclen);
+ tail += tfclen;
+ }
do {
int i;
- for (i=0; i<clen-skb->len - 2; i++)
+ for (i = 0; i < plen - 2; i++)
tail[i] = i + 1;
} while (0);
- tail[clen-skb->len - 2] = (clen - skb->len) - 2;
- tail[clen - skb->len - 1] = *skb_mac_header(skb);
+ tail[plen - 2] = plen - 2;
+ tail[plen - 1] = *skb_mac_header(skb);
pskb_put(skb, trailer, clen - skb->len + alen);

skb_push(skb, -skb_network_offset(skb));
--
1.7.1

2010-12-07 10:29:02

by Martin Willi

[permalink] [raw]
Subject: [PATCH 1/3] xfrm: Add Traffic Flow Confidentiality padding XFRM attribute

The XFRMA_TFC attribute for XFRM state installation configures
Traffic Flow Confidentiality by padding ESP packets to a specified
length.

Signed-off-by: Martin Willi <[email protected]>
---
include/linux/xfrm.h | 6 ++++++
include/net/xfrm.h | 1 +
net/xfrm/xfrm_user.c | 16 ++++++++++++++--
3 files changed, 21 insertions(+), 2 deletions(-)

diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h
index b971e38..7cd5232 100644
--- a/include/linux/xfrm.h
+++ b/include/linux/xfrm.h
@@ -283,6 +283,7 @@ enum xfrm_attr_type_t {
XFRMA_KMADDRESS, /* struct xfrm_user_kmaddress */
XFRMA_ALG_AUTH_TRUNC, /* struct xfrm_algo_auth */
XFRMA_MARK, /* struct xfrm_mark */
+ XFRMA_TFC, /* struct xfrm_tfc */
__XFRMA_MAX

#define XFRMA_MAX (__XFRMA_MAX - 1)
@@ -293,6 +294,11 @@ struct xfrm_mark {
__u32 m; /* mask */
};

+struct xfrm_tfc {
+ __u16 pad;
+ __u16 flags;
+};
+
enum xfrm_sadattr_type_t {
XFRMA_SAD_UNSPEC,
XFRMA_SAD_CNT,
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index bcfb6b2..03468c0 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -143,6 +143,7 @@ struct xfrm_state {
struct xfrm_id id;
struct xfrm_selector sel;
struct xfrm_mark mark;
+ struct xfrm_tfc tfc;

u32 genid;

diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 8bae6b2..df6a60f 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -148,7 +148,8 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
!attrs[XFRMA_ALG_AUTH_TRUNC]) ||
attrs[XFRMA_ALG_AEAD] ||
attrs[XFRMA_ALG_CRYPT] ||
- attrs[XFRMA_ALG_COMP])
+ attrs[XFRMA_ALG_COMP] ||
+ attrs[XFRMA_TFC])
goto out;
break;

@@ -172,7 +173,8 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
attrs[XFRMA_ALG_AEAD] ||
attrs[XFRMA_ALG_AUTH] ||
attrs[XFRMA_ALG_AUTH_TRUNC] ||
- attrs[XFRMA_ALG_CRYPT])
+ attrs[XFRMA_ALG_CRYPT] ||
+ attrs[XFRMA_TFC])
goto out;
break;

@@ -186,6 +188,7 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
attrs[XFRMA_ALG_CRYPT] ||
attrs[XFRMA_ENCAP] ||
attrs[XFRMA_SEC_CTX] ||
+ attrs[XFRMA_TFC] ||
!attrs[XFRMA_COADDR])
goto out;
break;
@@ -439,6 +442,9 @@ static struct xfrm_state *xfrm_state_construct(struct net *net,
goto error;
}

+ if (attrs[XFRMA_TFC])
+ memcpy(&x->tfc, nla_data(attrs[XFRMA_TFC]), sizeof(x->tfc));
+
if (attrs[XFRMA_COADDR]) {
x->coaddr = kmemdup(nla_data(attrs[XFRMA_COADDR]),
sizeof(*x->coaddr), GFP_KERNEL);
@@ -688,6 +694,9 @@ static int copy_to_user_state_extra(struct xfrm_state *x,
if (x->encap)
NLA_PUT(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap);

+ if (x->tfc.pad)
+ NLA_PUT(skb, XFRMA_TFC, sizeof(x->tfc), &x->tfc);
+
if (xfrm_mark_put(skb, &x->mark))
goto nla_put_failure;

@@ -2122,6 +2131,7 @@ static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = {
[XFRMA_MIGRATE] = { .len = sizeof(struct xfrm_user_migrate) },
[XFRMA_KMADDRESS] = { .len = sizeof(struct xfrm_user_kmaddress) },
[XFRMA_MARK] = { .len = sizeof(struct xfrm_mark) },
+ [XFRMA_TFC] = { .len = sizeof(struct xfrm_tfc) },
};

static struct xfrm_link {
@@ -2301,6 +2311,8 @@ static inline size_t xfrm_sa_len(struct xfrm_state *x)
l += nla_total_size(sizeof(*x->calg));
if (x->encap)
l += nla_total_size(sizeof(*x->encap));
+ if (x->tfc.pad)
+ l += nla_total_size(sizeof(x->tfc));
if (x->security)
l += nla_total_size(sizeof(struct xfrm_user_sec_ctx) +
x->security->ctx_len);
--
1.7.1


2010-12-08 08:49:54

by Herbert Xu

[permalink] [raw]
Subject: Re: [PATCH 2/3] xfrm: Traffic Flow Confidentiality for IPv4 ESP

On Tue, Dec 07, 2010 at 11:29:03AM +0100, Martin Willi wrote:
> Add TFC padding to all packets smaller than the boundary configured
> on the xfrm state. If the boundary is larger than the PMTU, limit
> padding to the PMTU.

Thanks for the update Martin.

However, I still think it's more complicated than it needs be.
In particular, why would we need a boundary at all? Setting it to
anything other than the PMTU would seem to defeat the purpose of
TFC for packets between the boundary and the PMTU.

If we can get rid of tfc.pad, we can simplify the user-interface
change to just adding an xfrm_state flag.

Cheers,
--
Email: Herbert Xu <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

2010-12-08 09:20:44

by Martin Willi

[permalink] [raw]
Subject: Re: [PATCH 2/3] xfrm: Traffic Flow Confidentiality for IPv4 ESP


> In particular, why would we need a boundary at all? Setting it to
> anything other than the PMTU would seem to defeat the purpose of
> TFC for packets between the boundary and the PMTU.

I don't agree, this highly depends on the traffic on the SA. For a
general purpose tunnel with TCP flows, PMTU padding is fine. But if
there are only small packets (maybe SIP+RTP), padding to the PMTU is
very expensive.

The administrator setting up the SAs probably knows (or even controls
directly) what traffic it is used for, and might lower the boundary
accordingly.

Regards
Martin

2010-12-08 09:24:34

by Herbert Xu

[permalink] [raw]
Subject: Re: [PATCH 2/3] xfrm: Traffic Flow Confidentiality for IPv4 ESP

On Wed, Dec 08, 2010 at 10:20:41AM +0100, Martin Willi wrote:
>
> > In particular, why would we need a boundary at all? Setting it to
> > anything other than the PMTU would seem to defeat the purpose of
> > TFC for packets between the boundary and the PMTU.
>
> I don't agree, this highly depends on the traffic on the SA. For a
> general purpose tunnel with TCP flows, PMTU padding is fine. But if
> there are only small packets (maybe SIP+RTP), padding to the PMTU is
> very expensive.
>
> The administrator setting up the SAs probably knows (or even controls
> directly) what traffic it is used for, and might lower the boundary
> accordingly.

OK, that's a good reason.

But you should probably get rid of that unused flag field in
the user-interface and just provide a pad length.

Thanks,
--
Email: Herbert Xu <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt