Subject: Re: [tsvwg] UDP options list of issues

From: Joe Touch <[email-masked]>
Date: Thu, 24 May 2018 11:43:47 -0700

Hi, all, 

I didn't see any comments on the following - it would be useful to hear
from anyone on the list regarding the issues below so we can run a rev
on the doc and pin these things down. 

So far I've heard from only two parties - I'd appreciate both them and
anyone else providing a very brief list of positions on these... 

Thanks,
Joe

On 2018-03-04 14:39, Joe Touch wrote:

> Hi, all, 
> 
> IMO, we would benefit popping up a level to the list of issues and summarizing our views. 
> 
> Here's my attempt to do that. 
> 
> Joe 
> 
> ------ 
> 
> Some assumptions: 
> a) overhead is useful to minimize (efficiency and may reduce or avoid fragmentation) 
> b) LITE capability must be preserved 
> c) LITE+FRAG capability must be preserved 
> d) this solution is not expected to outperform TCP (i.e., this is not an opportunity to redesign transport from scratch) 
> 
> - TLV vs fixed header 
> motivated (AFAICT) by the desire to enable hardware optimization and/or to detect error/misuses of spare area 
> no clear hardware benefit (given the option area "floats" relative to the UDP header,  
> which floats relative to the IPv6 header TLV chain, and given it may not be word aligned) 
> no clear benefit regarding packet errors or other spare area uses  
> (both require either CS works or TLV chain parses, neither of which is likely for random errors or other misuses) 
> fixed wastes at least 2 bytes if CS isn't used, (maybe 4-6 if supporting LITE/LITE+FRAG) 
> 
> - Optional CS vs. mandatory 
> motivated (AFAICT) by the desire to avoid processing packets with errors (accidental or by others misusing the extra space) 
> optional is needed to correlate to lack of UDP checksum (for some types of tunnels, e.g.) 
> mandatory also implies fixed (above), which incurs 2-6 bytes of overhead 
> 
> - option-area checksum details 
> size 
> 8 if TLV, 16 if fixed; no clear problem with either choice 
> algorithm 
> no clear issue with using minor mods (foldover for 8 bit, invert or not) 
> there are known dangers to using the complement of the sum  
> (such that the sum and data zero-out), as noted by the Partridge paper in the 90s. 
> 
> - EOL vs option length field 
> length would have to be 2 bytes; EOL is an optional one byte (not needed if no spare area remains) 
> EOL thus saves up to 2 bytes when not needed (and it should generally not be needed at all) 
> allowing EOL (i.e., allowing remaining unused spare area) implies that processing needs to stop at some point,  
> either based on a counter or the data seen (and given that a CS loads data into a register anyway, there's no clear performance win to either approach) 
> EOL itself is patterned after the TCP option of the same name 
> and yes, leaving the spare area available for future use by other protocol extensions is intended here 
> 
> - does CS end when EOL is seen? 
> yes, as currently specified 
> as noted above, leaving the spare are for future standards is a goal 
> 
> My conclusion is that all the choices above either fail to improve the situation vs. our current proposal or increase overhead (or both). I don't yet see a reason why any of them warrant a change vs. the existing approach.

---

From: Tom Herbert <[email-masked]>
Date: Thu, 24 May 2018 12:52:31 -0700

On Thu, May 24, 2018 at 11:43 AM, Joe Touch <[email-masked]> wrote:
> Hi, all,
>
> I didn't see any comments on the following - it would be useful to hear from
> anyone on the list regarding the issues below so we can run a rev on the doc
> and pin these things down.
>
Joe,

One of the problems with TLVs in a datapath protocol is that they can
too easily be used for DOS attack. This is especially true in the case
that unkown TLV types are be ignored by a receiver and there is no
reasonable protocol limit to the number of TLVs can be put into a
packet. Both of these conditions seem to be true for the UDP options.
The attack is simple, just fill up a packet with tiny TLVs with
unknown types to the receiver.

A mitigation is described in the draft:

 ">> Required options MUST come before other options. Each required
option MUST NOT occur more than once (if they are repeated in a
received segment, all except the first MUST be silently ignored)."

and

"Implementations concerned with the potential for this vulnerability
MAY implement only the required options"

The first question I have to this is what are "required options". I
don't see where this is defined. Also, required is ambiguous. I assume
the intent is that these are options that a receiver is required to
implement-- but that could have other meanings, like options that a
sender is required to send. This needs to be clarified. Also, if
required options must appear first then that raises another question:
what happens if a packet is received where required options follow
non-required options. How does the receiver deal with this?

I'll assume for sake of argument that the options specified in the
draft are required options in that sense that a receiver must
understand these. So then my next question is how can any new required
options be added. Say that type 9 is defined as new security option
that is considered a required option. How will deployed devices know
that this is a required option (as opposed to one that isn't required
and can be ignored)? Seems like the proper  way to deal with would be
to steal a bit from the type field that indicates the receive behavior
if the type in unknown-- either ignore TLV or drop packet. This is
similar to high order two bits of IPv6 option types (an option to send
an ICMP error might also be useful here).

But, even if the required options are handled, DOS is still a problem
if an implementation wants to process even one non required option. In
that case it always needs to parse all the TLVs (i.e. it doesn't know
where in the TLV list the option is that it's looking for). So this
presents the implementor with an unpleasant tradeoff, implementing any
non-required options may mean allowing exposure to DOS attack.

BTW, this DOS attack issue comes up in other context. For DO and HBH
options we added text to draft-ietf-6man-rfc6434-bis-08 that allows
configurable limits on number of options (regardless of whether the
options are "required"). If the limit is exceeded the packet is
dropped. In Linux the default is to allow up to eight options, that's
approximately based on the number of implemented options plus five.

Tom

> ———
> d) this solution is not expected to outperform TCP (i.e., this is not an
> opportunity to redesign transport from scratch)
>
> - TLV vs fixed header
> (both require either CS works or TLV chain parses, neither of which is
> likely for random errors or other misuses)
> motivated (AFAICT) by the desire to avoid processing packets with errors
> (accidental or by others misusing the extra space)
> either based on a counter or the data seen (and given that a CS loads data
> into a register anyway, there's no clear performance win to either approach)
> My conclusion is that all the choices above either fail to improve the
> situation vs. our current proposal or increase overhead (or both). I don't
> yet see a reason why any of them warrant a change vs. the existing approach.
>

---

From: Joe Touch <[email-masked]>
Date: Thu, 24 May 2018 14:08:47 -0700

Tom, 

We've had the TLV discussion on other lists. 

What I'm wondering here is why UDP options would need to be different
than TCP options - which are TLV exactly to allow the flexibility of
future evolution that have enabled quite a few TCP features beyond the
fixed header. 

It would be useful to hear from others on this point as well. 

Some clarifications: 

- required options are those with a star (*) in sec 5; we can adjust
that list prior to final publication vs. the ones currently indicated 

- "required' means 'required to implement' only; all options are
optional to use in general (they may be expected on a given association,
but that doesn't mandate order)

Joe

---

From: Tom Herbert <[email-masked]>
Date: Thu, 24 May 2018 14:49:59 -0700

On Thu, May 24, 2018 at 2:08 PM, Joe Touch <[email-masked]> wrote:
> What I'm wondering here is why UDP options would need to be different than
> TCP options - which are TLV exactly to allow the flexibility of future
> evolution that have enabled quite a few TCP features beyond the fixed
> header.

They are different because: 1) TCP options are limited to forty bytes
in length 2) TCP options are negotiated 3) For a non-SYN packet,
options are only processed after the TCP connection is matched. In
other words, there is no way to send unsolicited TCP packets with long
lists of TLVs to DOS a receiver (even if EDO were in use). UDP options
are much more like IPv6 DO and HBH options in this regard.

> - required options are those with a star (*) in sec 5; we can adjust that
> list prior to final publication vs. the ones currently indicated
>
I see, these were not explicitly called out to be required options.
Probably need some more text about this. Also, does this mean that the
three options marked as required (or whatever others are added to the
required list before publication) are the only ones that will ever be
required in UDP options (see my point about problem in adding new
required options).

I am a little suprised that ACS isn't required. This means that a
sender may go though all of the work to create the checksum, but a
receiver can simply ignore it. That behavior is not typical of
checksums in IP protocols. Usually, the sender controls whether
checksum is set and receivers only accept packets with the checksum
present if it has been verified (like how UDP checksum is optional by
sender to set, but not optional for receiver to ignore if it's
non-zero, RFC1122).

> - "required' means 'required to implement' only; all options are optional to
> use in general (they may be expected on a given association, but that
> doesn't mandate order)

I think you mean required to be implemented and be recognized by a
receiver. Please clarify this in the next draft.

Tom

---

From: Mitchell Erblich <[email-masked]>
Date: Thu, 24 May 2018 19:59:44 -0700

A  possible DoS mitigation due to TLV processing, could be added with wording such as:

			Any receiver/intermediate system processing a packet with multiple TLVs SHOULD have the option to drop the packet and/or quietly and/or respond with a packet processing time exceeded error or packet exceeded the maximum number of unknown count of TLVs if the processing of the packet exceeds a TLV processing time or the number of unknown TLVs exceeds a maximum count.

			Any receiver/intermediate system should keep a count of discarded packets and if the count exceeds a maximum local value, be able to make decisions to black hole or make some other decision against the packet’s believed source.

Mitchell Erblich
[email-masked]

> On May 24, 2018, at 2:08 PM, Joe Touch <[email-masked]> wrote:
> 
> Tom,
> 
> What I'm wondering here is why UDP options would need to be different than TCP options - which are TLV exactly to allow the flexibility of future evolution that have enabled quite a few TCP features beyond the fixed header.
> 
> - required options are those with a star (*) in sec 5; we can adjust that list prior to final publication vs. the ones currently indicated
> 
> - "required' means 'required to implement' only; all options are optional to use in general (they may be expected on a given association, but that doesn't mandate order)
> 
>  
> Joe
>

---

From: Joe Touch <[email-masked]>
Date: Thu, 24 May 2018 22:35:07 -0700

On 2018-05-24 14:49, Tom Herbert wrote:

> in length 2) TCP options are negotiated

These effectively are as well - although with soft state only. 

> 3) For a non-SYN packet,
> options are only processed after the TCP connection is matched.

That's roughly true here as well - due to the soft state property. The
state isn't due to a handshake, but packets arriving at a host not
listening to a port would not need to have their options processed
either. 

> In

Perhaps, but a host can easily just decide not to process options
sequences that are too long - just as they can do so to SYN floods. 

> required in UDP options (see my point about problem in adding new

They're the same as the only ones required for TCP - they MUST be
implemented, which means both that transmitters MUST be able to send
them and receivers MUST be able to interpret them. 

> receiver can simply ignore it.

True - and it's up to the sender to decide to cease further transmission
if desired. 

> That behavior is not typical of
> checksums in IP protocols.

It's exactly the behavior of *alternate* checksums, which are all
optional. 

> Usually, the sender controls whether

That wouldn't be true for any of the alternate checksums in TCP. 

> receiver. Please clarify this in the next draft.

And for the sender to transmit these. 

The list right now is based on the current minimum required set for TCP.
If there's a clear case for making any of the others required, we can
include them too - I'm hoping the set can be kept small enough not to be
a burden for IoT devices. 

Joe

---

From: Gorry Fairhurst <[email-masked]>
Date: Fri, 25 May 2018 08:50:04 +0100

I'd encourage some thought on TLV processing and DOS vulnerabilities as 
a separate security considerations subsection. I'd suggest this topic 
appears enough in transport design to justify a separate heading to 
assure readers of the safety of the approach.

Since UDP provides a datagram service, the app (or the stack/path) can 
silently discard any data. I think this means we can think a little 
about how this should best now be handled.

Is it the case that option and the datagram payload share the same fate?
i.e. if the option part is not processed - then the datagram payload is 
not forwarded to the App?
- This could simplify any probing by an endpoint to understand if an 
option is supported and will also avoid unexpected behaviours when any 
DDOS mechanism kicks-in and starts not processing options. If the API 
discards the entire datagram, it then behaves just as any IP-level 
policer would.
- I also think it may perhaps be OK to separately log these discards 
(where rate-limiting permits), counting them as received at the 
transport but not forwarded to the App. I was assuming from what is 
written below that the decision about how to respond would be at the 
application level, or do you think the stack would have enough 
information to implement this sort of function?

Gorry

On 25/05/2018, 03:59, Mitchell Erblich wrote:
>> On May 24, 2018, at 2:08 PM, Joe Touch<[email-masked]>  wrote:
>>
>> Tom,
>>
>>> On Thu, May 24, 2018 at 11:43 AM, Joe Touch<[email-masked]>  wrote:
>>>> Hi, all,
>>>>

---

From: Tom Herbert <[email-masked]>
Date: Fri, 25 May 2018 07:49:04 -0700

On Thu, May 24, 2018 at 10:35 PM, Joe Touch <[email-masked]> wrote:
> That's roughly true here as well - due to the soft state property. The state
> isn't due to a handshake, but packets arriving at a host not listening to a
> port would not need to have their options processed either.
>
>
>
> In
> Perhaps, but a host can easily just decide not to process options sequences
> that are too long - just as they can do so to SYN floods.
>
>
>
>
> implemented, which means both that transmitters MUST be able to send them
> and receivers MUST be able to interpret them.
>
>
> True - and it's up to the sender to decide to cease further transmission if
> desired.
>
>
> It's exactly the behavior of *alternate* checksums, which are all optional.
>
>
> The list right now is based on the current minimum required set for TCP. If
> there's a clear case for making any of the others required, we can include
> them too - I'm hoping the set can be kept small enough not to be a burden
> for IoT devices.
>
Joe,

Checksum is not optional in TCP, it is a field in the fixed TCP
header. The TCP checksum must always be set by the sender and
validated by the receiver. This advantages of a required checksum are
major reason why I still think there should be a fixed header
preceeding the UDP options list. The header would contain a one byte
slack space type, a one byte length, two byte one's complement
checksum of the header and option list (coverage inidicated by
length). Such a header allows other uses of the slack space,
substantially decreases the probability of misinterpretation of random
bits in the slack space as being UDP options (checksum, type, and
length need to be correct), solves the the checksum type being
corrupted problem, and eliminates the need for EOL option. Please
consider adding this header.

Tom

---

From: Joe Touch <[email-masked]>
Date: Fri, 25 May 2018 09:10:33 -0700

Hi, Tom, 

I think you're confusing ACS with OCS; ACS is the alternate checksum on
the body.

You've made your views on OCS clear; it would be useful to hear from
others. 

Also, note that even if OCS were mandatory: 

a) it probably cannot come before LITE 

b) there's no need to include a length field with OCS per se; further, a
one-byte length puts us back on the path where TCP ended up (of limiting
option space). IF we include that, it would need to be two bytes 

Joe

---

From: Tom Herbert <[email-masked]>
Date: Fri, 25 May 2018 09:18:41 -0700

> option space). IF we include that, it would need to be two bytes

A one byte length field would allow 256 bytes of options, same as IPv6 DO
and HBH. That's already almost 20% of normal Ethernet MTU, I'm very
doubtful there would ever be a practical use for more bytes in options
(except for DOS!).

Tom

Joe
> from
> EOL thus saves up to 2 bytes when not needed (and it should generally not
> be
> needed at all)

---

From: Joe Touch <[email-masked]>
Date: Fri, 25 May 2018 09:27:35 -0700

On 2018-05-25 09:18, Tom Herbert wrote:

>> I think you're confusing ACS with OCS; ACS is the alternate checksum on the body. 
>> 
>> You've made your views on OCS clear; it would be useful to hear from others. 
>> 
>> b) there's no need to include a length field with OCS per se; further, a one-byte length puts us back on the path where TCP ended up (of limiting option space). IF we include that, it would need to be two bytes
> 
> A one byte length field would allow 256 bytes of options, same as IPv6 DO and HBH. That's already almost 20% of normal Ethernet MTU, I'm very doubtful there would ever be a practical use for more bytes in options (except for DOS!).

At the transport layer, the "option" space could be used for any number
of things - I'd also have to check how it interacts with FRAGs as well.
I don't think it is useful to make this assumption at this time. 

Joe

---

From: Joe Touch <[email-masked]>
Date: Fri, 25 May 2018 09:31:55 -0700

HI, Gorry, 

On 2018-05-25 00:50, Gorry Fairhurst wrote: 

>> I'd encourage some thought on TLV processing and DOS vulnerabilities as a separate security considerations subsection. I'd suggest this topic appears enough in transport design to justify a separate heading to assure readers of the safety of the approach.

While I agree some text would be useful, I don't think this protocol
needs to fight that battle in total. 

>> Since UDP provides a datagram service, the app (or the stack/path) can silently discard any data. I think this means we can think a little about how this should best now be handled.
>> 
>> i.e. if the option part is not processed - then the datagram payload is not forwarded to the App?

It depends on the receiver's capability; for legacy receivers, yes - it
would be forwarded. 

For option-capable receivers, that's a configuration parameter for the
socket. 

>> - This could simplify any probing by an endpoint to understand if an option is supported and will also avoid unexpected behaviours when any DDOS mechanism kicks-in and starts not processing options. If the API discards the entire datagram, it then behaves just as any IP-level policer would.

I don't think we should encourage dropping packets with unknown options
until soft state has been established, because that undermines the
deployment of new capabilities. But after that, sure. 

This does argue for an expanded discussion of the issue of soft state,
though. 

>> - I also think it may perhaps be OK to separately log these discards (where rate-limiting permits), counting them as received at the transport but not forwarded to the App.

It's not clear that's useful after soft-state is established.  

>> I was assuming from what is written below that the decision about how to respond would be at the application level, or do you think the stack would have enough information to implement this sort of function?

The stack should, but if the count is high then at best it should alert
the app. Any other behavior should be out of scope for this doc to
specify - because a burst of such packets can occur legitimately (UDP is
not rate-controlled or stateful), so it is inappropriate to infer an
attack. 

>From another discussion, my corollary to the Postal Principle is: 

     on sending, do not IMPLY 
     on receiving, do not INFER 

Joe

---

From: Tom Herbert <[email-masked]>
Date: Fri, 25 May 2018 09:35:07 -0700

On Fri, May 25, 2018, 9:32 AM Joe Touch <[email-masked]> wrote:

> I'd encourage some thought on TLV processing and DOS vulnerabilities as a
> separate security considerations subsection. I'd suggest this topic appears
> enough in transport design to justify a separate heading to assure readers
> of the safety of the approach.
>
>
> While I agree some text would be useful, I don't think this protocol needs
> to fight that battle in total.
>
>
> silently discard any data. I think this means we can think a little about
> how this should best now be handled.
>
> option is supported and will also avoid unexpected behaviours when any DDOS
> mechanism kicks-in and starts not processing options. If the API discards
> the entire datagram, it then behaves just as any IP-level policer would.
>
>

The draft mentions that UDP options should be negotiated. Is a protocol
going to be specified for that?

Tom

> (where rate-limiting permits), counting them as received at the transport
> but not forwarded to the App.
>
>
> I was assuming from what is written below that the decision about how to
> respond would be at the application level, or do you think the stack would
> have enough information to implement this sort of function?
>
>
> the app. Any other behavior should be out of scope for this doc to specify
> - because a burst of such packets can occur legitimately (UDP is not
> rate-controlled or stateful), so it is inappropriate to infer an attack.
>

---

