-
Notifications
You must be signed in to change notification settings - Fork 3k
Limit size of sctp_event_subscribe on Linux #10321
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
base: maint
Are you sure you want to change the base?
Conversation
CT Test Results 3 files 142 suites 50m 19s ⏱️ Results for commit 00bda45. ♻️ This comment has been updated with latest results. To speed up review, make sure that you have read Contributing to Erlang/OTP and that all checks pass. See the TESTING and DEVELOPMENT HowTo guides for details about how to run test locally. Artifacts// Erlang/OTP Github Action Bot |
|
Brief update on testing the socket API: i'm failing. Usage above is inspired by socket_server:do_manager_init(). |
| { | ||
| struct sctp_event_subscribe events; | ||
| BOOLEAN_T error; | ||
| int last_opt = offsetof(struct sctp_event_subscribe, |
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 looks like you could add a "#if defined(linux) ... #endif" around all the last_opt assignments.
Unless you are counting on the compiler optimizing those away on non-linux?
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.
Yes, indeed i could.
I thought that would be too messy and since this isn't a hot code path at all, i did not consider it for manual optimization.
If that's how you would like it to look though, i'll gladly add that.
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 do.
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.
9dc8a01 to
00bda45
Compare
|
Note that the sctp support is currently limited. |
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