[NET]: Fix incorrect sg_mark_end() calls.
This fixes scatterlist corruptions added by
commit 68e3f5dd4d
[CRYPTO] users: Fix up scatterlist conversion errors
The issue is that the code calls sg_mark_end() which clobbers the
sg_page() pointer of the final scatterlist entry.
The first part fo the fix makes skb_to_sgvec() do __sg_mark_end().
After considering all skb_to_sgvec() call sites the most correct
solution is to call __sg_mark_end() in skb_to_sgvec() since that is
what all of the callers would end up doing anyways.
I suspect this might have fixed some problems in virtio_net which is
the sole non-crypto user of skb_to_sgvec().
Other similar sg_mark_end() cases were converted over to
__sg_mark_end() as well.
Arguably sg_mark_end() is a poorly named function because it doesn't
just "mark", it clears out the page pointer as a side effect, which is
what led to these bugs in the first place.
The one remaining plain sg_mark_end() call is in scsi_alloc_sgtable()
and arguably it could be converted to __sg_mark_end() if only so that
we can delete this confusing interface from linux/scatterlist.h
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
@@ -2028,8 +2028,8 @@ void __init skb_init(void)
|
||||
* Fill the specified scatter-gather list with mappings/pointers into a
|
||||
* region of the buffer space attached to a socket buffer.
|
||||
*/
|
||||
int
|
||||
skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
|
||||
static int
|
||||
__skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
|
||||
{
|
||||
int start = skb_headlen(skb);
|
||||
int i, copy = start - offset;
|
||||
@@ -2078,7 +2078,8 @@ skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
|
||||
if ((copy = end - offset) > 0) {
|
||||
if (copy > len)
|
||||
copy = len;
|
||||
elt += skb_to_sgvec(list, sg+elt, offset - start, copy);
|
||||
elt += __skb_to_sgvec(list, sg+elt, offset - start,
|
||||
copy);
|
||||
if ((len -= copy) == 0)
|
||||
return elt;
|
||||
offset += copy;
|
||||
@@ -2090,6 +2091,15 @@ skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
|
||||
return elt;
|
||||
}
|
||||
|
||||
int skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
|
||||
{
|
||||
int nsg = __skb_to_sgvec(skb, sg, offset, len);
|
||||
|
||||
__sg_mark_end(&sg[nsg - 1]);
|
||||
|
||||
return nsg;
|
||||
}
|
||||
|
||||
/**
|
||||
* skb_cow_data - Check that a socket buffer's data buffers are writable
|
||||
* @skb: The socket buffer to check.
|
||||
|
Reference in New Issue
Block a user