Limit size of sctp_event_subscribe on Linux #10321
Open
+16
β1
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Use only the size which contains the last used option. This will help with compatibility since some vendor kernels have backported SCTP options turning simple backwards compatibility into breaking forward compatibility even for relatively similar versions. The Linux kernel is robust against using arbitrary sized structs.
=== Commit message ends ===
NB: Still slightly WIP - i do want to add inline comments, but i think it is better i do that after initial discussion so they are on the correct level.
Only the inet code is tested as of writing this.
=== Extra info ===
The problem
The struct for the
SCTP_EVENTSsocket option (sctp_event_subscribe) breaks ABI/API and is only backwards compatible.We are making a single OTP build that is used across a few different Linux versions.
Yes, that's not the best way to do things - but given the low amount of dependencies and that we have taken some care to select build host, it has been working fine for our purposes for many many years.
Up until now, that is.
It turns out some vendor kernels have backported options all the way from 5.5 to 4.18, causing what should otherwise have been a simple minor backward compatibility situation to instead be a forward compatibility problem (which breaks, as it should).
This option,
SCTP_EVENTS, is known to have this issue and has been deprecated.However, it seems to early to stop using it (see Alternative solutions).
Proposed solution
Use a smaller struct size
Linux, though late on the suggested proper solution (
SCTP_EVENT), has very robust handling of thesctp_event_subscribestruct which is pretty much as good and supports arbitrary sizes as long as the fields are in the correct order (and they are).The only thing that will return an error is if we would pass it a larger struct than what it knows what to do with when setting options. Doing that could indicate the user had set options which the kernel did not accept.
Therefore i propose to clamp the struct size used to include only the highest used/usable option.
The socket api exposes options 9 and 10, beyond the 8 that inet does, behind individual config-tested ifdefs.
This makes the proposed code in inet and socket slightly different to keep in line with the respective module.
(Sidenote: Currently the socket API is limited to only the events defined in the RFC. This is good practice; so if/when further options are needed, add the
SCTP_EVENToption for individual options instead).(Sidenote 2: Should trying to set option 9 or 10 when not supported not return an error?)
Unfortunately; this will have to be a Linux-only solution.
FreeBSD and IllumOS both have no recent updates to this struct - but also basically no usable backward compatibility mechnisms.
FreeBSD will return EINVAL if the provided size is smaller than the kernel's definition of the struct, both for reading and writing, i.e. silently discard too-new options(!).
IllumOS does not check the allocated size whatsoever and just casts to the Kernel's definition of the struct, both potentially segfaulting and ignoring options with non-matching definitions.
It is fair to assume FreeBSD and IllumOS will adopt some sort of robustness features if they ever add more fields, but what they will look like is anyone's guess.
Alternative solutions
SCTP_EVENT (singular) socket options
This would allow us to set individual options and not care about struct size.
OTP could even own a RFC-like struct definiton (which it basically does already) and translate to individual
SCTP_EVENTcalls.This was added in FreeBSD 9 (2012), Linux 5.0 (2019), but does not exost in IllumOS.
Not sure what te status of IllumOS support actually is, but dropping support for Linux 4.X seems a little too drastic.
I.e. i agree with the decision to keep using the deprecated SCTP_EVNTS (plural) socket option for a while longer.
(Especially since the Linux implementation is so good).
History of the options struct
The ABI up until including sctp_sender_dry_event is in RFC 6458.
No idea where the rest comes from - but at lest Linux and FreeBSD agree on what the 11th event is.
IllumOS, then Solaris, development seems to have stopped at the first published revision of the struct.
RFC 6458 (and preceeding IETF draft)
https://datatracker.ietf.org/doc/html/rfc6458
Linux
https://github.com/torvalds/linux/blame/6548d364a3e850326831799d7e3ea2d7bb97ba08/include/uapi/linux/sctp.h#L611
FreeBSD
https://github.com/freebsd/freebsd-src/blame/131dc2b7ad1b147b3b2775090f9eb55a7c2112ba/sys/netinet/sctp_uio.h#L61
IllumOS
https://github.com/illumos/illumos-gate/blame/7f3d7c9289dee6488b3cd2848a68c0b8580d750c/usr/src/uts/common/netinet/sctp.h#L159