Commit 2f19f50e authored by David S. Miller's avatar David S. Miller

Merge branch 'dst-tag-ksz-fix'

Florian Fainelli says:

====================
net: dsa: Fix tag_ksz.c

This implements David's suggestion of providing low-level functions
to control whether skb_pad() and skb_put_padto() should be freeing
the passed skb.

We make use of it to fix a double free in net/dsa/tag_ksz.c that would
occur if we kept using skb_put_padto() in both places.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 013dae5d 49716679
...@@ -973,7 +973,23 @@ int __must_check skb_to_sgvec_nomark(struct sk_buff *skb, struct scatterlist *sg ...@@ -973,7 +973,23 @@ int __must_check skb_to_sgvec_nomark(struct sk_buff *skb, struct scatterlist *sg
int __must_check skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int __must_check skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg,
int offset, int len); int offset, int len);
int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer); int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer);
int skb_pad(struct sk_buff *skb, int pad); int __skb_pad(struct sk_buff *skb, int pad, bool free_on_error);
/**
* skb_pad - zero pad the tail of an skb
* @skb: buffer to pad
* @pad: space to pad
*
* Ensure that a buffer is followed by a padding area that is zero
* filled. Used by network drivers which may DMA or transfer data
* beyond the buffer end onto the wire.
*
* May return error in out of memory cases. The skb is freed on error.
*/
static inline int skb_pad(struct sk_buff *skb, int pad)
{
return __skb_pad(skb, pad, true);
}
#define dev_kfree_skb(a) consume_skb(a) #define dev_kfree_skb(a) consume_skb(a)
int skb_append_datato_frags(struct sock *sk, struct sk_buff *skb, int skb_append_datato_frags(struct sock *sk, struct sk_buff *skb,
...@@ -2825,25 +2841,42 @@ static inline int skb_padto(struct sk_buff *skb, unsigned int len) ...@@ -2825,25 +2841,42 @@ static inline int skb_padto(struct sk_buff *skb, unsigned int len)
* skb_put_padto - increase size and pad an skbuff up to a minimal size * skb_put_padto - increase size and pad an skbuff up to a minimal size
* @skb: buffer to pad * @skb: buffer to pad
* @len: minimal length * @len: minimal length
* @free_on_error: free buffer on error
* *
* Pads up a buffer to ensure the trailing bytes exist and are * Pads up a buffer to ensure the trailing bytes exist and are
* blanked. If the buffer already contains sufficient data it * blanked. If the buffer already contains sufficient data it
* is untouched. Otherwise it is extended. Returns zero on * is untouched. Otherwise it is extended. Returns zero on
* success. The skb is freed on error. * success. The skb is freed on error if @free_on_error is true.
*/ */
static inline int skb_put_padto(struct sk_buff *skb, unsigned int len) static inline int __skb_put_padto(struct sk_buff *skb, unsigned int len,
bool free_on_error)
{ {
unsigned int size = skb->len; unsigned int size = skb->len;
if (unlikely(size < len)) { if (unlikely(size < len)) {
len -= size; len -= size;
if (skb_pad(skb, len)) if (__skb_pad(skb, len, free_on_error))
return -ENOMEM; return -ENOMEM;
__skb_put(skb, len); __skb_put(skb, len);
} }
return 0; return 0;
} }
/**
* skb_put_padto - increase size and pad an skbuff up to a minimal size
* @skb: buffer to pad
* @len: minimal length
*
* Pads up a buffer to ensure the trailing bytes exist and are
* blanked. If the buffer already contains sufficient data it
* is untouched. Otherwise it is extended. Returns zero on
* success. The skb is freed on error.
*/
static inline int skb_put_padto(struct sk_buff *skb, unsigned int len)
{
return __skb_put_padto(skb, len, true);
}
static inline int skb_add_data(struct sk_buff *skb, static inline int skb_add_data(struct sk_buff *skb,
struct iov_iter *from, int copy) struct iov_iter *from, int copy)
{ {
......
...@@ -1363,18 +1363,20 @@ struct sk_buff *skb_copy_expand(const struct sk_buff *skb, ...@@ -1363,18 +1363,20 @@ struct sk_buff *skb_copy_expand(const struct sk_buff *skb,
EXPORT_SYMBOL(skb_copy_expand); EXPORT_SYMBOL(skb_copy_expand);
/** /**
* skb_pad - zero pad the tail of an skb * __skb_pad - zero pad the tail of an skb
* @skb: buffer to pad * @skb: buffer to pad
* @pad: space to pad * @pad: space to pad
* @free_on_error: free buffer on error
* *
* Ensure that a buffer is followed by a padding area that is zero * Ensure that a buffer is followed by a padding area that is zero
* filled. Used by network drivers which may DMA or transfer data * filled. Used by network drivers which may DMA or transfer data
* beyond the buffer end onto the wire. * beyond the buffer end onto the wire.
* *
* May return error in out of memory cases. The skb is freed on error. * May return error in out of memory cases. The skb is freed on error
* if @free_on_error is true.
*/ */
int skb_pad(struct sk_buff *skb, int pad) int __skb_pad(struct sk_buff *skb, int pad, bool free_on_error)
{ {
int err; int err;
int ntail; int ntail;
...@@ -1403,10 +1405,11 @@ int skb_pad(struct sk_buff *skb, int pad) ...@@ -1403,10 +1405,11 @@ int skb_pad(struct sk_buff *skb, int pad)
return 0; return 0;
free_skb: free_skb:
if (free_on_error)
kfree_skb(skb); kfree_skb(skb);
return err; return err;
} }
EXPORT_SYMBOL(skb_pad); EXPORT_SYMBOL(__skb_pad);
/** /**
* pskb_put - add data to the tail of a potentially fragmented buffer * pskb_put - add data to the tail of a potentially fragmented buffer
......
...@@ -42,7 +42,8 @@ static struct sk_buff *ksz_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -42,7 +42,8 @@ static struct sk_buff *ksz_xmit(struct sk_buff *skb, struct net_device *dev)
padlen = (skb->len >= ETH_ZLEN) ? 0 : ETH_ZLEN - skb->len; padlen = (skb->len >= ETH_ZLEN) ? 0 : ETH_ZLEN - skb->len;
if (skb_tailroom(skb) >= padlen + KSZ_INGRESS_TAG_LEN) { if (skb_tailroom(skb) >= padlen + KSZ_INGRESS_TAG_LEN) {
if (skb_put_padto(skb, skb->len + padlen)) /* Let dsa_slave_xmit() free skb */
if (__skb_put_padto(skb, skb->len + padlen, false))
return NULL; return NULL;
nskb = skb; nskb = skb;
...@@ -60,10 +61,11 @@ static struct sk_buff *ksz_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -60,10 +61,11 @@ static struct sk_buff *ksz_xmit(struct sk_buff *skb, struct net_device *dev)
skb_transport_header(skb) - skb->head); skb_transport_header(skb) - skb->head);
skb_copy_and_csum_dev(skb, skb_put(nskb, skb->len)); skb_copy_and_csum_dev(skb, skb_put(nskb, skb->len));
if (skb_put_padto(nskb, nskb->len + padlen)) { /* Let skb_put_padto() free nskb, and let dsa_slave_xmit() free
kfree_skb(nskb); * skb
*/
if (skb_put_padto(nskb, nskb->len + padlen))
return NULL; return NULL;
}
kfree_skb(skb); kfree_skb(skb);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment