-
Notifications
You must be signed in to change notification settings - Fork 103
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix #1147 : init frag variable before use. #1162
Changes from all commits
516509c
3ed0fd9
f763b9d
3b930c1
dc9558f
96b8933
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -34,20 +34,22 @@ | |||||||
int | ||||||||
tfw_msg_write(TfwMsgIter *it, const TfwStr *data) | ||||||||
{ | ||||||||
char *p; | ||||||||
const TfwStr *c, *end; | ||||||||
skb_frag_t *frag; | ||||||||
unsigned int c_off = 0, f_size, c_size, f_room, n_copy; | ||||||||
|
||||||||
BUG_ON(TFW_STR_DUP(data)); | ||||||||
if (WARN_ON_ONCE(it->frag >= skb_shinfo(it->skb)->nr_frags)) | ||||||||
return -E2BIG; | ||||||||
|
||||||||
TFW_STR_FOR_EACH_CHUNK(c, data, end) { | ||||||||
char *p; | ||||||||
unsigned int c_off = 0, c_size, f_room, n_copy; | ||||||||
this_chunk: | ||||||||
if (!frag) | ||||||||
return -E2BIG; | ||||||||
|
||||||||
c_size = c->len - c_off; | ||||||||
if (it->frag >= 0) { | ||||||||
frag = &skb_shinfo(it->skb)->frags[it->frag]; | ||||||||
unsigned int f_size; | ||||||||
skb_frag_t *frag = &skb_shinfo(it->skb)->frags[it->frag]; | ||||||||
|
||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems that there is a problem with using skb header when allocating more than one skb - in Line 174 in 5631d72
but in tfw_msg_write() only the header of the first skb in list is used (it->frag < 0 ):Line 59 in 5631d72
for subsequent skb it-> frag is always initialized to zero:Line 132 in 5631d72
so then we always fall into the it->frag >= 0 branch.Looks like the current master version of tfw_msg_write() has the same issue.
|
||||||||
f_size = skb_frag_size(frag); | ||||||||
f_room = PAGE_SIZE - frag->page_offset - f_size; | ||||||||
p = (char *)skb_frag_address(frag) + f_size; | ||||||||
|
@@ -62,24 +64,26 @@ tfw_msg_write(TfwMsgIter *it, const TfwStr *data) | |||||||
|
||||||||
memcpy_fast(p, c->data + c_off, n_copy); | ||||||||
|
||||||||
if (c_size < f_room) { | ||||||||
/* | ||||||||
* The chunk fits in the SKB fragment with room | ||||||||
* to spare. Stay in the same SKB fragment, switch | ||||||||
* to next chunk of the string. | ||||||||
*/ | ||||||||
c_off = 0; | ||||||||
} else { | ||||||||
frag = ss_skb_frag_next(&it->skb, it->skb_head, | ||||||||
&it->frag); | ||||||||
/* | ||||||||
* The chunk occupied all the spare space in the SKB fragment, | ||||||||
* switch to the next fragment. | ||||||||
*/ | ||||||||
if (c_size >= f_room) { | ||||||||
skb_frag_t *frag = ss_skb_frag_next(&it->skb, | ||||||||
it->skb_head, | ||||||||
&it->frag); | ||||||||
if (WARN_ON_ONCE(!frag | ||||||||
&& ((c_size != f_room) | ||||||||
|| (c + 1 < end)))) | ||||||||
{ | ||||||||
return -E2BIG; | ||||||||
} | ||||||||
/* | ||||||||
* If all data from the chunk has been copied, | ||||||||
* then switch to the next chunk. Otherwise, | ||||||||
* stay in the current chunk. | ||||||||
* Not all data from the chunk has been copied, | ||||||||
* stay in the current chunk and copy the rest to the | ||||||||
* next fragment. | ||||||||
*/ | ||||||||
if (c_size == f_room) { | ||||||||
c_off = 0; | ||||||||
} else { | ||||||||
if (c_size != f_room) { | ||||||||
c_off += n_copy; | ||||||||
goto this_chunk; | ||||||||
} | ||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In case of
*skb == skb_head
inss_skb_frag_next()
we get hereskb_head == it->skb
and0 == it->frag
; so, conditionit->frag >= skb_shinfo(it->skb)->nr_frags)
probably will be false here and we continue execute all the followingtfw_msg_write()
calls without warnings.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The scenario you've described may happen on subsequent
tfw_msg_write()
calls, which is very common case. So yes, the condition will false and we will continue to execute the function. But*skb == skb_head
really means that we run out of the spare place in the skb fragments, and no more data can be pushed there. So if we continue to execute the function, we will walk through all the fragments once again and return-E2BIG
error.So there is no errors and the function can be called multiple times without any worries. The
tfw_msg_write()
function is used only for preallocated skbs, and data size is known before skb allocations, thusdata
should perfectly fit theit
.The reason for
WARN_ON
is invalidit
state, where isit->frag
points to nonexistent fragment.