This is an interesting PR, and likely accomplishes the goals at the moment.
I do really like how we’ve kept some bidirectionally of the approach and the 
padding can stay as is. 

Just thinking things through a little bit: 
(This is all discussed below by Ian/Magnus/Martin/Kazuho, and others, just 
restating so we have it in one place)

At any point, either endpoint can choose to send a PATH_CHALLENGE.
The presence of a PATH_CHALLENGE always evokes a PATH_RESPONSE.

Therefore, we assume that in order to restrict folks from being able to spoof a 
source address when sending a PATH_CHALLENGE and attack the real owner of that 
source address with the PATH_RESPONSE, we need to make the PATH_CHALLENGE very 
large as well. 

However, there’s another situation where PATH_CHALLENGE is sent, and that's 
whenever we receive a non-probing packet that arrives on a new path without any 
prior validation, and we send that PATH_CHALLENGE on both the old and the new 
path.

This is where we haven’t fully plugged the amplification hole, since an 
attacker can use any other, smaller datagram to cause the other endpoint to 
generate full-size datagrams containing PATH_CHALLENGE. This wasn’t previously 
a huge issue since PATH_CHALLENGE wasn’t meaningfully larger than the smallest 
packet you’d otherwise be able to send (slash the per-packet costs were 
potentially higher than the cost of the data inside that packet).

——— 

One other approach we could take here would be to restrict ourselves to only 
covering the cases where you’re actively generating a PATH_CHALLENGE to 
validate a new path, not responding to a new non-probing packet on an 
unvalidated path. 

In other words: 
Only the client needs to pad PATH_CHALLENGE and any response to a padded 
PATH_CHALLENGE should also be padded. That also fits nicely into the 
unidirectionality of path validation as it stands today.


The other option that we haven’t discussed much is if we’d rather live with the 
previous pre-padding problem and remove the padding. 
My initial inclination was to avoid this, but actually we’d be returning to a 
state where the main risk was that the path wasn’t MTU compatible and any 
implementation migrating is likely already dealing with cases where packets 
aren’t going through on a path in at least one direction. So, the natural 
responses to path validation failures (for MTU reasons or otherwise), if you 
map them all out, generally result in the “correct” behavior. We could then say 
“any endpoint using a new path is encouraged to do PMTUD or otherwise be 
careful that the path may not work in at least one direction” and leave it at 
that.

——— 

Overall, I suspect we’re probably headed in the right direction by making the 
3x limit more universal, although it does seem like it introduces some really 
interesting cases to code around, and that limit and double path validation 
might be more painful than just checking for “am I client, therefore I should 
pad” which is annoying because it has a client/server distinction but does 
likely cause less churn and risk for later fallout.

Thanks,
Eric


> On Oct 27, 2020, at 7:41 PM, Martin Thomson <[email protected]> wrote:
> 
> Thanks to everyone for the feedback.
> 
> I've written up a draft pull request here: 
> https://github.com/quicwg/base-drafts/pull/4264
> 
> This does something like what Magnus suggests below.  It's not pretty, 
> because in some very common cases path validation could take twice as long, 
> and it's more complicated, but I think that it is at least principled.
> 
> On Wed, Oct 28, 2020, at 04:04, Magnus Westerlund wrote:
>> On Tue, 2020-10-27 at 09:12 -0400, Ian Swett wrote:
>>> Thanks for summarizing this issue. I think the above discussion is about
>>> immediate migration and repeated immediate migrations, but I also wonder if
>>> we've introduced a single packet amplification attack by requiring
>>> PATH_RESPONSEs be padded on new paths without a requirement on the size of
>>> PATH_CHALLENGE(see first item)?
>>> 
>>> Validating a new path
>>> If one receives only a PATH_CHALLENGE on a new path, then the server
>>> responds with a full-sized PATH_RESPONSE.  This seems safe.  If a non-padded
>>> PATH_CHALLENGE is received on a new path, then the peer is supposed to send 
>>> a
>>> fully padded PATH_RESPONSE on the path, which could be >20x larger.  I'm not
>>> sure if we care about this, but I wanted to point it out. 
>>> 
>>> Immediately migrating to a new path
>>> I think we should remove the text about allowing kMinimumWindow each
>>> kInitialRtt after migration and change it to the 3x limit.  I'm actually
>>> surprised the text about 2*kInitialWindow still exists, since recovery says
>>> "Until the server has validated the client's address on the path, the amount
>>> of data it can send is limited to three times the amount of data received, 
>>> as
>>> specified in Section 8.1 of {{QUIC-TRANSPORT}}.".
>>> 
>>> In order to not get deadlocked by the 3x factor, I think we should change 
>>> the
>>> newly added MUSTs to only apply to path validation prior to migration, not 
>>> the
>>> peer responding to migration.
>>> 
>>> My reasoning is that if a peer migrates prior to validating the path, it 
>>> means
>>> it's either unintentional or they have no other choice, so the migrating 
>>> peer
>>> has implicitly decided that validating PathMTU is not a prerequisite to
>>> migrating.
>> 
>> So some quesitons and ideas as I think it is relevant to resolve this as 
>> best as
>> possible.
>> 
>> So isn't this recreating the issue that if the client initiates a migration 
>> to a
>> new path that is not QUIC compatible, by responding with a minimal size 
>> packet
>> and completing the migration and then if the server performs the path
>> verification with 1200 bytes UDP payload it fails. Thus maintaining a broken
>> path. 
>> 
>> So is there need for the non pre-validated path migration case that one need
>> need to do a two step process where one will ACK with minimal packet while
>> initiating path validation. If path validatation fails then maybe one need to
>> close down the connection as the migration ended up on a path that was 
>> unable to
>> support QUIC. The question here is how to avoid the DoS attack this may open 
>> up
>> if an attack rewrites source address of packets. 
>> 
>> So Maybe the path validation needs to be a two step process. First a return
>> routability over the new path to verify that it is bi-directional. When that 
>> has
>> been verified one does a test with minimal MTU to prove it to be QUIC
>> compatible. This might even be done with application data if there is some 
>> that
>> are available to send. 
>> 
>> But, I think that one needs to work through the criterias for when the QUIC
>> connection is shut down under the conditions that the path available is not
>> supporting 1200 bytes. Also do we end up in a situation where the client 
>> needs
>> to do the second step itself towards the server to verify the path so that it
>> can determine if it needs to try another path if this one doesn't work? 
>> 
>> Cheers
>> 
>> Magnus
>> 
>> 
>> Attachments:
>> * smime.p7s
> 

Reply via email to