-
Notifications
You must be signed in to change notification settings - Fork 2k
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
gnrc_sock_udp: choose random ephemeral port #13253
Conversation
actually there was a discussion regarding random or not between @OlegHahm and me (@smlng), the reasoning was to not introduce the additional overhead of random by default. However, we also wanted to discuss this (or the implementation according to RFC 6056) separately of the PR #6212 - which sadly never happened. Maybe this PR takes this up now - |
on another note: (to me) in the past we (RIOT developers) were more into runtime and binary optimisation back when, but today I generally agree that features and security (should) come first. So I'm in favour of (re)introducing random here, but please review RFC 6056 too. |
Implements a random ephemeral port selection as per the second algorithm from RFC 6056, see https://tools.ietf.org/html/rfc6056#section-3.3.2.
Thanks for pointing that out, I somehow missed that thread in the pull request, sorry.
Didn't know about that RFC, thanks a lot for referencing it. In fact, the comment above RFC 6056 has an interesting section on Choosing an Ephemeral Port Selection Algorithm. According to this section, the algorithm proposed here "increase the chances of port number collisions, which could lead to the failure of a connection establishment attempt.". However, in my experience constrained devices establish far less connections than conventional ones. For this reason, I deem collisions to be less likely and have a personal preference towards this algorithm as it chooses a new truly random port for each socket. I will update the PR to make sure it implements Another Simple Port Randomization Algorithm correctly. If you prefer a different algorithm let me know. |
79201d7
to
b37bed8
Compare
Still check if the port is unused if no socket has been given.
310a2a3
to
5cf4338
Compare
@smlng seems the assumption about
I changed the check to: if ((sock != NULL && (sock->flags & SOCK_FLAGS_REUSE_EP)) ||
!_dyn_port_used(port)) |
so there was a reason for the check after all 😉 didn't remember that. |
if ((sock == NULL) || (sock->flags & SOCK_FLAGS_REUSE_EP) || | ||
!_dyn_port_used(port)) { | ||
(random_uint32() % GNRC_SOCK_DYN_PORTRANGE_NUM); | ||
if ((sock && (sock->flags & SOCK_FLAGS_REUSE_EP)) || !_dyn_port_used(port)) { |
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'd suggest to leave as it was before, right?
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 thought we agreed that the previous check was broken:
mhm, you're right the '||' doesn't make sense here.
To recap, the previous check would not check for local port collisions if sock
is NULL, which seems very wrong to me.
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.
?
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.
sock == NULL || (sock->flags & SOCK_FLAGS_REUSE_EP)
basically is sock → (sock->flags & SOCK_FLAGS_REUSE_EP)
in boolean logic. The logical implication allows basically all fire and forget "socks" (i.e. sock == NULL
) to be configured to use reusable ports.
sock |
reuse |
unused |
sock → reuse |
sock && reuse |
old | new |
---|---|---|---|---|---|---|
0 | 0 | 0 | 1 | 0 | 1 | 0 |
0 | 0 | 1 | 1 | 0 | 1 | 1 |
0 | 1 | 0 | 1 | 0 | 1 | 0 |
0 | 1 | 1 | 1 | 0 | 1 | 1 |
1 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 1 | 0 | 0 | 1 | 1 |
1 | 1 | 0 | 1 | 1 | 1 | 1 |
1 | 1 | 1 | 1 | 1 | 1 | 1 |
While technically this would be in line with GNRC below, I think for the sock interface this is not desirable. So I agree with @nmeum here that the new change makes more sense.
Yepp, very useful for simple fire-and-forget solutions ;-) |
Any reason why this hasn't been merged yet? IMHO this change is straightforward. I would also like to point out that RFC 6056 explicitly discourages using Algorithm 3 (which is incorrectly implemented at the moment anyhow as |
I suspect @smlng disappeared in children-assisted home office ;-) so let me have a look. |
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.
ACK. Tested with tests/gnrc_sock_udp
on native
and samr21-xpro
. Both still succeed.
if ((sock == NULL) || (sock->flags & SOCK_FLAGS_REUSE_EP) || | ||
!_dyn_port_used(port)) { | ||
(random_uint32() % GNRC_SOCK_DYN_PORTRANGE_NUM); | ||
if ((sock && (sock->flags & SOCK_FLAGS_REUSE_EP)) || !_dyn_port_used(port)) { |
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.
sock == NULL || (sock->flags & SOCK_FLAGS_REUSE_EP)
basically is sock → (sock->flags & SOCK_FLAGS_REUSE_EP)
in boolean logic. The logical implication allows basically all fire and forget "socks" (i.e. sock == NULL
) to be configured to use reusable ports.
sock |
reuse |
unused |
sock → reuse |
sock && reuse |
old | new |
---|---|---|---|---|---|---|
0 | 0 | 0 | 1 | 0 | 1 | 0 |
0 | 0 | 1 | 1 | 0 | 1 | 1 |
0 | 1 | 0 | 1 | 0 | 1 | 0 |
0 | 1 | 1 | 1 | 0 | 1 | 1 |
1 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 1 | 0 | 0 | 1 | 1 |
1 | 1 | 0 | 1 | 1 | 1 | 1 |
1 | 1 | 1 | 1 | 1 | 1 | 1 |
While technically this would be in line with GNRC below, I think for the sock interface this is not desirable. So I agree with @nmeum here that the new change makes more sense.
Last compile test was >1 month ago. Let's give that a rerun. |
Failing tests are unrelated and also fail in the current nightlies. |
Contribution description
While writing a PoC for #12293 and #12382 I noticed that RIOT does not randomize its ephemeral currently. This circumstance also made it significantly easier to exploit #10739. The first port value is
49152
and the value is simply sequential incremented after that. I consider this a security issue as it eases spoofing replies why this is a problem is hopefully illustrated by the previously mentioned issues.While working on this change, I noticed that
gnrc_sock_udp
already depends on therandom
module inMakefile.dep
, even though it does not use it. This made me curious and I discovered that it was removed, without much further discussion, in #6212:I personally think that this is a bad idea and an unnecessary security risk. If there is any specific reason why I should not be randomized please let me know.
Testing procedure
I tested this change using
examples/asymcute_mqttsn/
simply build the application, start it. Try to connect to a non-existing MQTT server and check using wireshark/tcpdump that it uses a random port as the UDP source port.Related