Commit 3a0504d5 authored by Ondrej Mosnacek's avatar Ondrej Mosnacek Committed by Jakub Kicinski

sctp: fix association labeling in the duplicate COOKIE-ECHO case

sctp_sf_do_5_2_4_dupcook() currently calls security_sctp_assoc_request()
on new_asoc, but as it turns out, this association is always discarded
and the LSM labels never get into the final association (asoc).

This can be reproduced by having two SCTP endpoints try to initiate an
association with each other at approximately the same time and then peel
off the association into a new socket, which exposes the unitialized
labels and triggers SELinux denials.

Fix it by calling security_sctp_assoc_request() on asoc instead of
new_asoc. Xin Long also suggested limit calling the hook only to cases
A, B, and D, since in cases C and E the COOKIE ECHO chunk is discarded
and the association doesn't enter the ESTABLISHED state, so rectify that
as well.

One related caveat with SELinux and peer labeling: When an SCTP
connection is set up simultaneously in this way, we will end up with an
association that is initialized with security_sctp_assoc_request() on
both sides, so the MLS component of the security context of the
association will get swapped between the peers, instead of just one side
setting it to the other's MLS component. However, at that point
security_sctp_assoc_request() had already been called on both sides in
sctp_sf_do_unexpected_init() (on a temporary association) and thus if
the exchange didn't fail before due to MLS, it won't fail now either
(most likely both endpoints have the same MLS range).

Tested by:
 - reproducer from https://src.fedoraproject.org/tests/selinux/pull-request/530
 - selinux-testsuite (https://github.com/SELinuxProject/selinux-testsuite/)
 - sctp-tests (https://github.com/sctp/sctp-tests) - no tests failed
   that wouldn't fail also without the patch applied

Fixes: c081d53f ("security: pass asoc to sctp_assoc_request and sctp_sk_clone")
Suggested-by: default avatarXin Long <lucien.xin@gmail.com>
Signed-off-by: default avatarOndrej Mosnacek <omosnace@redhat.com>
Acked-by: default avatarXin Long <lucien.xin@gmail.com>
Acked-by: Paul Moore <paul@paul-moore.com> (LSM/SELinux)
Link: https://patch.msgid.link/20240826130711.141271-1-omosnace@redhat.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 237c3851
...@@ -2260,12 +2260,6 @@ enum sctp_disposition sctp_sf_do_5_2_4_dupcook( ...@@ -2260,12 +2260,6 @@ enum sctp_disposition sctp_sf_do_5_2_4_dupcook(
} }
} }
/* Update socket peer label if first association. */
if (security_sctp_assoc_request(new_asoc, chunk->head_skb ?: chunk->skb)) {
sctp_association_free(new_asoc);
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
}
/* Set temp so that it won't be added into hashtable */ /* Set temp so that it won't be added into hashtable */
new_asoc->temp = 1; new_asoc->temp = 1;
...@@ -2274,6 +2268,22 @@ enum sctp_disposition sctp_sf_do_5_2_4_dupcook( ...@@ -2274,6 +2268,22 @@ enum sctp_disposition sctp_sf_do_5_2_4_dupcook(
*/ */
action = sctp_tietags_compare(new_asoc, asoc); action = sctp_tietags_compare(new_asoc, asoc);
/* In cases C and E the association doesn't enter the ESTABLISHED
* state, so there is no need to call security_sctp_assoc_request().
*/
switch (action) {
case 'A': /* Association restart. */
case 'B': /* Collision case B. */
case 'D': /* Collision case D. */
/* Update socket peer label if first association. */
if (security_sctp_assoc_request((struct sctp_association *)asoc,
chunk->head_skb ?: chunk->skb)) {
sctp_association_free(new_asoc);
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
}
break;
}
switch (action) { switch (action) {
case 'A': /* Association restart. */ case 'A': /* Association restart. */
retval = sctp_sf_do_dupcook_a(net, ep, asoc, chunk, commands, retval = sctp_sf_do_dupcook_a(net, ep, asoc, chunk, commands,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment