diff options
author | Doron Roberts-Kedes <doronrk@fb.com> | 2018-04-11 18:05:16 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-04-12 21:54:59 -0400 |
commit | 9d0c75bf6e03d9bf80c55b0f677dc9b982958fd5 (patch) | |
tree | bb0a065e70bb7331987e4759f216ba24db4949a0 /net/strparser/strparser.c | |
parent | 5ff9c1a3dd92d2d8eeea6bb15b3502cfcc0e26fa (diff) |
strparser: Fix incorrect strp->need_bytes value.
strp_data_ready resets strp->need_bytes to 0 if strp_peek_len indicates
that the remainder of the message has been received. However,
do_strp_work does not reset strp->need_bytes to 0. If do_strp_work
completes a partial message, the value of strp->need_bytes will continue
to reflect the needed bytes of the previous message, causing
future invocations of strp_data_ready to return early if
strp->need_bytes is less than strp_peek_len. Resetting strp->need_bytes
to 0 in __strp_recv on handing a full message to the upper layer solves
this problem.
__strp_recv also calculates strp->need_bytes using stm->accum_len before
stm->accum_len has been incremented by cand_len. This can cause
strp->need_bytes to be equal to the full length of the message instead
of the full length minus the accumulated length. This, in turn, causes
strp_data_ready to return early, even when there is sufficient data to
complete the partial message. Incrementing stm->accum_len before using
it to calculate strp->need_bytes solves this problem.
Found while testing net/tls_sw recv path.
Fixes: 43a0c6751a322847 ("strparser: Stream parser for messages")
Signed-off-by: Doron Roberts-Kedes <doronrk@fb.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/strparser/strparser.c')
-rw-r--r-- | net/strparser/strparser.c | 7 |
1 files changed, 3 insertions, 4 deletions
diff --git a/net/strparser/strparser.c b/net/strparser/strparser.c index b9283ce5cd85..805b139756db 100644 --- a/net/strparser/strparser.c +++ b/net/strparser/strparser.c | |||
@@ -296,9 +296,9 @@ static int __strp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb, | |||
296 | strp_start_timer(strp, timeo); | 296 | strp_start_timer(strp, timeo); |
297 | } | 297 | } |
298 | 298 | ||
299 | stm->accum_len += cand_len; | ||
299 | strp->need_bytes = stm->strp.full_len - | 300 | strp->need_bytes = stm->strp.full_len - |
300 | stm->accum_len; | 301 | stm->accum_len; |
301 | stm->accum_len += cand_len; | ||
302 | stm->early_eaten = cand_len; | 302 | stm->early_eaten = cand_len; |
303 | STRP_STATS_ADD(strp->stats.bytes, cand_len); | 303 | STRP_STATS_ADD(strp->stats.bytes, cand_len); |
304 | desc->count = 0; /* Stop reading socket */ | 304 | desc->count = 0; /* Stop reading socket */ |
@@ -321,6 +321,7 @@ static int __strp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb, | |||
321 | /* Hurray, we have a new message! */ | 321 | /* Hurray, we have a new message! */ |
322 | cancel_delayed_work(&strp->msg_timer_work); | 322 | cancel_delayed_work(&strp->msg_timer_work); |
323 | strp->skb_head = NULL; | 323 | strp->skb_head = NULL; |
324 | strp->need_bytes = 0; | ||
324 | STRP_STATS_INCR(strp->stats.msgs); | 325 | STRP_STATS_INCR(strp->stats.msgs); |
325 | 326 | ||
326 | /* Give skb to upper layer */ | 327 | /* Give skb to upper layer */ |
@@ -410,9 +411,7 @@ void strp_data_ready(struct strparser *strp) | |||
410 | return; | 411 | return; |
411 | 412 | ||
412 | if (strp->need_bytes) { | 413 | if (strp->need_bytes) { |
413 | if (strp_peek_len(strp) >= strp->need_bytes) | 414 | if (strp_peek_len(strp) < strp->need_bytes) |
414 | strp->need_bytes = 0; | ||
415 | else | ||
416 | return; | 415 | return; |
417 | } | 416 | } |
418 | 417 | ||