|
@@ -153,10 +153,7 @@ static enum sctp_disposition sctp_sf_violation_chunk(
|
|
|
struct sctp_cmd_seq *commands);
|
|
|
|
|
|
static enum sctp_ierror sctp_sf_authenticate(
|
|
|
- struct net *net,
|
|
|
- const struct sctp_endpoint *ep,
|
|
|
const struct sctp_association *asoc,
|
|
|
- const union sctp_subtype type,
|
|
|
struct sctp_chunk *chunk);
|
|
|
|
|
|
static enum sctp_disposition __sctp_sf_do_9_1_abort(
|
|
@@ -626,6 +623,38 @@ enum sctp_disposition sctp_sf_do_5_1C_ack(struct net *net,
|
|
|
return SCTP_DISPOSITION_CONSUME;
|
|
|
}
|
|
|
|
|
|
+static bool sctp_auth_chunk_verify(struct net *net, struct sctp_chunk *chunk,
|
|
|
+ const struct sctp_association *asoc)
|
|
|
+{
|
|
|
+ struct sctp_chunk auth;
|
|
|
+
|
|
|
+ if (!chunk->auth_chunk)
|
|
|
+ return true;
|
|
|
+
|
|
|
+ /* SCTP-AUTH: auth_chunk pointer is only set when the cookie-echo
|
|
|
+ * is supposed to be authenticated and we have to do delayed
|
|
|
+ * authentication. We've just recreated the association using
|
|
|
+ * the information in the cookie and now it's much easier to
|
|
|
+ * do the authentication.
|
|
|
+ */
|
|
|
+
|
|
|
+ /* Make sure that we and the peer are AUTH capable */
|
|
|
+ if (!net->sctp.auth_enable || !asoc->peer.auth_capable)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ /* set-up our fake chunk so that we can process it */
|
|
|
+ auth.skb = chunk->auth_chunk;
|
|
|
+ auth.asoc = chunk->asoc;
|
|
|
+ auth.sctp_hdr = chunk->sctp_hdr;
|
|
|
+ auth.chunk_hdr = (struct sctp_chunkhdr *)
|
|
|
+ skb_push(chunk->auth_chunk,
|
|
|
+ sizeof(struct sctp_chunkhdr));
|
|
|
+ skb_pull(chunk->auth_chunk, sizeof(struct sctp_chunkhdr));
|
|
|
+ auth.transport = chunk->transport;
|
|
|
+
|
|
|
+ return sctp_sf_authenticate(asoc, &auth) == SCTP_IERROR_NO_ERROR;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Respond to a normal COOKIE ECHO chunk.
|
|
|
* We are the side that is being asked for an association.
|
|
@@ -763,37 +792,9 @@ enum sctp_disposition sctp_sf_do_5_1D_ce(struct net *net,
|
|
|
if (error)
|
|
|
goto nomem_init;
|
|
|
|
|
|
- /* SCTP-AUTH: auth_chunk pointer is only set when the cookie-echo
|
|
|
- * is supposed to be authenticated and we have to do delayed
|
|
|
- * authentication. We've just recreated the association using
|
|
|
- * the information in the cookie and now it's much easier to
|
|
|
- * do the authentication.
|
|
|
- */
|
|
|
- if (chunk->auth_chunk) {
|
|
|
- struct sctp_chunk auth;
|
|
|
- enum sctp_ierror ret;
|
|
|
-
|
|
|
- /* Make sure that we and the peer are AUTH capable */
|
|
|
- if (!net->sctp.auth_enable || !new_asoc->peer.auth_capable) {
|
|
|
- sctp_association_free(new_asoc);
|
|
|
- return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
|
|
|
- }
|
|
|
-
|
|
|
- /* set-up our fake chunk so that we can process it */
|
|
|
- auth.skb = chunk->auth_chunk;
|
|
|
- auth.asoc = chunk->asoc;
|
|
|
- auth.sctp_hdr = chunk->sctp_hdr;
|
|
|
- auth.chunk_hdr = (struct sctp_chunkhdr *)
|
|
|
- skb_push(chunk->auth_chunk,
|
|
|
- sizeof(struct sctp_chunkhdr));
|
|
|
- skb_pull(chunk->auth_chunk, sizeof(struct sctp_chunkhdr));
|
|
|
- auth.transport = chunk->transport;
|
|
|
-
|
|
|
- ret = sctp_sf_authenticate(net, ep, new_asoc, type, &auth);
|
|
|
- if (ret != SCTP_IERROR_NO_ERROR) {
|
|
|
- sctp_association_free(new_asoc);
|
|
|
- return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
|
|
|
- }
|
|
|
+ if (!sctp_auth_chunk_verify(net, chunk, new_asoc)) {
|
|
|
+ sctp_association_free(new_asoc);
|
|
|
+ return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
|
|
|
}
|
|
|
|
|
|
repl = sctp_make_cookie_ack(new_asoc, chunk);
|
|
@@ -1797,13 +1798,15 @@ static enum sctp_disposition sctp_sf_do_dupcook_a(
|
|
|
if (sctp_auth_asoc_init_active_key(new_asoc, GFP_ATOMIC))
|
|
|
goto nomem;
|
|
|
|
|
|
+ if (!sctp_auth_chunk_verify(net, chunk, new_asoc))
|
|
|
+ return SCTP_DISPOSITION_DISCARD;
|
|
|
+
|
|
|
/* Make sure no new addresses are being added during the
|
|
|
* restart. Though this is a pretty complicated attack
|
|
|
* since you'd have to get inside the cookie.
|
|
|
*/
|
|
|
- if (!sctp_sf_check_restart_addrs(new_asoc, asoc, chunk, commands)) {
|
|
|
+ if (!sctp_sf_check_restart_addrs(new_asoc, asoc, chunk, commands))
|
|
|
return SCTP_DISPOSITION_CONSUME;
|
|
|
- }
|
|
|
|
|
|
/* If the endpoint is in the SHUTDOWN-ACK-SENT state and recognizes
|
|
|
* the peer has restarted (Action A), it MUST NOT setup a new
|
|
@@ -1912,6 +1915,9 @@ static enum sctp_disposition sctp_sf_do_dupcook_b(
|
|
|
if (sctp_auth_asoc_init_active_key(new_asoc, GFP_ATOMIC))
|
|
|
goto nomem;
|
|
|
|
|
|
+ if (!sctp_auth_chunk_verify(net, chunk, new_asoc))
|
|
|
+ return SCTP_DISPOSITION_DISCARD;
|
|
|
+
|
|
|
/* Update the content of current association. */
|
|
|
sctp_add_cmd_sf(commands, SCTP_CMD_UPDATE_ASSOC, SCTP_ASOC(new_asoc));
|
|
|
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
|
|
@@ -2009,6 +2015,9 @@ static enum sctp_disposition sctp_sf_do_dupcook_d(
|
|
|
* a COOKIE ACK.
|
|
|
*/
|
|
|
|
|
|
+ if (!sctp_auth_chunk_verify(net, chunk, asoc))
|
|
|
+ return SCTP_DISPOSITION_DISCARD;
|
|
|
+
|
|
|
/* Don't accidentally move back into established state. */
|
|
|
if (asoc->state < SCTP_STATE_ESTABLISHED) {
|
|
|
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
|
|
@@ -4171,10 +4180,7 @@ gen_shutdown:
|
|
|
* The return value is the disposition of the chunk.
|
|
|
*/
|
|
|
static enum sctp_ierror sctp_sf_authenticate(
|
|
|
- struct net *net,
|
|
|
- const struct sctp_endpoint *ep,
|
|
|
const struct sctp_association *asoc,
|
|
|
- const union sctp_subtype type,
|
|
|
struct sctp_chunk *chunk)
|
|
|
{
|
|
|
struct sctp_shared_key *sh_key = NULL;
|
|
@@ -4275,7 +4281,7 @@ enum sctp_disposition sctp_sf_eat_auth(struct net *net,
|
|
|
commands);
|
|
|
|
|
|
auth_hdr = (struct sctp_authhdr *)chunk->skb->data;
|
|
|
- error = sctp_sf_authenticate(net, ep, asoc, type, chunk);
|
|
|
+ error = sctp_sf_authenticate(asoc, chunk);
|
|
|
switch (error) {
|
|
|
case SCTP_IERROR_AUTH_BAD_HMAC:
|
|
|
/* Generate the ERROR chunk and discard the rest
|