-
Notifications
You must be signed in to change notification settings - Fork 104
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 invalid hpack decoding #1874
Conversation
add4f16
to
6dfe462
Compare
6dfe462
to
1715bb1
Compare
0c66f11
to
0b640b6
Compare
bcfec45
to
76d1d7a
Compare
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.
LGTM
45dbefd
to
a090214
Compare
@@ -393,6 +393,7 @@ __split_linear_data(struct sk_buff *skb_head, struct sk_buff *skb, char *pspt, | |||
} | |||
skb->tail -= tail_len; | |||
skb->data_len += tail_len; | |||
skb->truesize += tail_len; |
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.
Please look for this place carefully! This code is necessary to prevent warning in kernel with small MTU and it makes akb truesize correct. But i don't fully understand why
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.
As I see it's correct fix. We need to adjust truesize
when we move data from linear part to paged fragments.
Lat's see on truesize
in kernel, it's consist of size of skb data + sizeof(sk_buff) + sizeof(skb_shared_info)
. It means size of reserved linear data will be included in truesize
during skb allocating. Because we don't change preallocated size of skb head when we manipulate with it, we must not change truesize
.
However, when we move data from head to paged we increase size of skb(data_len
) by adding new fragment, even if it points to already allocated data within skb. Thus, we must increment truesize
. Just for clarity, if we will realloc the skb, we can allocate less data to headroom and in this case we can not change truesize
.
a090214
to
67b232a
Compare
Continue decode hpack value same as we do it if this value was not devide between several frames.
In case when skb_room is equal to zero and we allocate a new skb, we should move some fragments from the first skb only if it contains body. Also we should allocate new skb if skb frags is equal to MAX_SKB_FRAGS, not use next skb, because next skb already contain headers!
In case when frame is not completely received and first part of frame was prossed with error we should not zero `ctx->to_read` value, since we should read the remaining part of the frame.
f975347
to
6650f76
Compare
@@ -393,6 +393,7 @@ __split_linear_data(struct sk_buff *skb_head, struct sk_buff *skb, char *pspt, | |||
} | |||
skb->tail -= tail_len; | |||
skb->data_len += tail_len; | |||
skb->truesize += tail_len; |
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.
As I see it's correct fix. We need to adjust truesize
when we move data from linear part to paged fragments.
Lat's see on truesize
in kernel, it's consist of size of skb data + sizeof(sk_buff) + sizeof(skb_shared_info)
. It means size of reserved linear data will be included in truesize
during skb allocating. Because we don't change preallocated size of skb head when we manipulate with it, we must not change truesize
.
However, when we move data from head to paged we increase size of skb(data_len
) by adding new fragment, even if it points to already allocated data within skb. Thus, we must increment truesize
. Just for clarity, if we will realloc the skb, we can allocate less data to headroom and in this case we can not change truesize
.
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.
It seems there are several issues
@@ -1311,6 +1318,7 @@ ss_skb_init_for_xmit(struct sk_buff *skb) | |||
|
|||
skb_dst_drop(skb); | |||
INIT_LIST_HEAD(&skb->tcp_tsorted_anchor); | |||
skb->tail_lock = 0; |
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.
ss_skb_init_for_xmit()
is called for all skbs being sent via ss_do_send()
, so a message, transformed splitting the linear part (and setting skb->tail_lock = 1
), might go via this code and the kernel will try to amend the tail of the linear part.
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.
Currently kernel can't work with tail_lock
. If skb passed to the kernel code with tail_lock = 1 it leads to panic.
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.
I'm not sure if I understood you correctly. We have skb_is_nonlinear()
and skb_tailroom_locked()
working with tail_lock
, which apparently must not crash. There is some bug around tail_lock
, which we need to fix, or we should fix both the function to assert BUG_ON(skb->tail_lock)
.
Does this PR close #1860? If yes, then we need at least to add this issue to #1859 and make much better explanation what's wrong with tail_lock
in the issue. I'm confused with the current state of tail_lock
in our code.
Answer:
ss_skb_init_for_xmit
is called before we pass skb to the kernel code. We can't pass skb to the kernel code with tail_lock = 1, because kernel can pass this skb to the __skb_put
and it will lead to crash.
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.
We agreed to add /* TODO #1859 #1860 ... */
comment and merge the PR.
5c0a5f8
to
5b0caf5
Compare
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.
@@ -1311,6 +1318,7 @@ ss_skb_init_for_xmit(struct sk_buff *skb) | |||
|
|||
skb_dst_drop(skb); | |||
INIT_LIST_HEAD(&skb->tcp_tsorted_anchor); | |||
skb->tail_lock = 0; |
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.
I'm not sure if I understood you correctly. We have skb_is_nonlinear()
and skb_tailroom_locked()
working with tail_lock
, which apparently must not crash. There is some bug around tail_lock
, which we need to fix, or we should fix both the function to assert BUG_ON(skb->tail_lock)
.
Does this PR close #1860? If yes, then we need at least to add this issue to #1859 and make much better explanation what's wrong with tail_lock
in the issue. I'm confused with the current state of tail_lock
in our code.
Answer:
ss_skb_init_for_xmit
is called before we pass skb to the kernel code. We can't pass skb to the kernel code with tail_lock = 1, because kernel can pass this skb to the __skb_put
and it will lead to crash.
090ea1b
to
5082e1f
Compare
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.
LGTM
@@ -1311,6 +1318,7 @@ ss_skb_init_for_xmit(struct sk_buff *skb) | |||
|
|||
skb_dst_drop(skb); | |||
INIT_LIST_HEAD(&skb->tcp_tsorted_anchor); | |||
skb->tail_lock = 0; |
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.
We agreed to add /* TODO #1859 #1860 ... */
comment and merge the PR.
We should set skb->tail_lock for the new skbs, because it could be set previously during some skb fragmentation. This field should be zero when we pass skb to the kernel code.
Previously we sent FIN to remote peer during socket closing, but didn't wait for ack to this FIN. Moreover if we could not transmit pending skbs we closed socket and lost these skbs. Now we don't drop connection until last ACK is come.
We should abort and drop all server connections, which are not closed gracefully.
After `skb_fragment` call we should upodate `skb` and `ptr` values using new values from `it`. Also improve work of `ss_skb_cutoff_data` function. If we deal with single skb we should update pointers in TfwStr only when new skb was allocated during `skb_fragment`. Closes #1864
Function `tfw_http_search_host_forwarded` worked incorrectly with TCP segmentation. We can't compare chunk by chunk with "host=", because "host=" can be separated between several chunks.
Before http request trailer headers check, we have to make sure that requerst is fully parsed.
- Change `offset` size to 16 bit and move it before `index` field. - Change `index` size to 32 bit because it is enough and it is better to struct layout. - Remove checking that forwarded host and header host is equal.
- Copy `__extract_request_authority` function to unit tests and use to set req->host value in appropriate tests as we do it in tempesta. - Fix unit tests according to changes in `match_host` function.
Moving body logic extracted to function and do it only if we have the body. Pointer to body never be NULL more safer not use it wthout check the body length.
69236c0
to
2417cda
Compare
Continue decode hpack value same as we do it
if this value was not devide between several
frames.