From: Joe Touch <[email-masked]>
Date: Fri, 25 May 2018 12:46:19 -0700

On 2018-05-25 09:35, Tom Herbert wrote:

>> This does argue for an expanded discussion of the issue of soft state, though....
> 
> The draft mentions that UDP options should be negotiated. Is a protocol going to be specified for that? 
> 
> Tom

Sort of. We're not adding a full handshake with state to the header, but
there is a notion that it might be useful to stop sending options that
are never received back... 

Yes, that needs to be explained a little better, but the idea is closer
to a probe than a handshake. 

Joe

---

From: Gorry Fairhurst <[email-masked]>
Date: Sat, 26 May 2018 08:40:09 +0100

On 25/05/2018, 17:31, Joe Touch wrote:
>>> I'd encourage some thought on TLV processing and DOS vulnerabilities 
>>> as a separate security considerations subsection. I'd suggest this 
>>> topic appears enough in transport design to justify a separate 
>>> heading to assure readers of the safety of the approach.
>>> Since UDP provides a datagram service, the app (or the stack/path) 
>>> can silently discard any data. I think this means we can think a 
>>> little about how this should best now be handled.
>>>
> It depends on the receiver's capability; for legacy receivers, yes - 
> it would be forwarded.
>>> option is supported and will also avoid unexpected behaviours when 
>>> any DDOS mechanism kicks-in and starts not processing options. If 
>>> the API discards the entire datagram, it then behaves just as any 
>>> IP-level policer would.
> I don't think we should encourage dropping packets with unknown 
> options until soft state has been established, because that undermines 
> the deployment of new capabilities. But after that, sure.
>>> transport but not forwarded to the App.
>>> I was assuming from what is written below that the decision about 
>>> how to respond would be at the application level, or do you think 
>>> the stack would have enough information to implement this sort of 
>>> function?
> The stack should, but if the count is high then at best it should 
> alert the app. Any other behavior should be out of scope for this doc 
> to specify - because a burst of such packets can occur legitimately 
> (UDP is not rate-controlled or stateful), so it is inappropriate to 
> infer an attack.

I'm really not so sure about adding these options and configuration 
possibilities to the draft. In some ways, I can see merit in clearly 
defining the main mechanism and perhaps even being silent on possible 
socket options.

I'm intrigued how soft-state helps with path changes, but I think 
additional security considerations text would help.

I think you've argued enough for me to want me to see text on the DoS case.

Gorry

---

From: Derek Fawcus <[email-masked]>
Date: Wed, 30 May 2018 00:45:07 +0100

> a) it probably cannot come before LITE 

I believe it can when we were only discussing swapping bytes,
and that I mentioned how previously.  (I've forgotten what that
means was, so would have to reread what I wrote before).

I've not reconsidered this for the case recently mentioned cases
where we may end up sliding bytes.

DF

---

From: Joe Touch <[email-masked]>
Date: Tue, 29 May 2018 21:47:51 -0700

> On May 29, 2018, at 4:45 PM, Derek Fawcus <[email-masked]> wrote:
> 

The current approach:
	- swaps/slides 4 bytes if LITE is present
	- allows OCS and the rest of the checksum computation to be word aligned (by prefixing NOPs)
	- after processing LITE, we process options as they come until we hit OCS (if we hit OCS), 
	at which point OCS checksum is computed from the beginning of the options (incl. the LITE header)

If OCS comes before LITE
	- it would be more complex to allow OCS word alignment 
		- we would have to move a variable number of 0-3 NOPs and OCS in addition to LITE
		- processing would need to read OCS and not start the checksum until it checks for LITE (because it would be misaligned if so)
			if LITE is present, process the swap/slide
		- start processing OCS including LITE, but do not act on LITE this time
	- LITE+FRAG would start partially processing the options of each of the fragments before reassembling them, 
	resulting in unnecessary repeated checking (yes, if the fragments are bad we could stop earlier, but we also run 
	the computation twice in [hopefully] the typical case where no errors occur).

Joe