From 551e6aca09c23e8231a984733f1997f1c1be7f1f Mon Sep 17 00:00:00 2001 From: Michael Tuexen <tuexen@fh-muenster.de> Date: Fri, 5 Oct 2018 20:14:32 +0200 Subject: [PATCH] Improve handling of malformed frames. --- gtests/net/packetdrill/run_packet.c | 321 ++++++++++++++++------------ 1 file changed, 180 insertions(+), 141 deletions(-) diff --git a/gtests/net/packetdrill/run_packet.c b/gtests/net/packetdrill/run_packet.c index bb9573fe..beeada6b 100644 --- a/gtests/net/packetdrill/run_packet.c +++ b/gtests/net/packetdrill/run_packet.c @@ -274,9 +274,6 @@ static struct socket *handle_listen_for_script_packet( } if (!match) return NULL; - - if (socket == NULL) - socket = setup_new_child_socket(state, packet); if (packet->sctp != NULL) { if (sctp_is_init_packet(packet)) { @@ -285,8 +282,13 @@ static struct socket *handle_listen_for_script_packet( item = packet->chunk_list->first; init = (struct _sctp_init_chunk *) item->chunk; - sctp_socket_set_initiate_tag(socket, ntohl(init->initiate_tag)); - sctp_socket_set_initial_tsn(socket, ntohl(init->initial_tsn)); + if (ntohs(init->length) >= sizeof(struct _sctp_init_chunk)) { + if (socket == NULL) + socket = setup_new_child_socket(state, packet); + + sctp_socket_set_initiate_tag(socket, ntohl(init->initiate_tag)); + sctp_socket_set_initial_tsn(socket, ntohl(init->initial_tsn)); + } } else { struct header sctp_header; unsigned int i; @@ -300,7 +302,7 @@ static struct socket *handle_listen_for_script_packet( break; } } - + assert(found != false); chunk_length = sctp_header.total_bytes - sizeof(struct sctp_common_header); @@ -308,10 +310,12 @@ static struct socket *handle_listen_for_script_packet( fprintf(stderr, "length of init chunk too short. you must specify the whole init chunk."); return NULL; } - + u8 *sctp_chunk_start = (u8 *) (packet->sctp + 1); struct _sctp_init_chunk *init = (struct _sctp_init_chunk *) sctp_chunk_start; - + + if (socket == NULL) + socket = setup_new_child_socket(state, packet); sctp_socket_set_initiate_tag(socket, ntohl(init->initiate_tag)); sctp_socket_set_initial_tsn(socket, ntohl(init->initial_tsn)); } @@ -319,8 +323,10 @@ static struct socket *handle_listen_for_script_packet( return socket; } } - + if (packet->tcp != NULL) { + if (socket == NULL) + socket = setup_new_child_socket(state, packet); socket->script.remote_isn = ntohl(packet->tcp->seq); socket->live.remote_isn = ntohl(packet->tcp->seq); } @@ -676,6 +682,7 @@ static int map_inbound_sctp_packet( u32 local_diff, remote_diff; u32 v_tag; u16 nr_gap_blocks, number_of_nr_gap_blocks, nr_dup_tsns, i; + u16 chunk_length; bool reflect_v_tag; bool contains_init_chunk; @@ -699,172 +706,201 @@ static int map_inbound_sctp_packet( socket->live.local_initial_tsn, socket->script.local_initial_tsn); remote_diff = socket->live.remote_initial_tsn - socket->script.remote_initial_tsn; local_diff = socket->live.local_initial_tsn - socket->script.local_initial_tsn; + chunk_length = ntohs(chunk->length); switch (chunk->type) { case SCTP_DATA_CHUNK_TYPE: - data = (struct _sctp_data_chunk *)chunk; - data->tsn = htonl(ntohl(data->tsn) + remote_diff); + if (chunk_length >= sizeof(struct _sctp_data_chunk)) { + data = (struct _sctp_data_chunk *)chunk; + data->tsn = htonl(ntohl(data->tsn) + remote_diff); + } break; case SCTP_INIT_CHUNK_TYPE: - init = (struct _sctp_init_chunk *)chunk; - init->initial_tsn = htonl(ntohl(init->initial_tsn) + remote_diff); - /* XXX: Does this work in all cases? */ - if (ntohl(init->initiate_tag) == socket->script.local_initiate_tag) { - init->initiate_tag = htonl(socket->live.local_initiate_tag); + if (chunk_length >= sizeof(struct _sctp_init_chunk)) { + init = (struct _sctp_init_chunk *)chunk; + init->initial_tsn = htonl(ntohl(init->initial_tsn) + remote_diff); + /* XXX: Does this work in all cases? */ + if (ntohl(init->initiate_tag) == socket->script.local_initiate_tag) { + init->initiate_tag = htonl(socket->live.local_initiate_tag); + } + contains_init_chunk = true; } - contains_init_chunk = true; break; case SCTP_INIT_ACK_CHUNK_TYPE: - init_ack = (struct _sctp_init_ack_chunk *)chunk; - init_ack->initial_tsn = htonl(ntohl(init_ack->initial_tsn) + remote_diff); - /* XXX: Does this work in all cases? */ - if (ntohl(init_ack->initiate_tag) == socket->script.local_initiate_tag) { - init_ack->initiate_tag = htonl(socket->live.local_initiate_tag); + if (chunk_length >= sizeof(struct _sctp_init_ack_chunk)) { + init_ack = (struct _sctp_init_ack_chunk *)chunk; + init_ack->initial_tsn = htonl(ntohl(init_ack->initial_tsn) + remote_diff); + /* XXX: Does this work in all cases? */ + if (ntohl(init_ack->initiate_tag) == socket->script.local_initiate_tag) { + init_ack->initiate_tag = htonl(socket->live.local_initiate_tag); + } } break; case SCTP_SACK_CHUNK_TYPE: - sack = (struct _sctp_sack_chunk *)chunk; - DEBUGP("Old SACK cum TSN %d\n", ntohl(sack->cum_tsn)); - sack->cum_tsn = htonl(ntohl(sack->cum_tsn) + local_diff); - DEBUGP("New SACK cum TSN %d\n", ntohl(sack->cum_tsn)); - nr_gap_blocks = ntohs(sack->nr_gap_blocks); - nr_dup_tsns = ntohs(sack->nr_dup_tsns); - - if (ntohs(sack->length) == sizeof(struct _sctp_sack_chunk) + sizeof(union sctp_sack_block) * (nr_dup_tsns+nr_gap_blocks)) { - for (i = 0; i < nr_dup_tsns; i++) { - sack->block[i + nr_gap_blocks].tsn = htonl(ntohl(sack->block[i + nr_gap_blocks].tsn) + local_diff); + if (chunk_length >= sizeof(struct _sctp_sack_chunk)) { + sack = (struct _sctp_sack_chunk *)chunk; + DEBUGP("Old SACK cum TSN %d\n", ntohl(sack->cum_tsn)); + sack->cum_tsn = htonl(ntohl(sack->cum_tsn) + local_diff); + DEBUGP("New SACK cum TSN %d\n", ntohl(sack->cum_tsn)); + nr_gap_blocks = ntohs(sack->nr_gap_blocks); + nr_dup_tsns = ntohs(sack->nr_dup_tsns); + + if (chunk_length == sizeof(struct _sctp_sack_chunk) + sizeof(union sctp_sack_block) * (nr_dup_tsns + nr_gap_blocks)) { + for (i = 0; i < nr_dup_tsns; i++) { + sack->block[i + nr_gap_blocks].tsn = htonl(ntohl(sack->block[i + nr_gap_blocks].tsn) + local_diff); + } } } break; case SCTP_NR_SACK_CHUNK_TYPE: - nr_sack = (struct _sctp_nr_sack_chunk *)chunk; - DEBUGP("Old SACK cum TSN %d\n", ntohl(nr_sack->cum_tsn)); - nr_sack->cum_tsn = htonl(ntohl(nr_sack->cum_tsn) + local_diff); - DEBUGP("New SACK cum TSN %d\n", ntohl(nr_sack->cum_tsn)); - nr_gap_blocks = ntohs(nr_sack->nr_gap_blocks); - number_of_nr_gap_blocks = ntohs(nr_sack->nr_of_nr_gap_blocks); - nr_dup_tsns = ntohs(nr_sack->nr_dup_tsns); - - if (ntohs(nr_sack->length) == sizeof(struct _sctp_nr_sack_chunk) + sizeof(union sctp_nr_sack_block) * (nr_dup_tsns+nr_gap_blocks)) { - for (i = 0; i < nr_dup_tsns; i++) { - u16 offset = nr_gap_blocks + number_of_nr_gap_blocks; - nr_sack->block[i + offset].tsn = htonl(ntohl(nr_sack->block[i + offset].tsn) + local_diff); + if (chunk_length >= sizeof(struct _sctp_nr_sack_chunk)) { + nr_sack = (struct _sctp_nr_sack_chunk *)chunk; + DEBUGP("Old SACK cum TSN %d\n", ntohl(nr_sack->cum_tsn)); + nr_sack->cum_tsn = htonl(ntohl(nr_sack->cum_tsn) + local_diff); + DEBUGP("New SACK cum TSN %d\n", ntohl(nr_sack->cum_tsn)); + nr_gap_blocks = ntohs(nr_sack->nr_gap_blocks); + number_of_nr_gap_blocks = ntohs(nr_sack->nr_of_nr_gap_blocks); + nr_dup_tsns = ntohs(nr_sack->nr_dup_tsns); + + if (chunk_length == sizeof(struct _sctp_nr_sack_chunk) + sizeof(union sctp_nr_sack_block) * (nr_dup_tsns+nr_gap_blocks)) { + for (i = 0; i < nr_dup_tsns; i++) { + u16 offset = nr_gap_blocks + number_of_nr_gap_blocks; + nr_sack->block[i + offset].tsn = htonl(ntohl(nr_sack->block[i + offset].tsn) + local_diff); + } } } break; case SCTP_ABORT_CHUNK_TYPE: - abort = (struct _sctp_abort_chunk *)chunk; - if (abort->flags & SCTP_ABORT_CHUNK_T_BIT) { - reflect_v_tag = true; + if (chunk_length >= sizeof(struct _sctp_abort_chunk)) { + abort = (struct _sctp_abort_chunk *)chunk; + if (abort->flags & SCTP_ABORT_CHUNK_T_BIT) { + reflect_v_tag = true; + } } break; case SCTP_SHUTDOWN_CHUNK_TYPE: - shutdown = (struct _sctp_shutdown_chunk *)chunk; - shutdown->cum_tsn = htonl(ntohl(shutdown->cum_tsn) + local_diff); + if (chunk_length >= sizeof(struct _sctp_shutdown_chunk)) { + shutdown = (struct _sctp_shutdown_chunk *)chunk; + shutdown->cum_tsn = htonl(ntohl(shutdown->cum_tsn) + local_diff); + } break; case SCTP_ECNE_CHUNK_TYPE: - ecne = (struct _sctp_ecne_chunk *)chunk; - ecne->lowest_tsn = htonl(ntohl(ecne->lowest_tsn) + local_diff); + if (chunk_length >= sizeof(struct _sctp_ecne_chunk)) { + ecne = (struct _sctp_ecne_chunk *)chunk; + ecne->lowest_tsn = htonl(ntohl(ecne->lowest_tsn) + local_diff); + } break; case SCTP_CWR_CHUNK_TYPE: - cwr = (struct _sctp_cwr_chunk *)chunk; - cwr->lowest_tsn = htonl(ntohl(cwr->lowest_tsn) + local_diff); + if (chunk_length >= sizeof(struct _sctp_cwr_chunk)) { + cwr = (struct _sctp_cwr_chunk *)chunk; + cwr->lowest_tsn = htonl(ntohl(cwr->lowest_tsn) + local_diff); + } break; case SCTP_SHUTDOWN_COMPLETE_CHUNK_TYPE: - shutdown_complete = (struct _sctp_shutdown_complete_chunk *)chunk; - if (shutdown_complete->flags & SCTP_SHUTDOWN_COMPLETE_CHUNK_T_BIT) { - reflect_v_tag = true; + if (chunk_length >= sizeof(struct _sctp_shutdown_complete_chunk)) { + shutdown_complete = (struct _sctp_shutdown_complete_chunk *)chunk; + if (shutdown_complete->flags & SCTP_SHUTDOWN_COMPLETE_CHUNK_T_BIT) { + reflect_v_tag = true; + } } break; case SCTP_I_DATA_CHUNK_TYPE: - i_data = (struct _sctp_i_data_chunk *)chunk; - i_data->tsn = htonl(ntohl(i_data->tsn) + remote_diff); + if (chunk_length >= sizeof(struct _sctp_i_data_chunk)) { + i_data = (struct _sctp_i_data_chunk *)chunk; + i_data->tsn = htonl(ntohl(i_data->tsn) + remote_diff); + } break; case SCTP_FORWARD_TSN_CHUNK_TYPE: - forward_tsn = (struct _sctp_forward_tsn_chunk *) chunk; - forward_tsn->cum_tsn = htonl(ntohl(forward_tsn->cum_tsn) + remote_diff); + if (chunk_length >= sizeof(struct _sctp_forward_tsn_chunk)) { + forward_tsn = (struct _sctp_forward_tsn_chunk *) chunk; + forward_tsn->cum_tsn = htonl(ntohl(forward_tsn->cum_tsn) + remote_diff); + } break; case SCTP_I_FORWARD_TSN_CHUNK_TYPE: - i_forward_tsn = (struct _sctp_i_forward_tsn_chunk *) chunk; - i_forward_tsn->cum_tsn = htonl(ntohl(i_forward_tsn->cum_tsn) + remote_diff); + if (chunk_length >= sizeof(struct _sctp_i_forward_tsn_chunk)) { + i_forward_tsn = (struct _sctp_i_forward_tsn_chunk *) chunk; + i_forward_tsn->cum_tsn = htonl(ntohl(i_forward_tsn->cum_tsn) + remote_diff); + } break; case SCTP_RECONFIG_CHUNK_TYPE: - reconfig = (struct _sctp_reconfig_chunk *)chunk; - if (htons(reconfig->length) >= sizeof(struct _sctp_reconfig_chunk) + 4) { - struct sctp_parameter *parameter; - struct sctp_parameters_iterator iter; - int parameters_length = ntohs(reconfig->length) - sizeof(struct _sctp_reconfig_chunk); - for (parameter = sctp_parameters_begin(reconfig->parameter, parameters_length, - &iter, error); - parameter != NULL; - parameter = sctp_parameters_next(&iter, error)) { - if (*error != NULL) { - DEBUGP("Partial parameter detected\n"); - free(*error); - *error = NULL; - break; - } - switch (htons(parameter->type)) { - case SCTP_OUTGOING_SSN_RESET_REQUEST_PARAMETER_TYPE: { - struct sctp_outgoing_ssn_reset_request_parameter *reset; - reset = (struct sctp_outgoing_ssn_reset_request_parameter *)parameter; - if (htons(reset->length) >= 8) { - reset->reqsn = htonl(ntohl(reset->reqsn) + remote_diff); - } - if (htons(reset->length) >= 12) { - reset->respsn = htonl(ntohl(reset->respsn) + local_diff); + if (chunk_length >= sizeof(struct _sctp_reconfig_chunk)) { + reconfig = (struct _sctp_reconfig_chunk *)chunk; + if (chunk_length >= sizeof(struct _sctp_reconfig_chunk) + 4) { + struct sctp_parameter *parameter; + struct sctp_parameters_iterator iter; + int parameters_length = ntohs(reconfig->length) - sizeof(struct _sctp_reconfig_chunk); + for (parameter = sctp_parameters_begin(reconfig->parameter, parameters_length, + &iter, error); + parameter != NULL; + parameter = sctp_parameters_next(&iter, error)) { + if (*error != NULL) { + DEBUGP("Partial parameter detected\n"); + free(*error); + *error = NULL; + break; } - if (htons(reset->length) >= 16) { - reset->last_tsn = htonl(ntohl(reset->last_tsn) + remote_diff); + switch (htons(parameter->type)) { + case SCTP_OUTGOING_SSN_RESET_REQUEST_PARAMETER_TYPE: { + struct sctp_outgoing_ssn_reset_request_parameter *reset; + reset = (struct sctp_outgoing_ssn_reset_request_parameter *)parameter; + if (htons(reset->length) >= 8) { + reset->reqsn = htonl(ntohl(reset->reqsn) + remote_diff); + } + if (htons(reset->length) >= 12) { + reset->respsn = htonl(ntohl(reset->respsn) + local_diff); + } + if (htons(reset->length) >= 16) { + reset->last_tsn = htonl(ntohl(reset->last_tsn) + remote_diff); + } + break; } - break; - } - case SCTP_INCOMING_SSN_RESET_REQUEST_PARAMETER_TYPE: { - struct sctp_incoming_ssn_reset_request_parameter *reset; - reset = (struct sctp_incoming_ssn_reset_request_parameter *)parameter; - if (htons(reset->length) >= 8) { - reset->reqsn = htonl(ntohl(reset->reqsn) + remote_diff); + case SCTP_INCOMING_SSN_RESET_REQUEST_PARAMETER_TYPE: { + struct sctp_incoming_ssn_reset_request_parameter *reset; + reset = (struct sctp_incoming_ssn_reset_request_parameter *)parameter; + if (htons(reset->length) >= 8) { + reset->reqsn = htonl(ntohl(reset->reqsn) + remote_diff); + } + break; } - break; - } - case SCTP_SSN_TSN_RESET_REQUEST_PARAMETER_TYPE: { - struct sctp_ssn_tsn_reset_request_parameter *reset; - reset = (struct sctp_ssn_tsn_reset_request_parameter *)parameter; - if (htons(reset->length) >= 8) { - reset->reqsn = htonl(ntohl(reset->reqsn) + remote_diff); + case SCTP_SSN_TSN_RESET_REQUEST_PARAMETER_TYPE: { + struct sctp_ssn_tsn_reset_request_parameter *reset; + reset = (struct sctp_ssn_tsn_reset_request_parameter *)parameter; + if (htons(reset->length) >= 8) { + reset->reqsn = htonl(ntohl(reset->reqsn) + remote_diff); + } + break; } - break; - } - case SCTP_RECONFIG_RESPONSE_PARAMETER_TYPE: { - struct sctp_reconfig_response_parameter *response; - response = (struct sctp_reconfig_response_parameter *)parameter; - response->respsn = htonl(htonl(response->respsn) + local_diff); - if (htons(response->length) >= 16) { - response->receiver_next_tsn = htonl(htonl(response->receiver_next_tsn) + local_diff); + case SCTP_RECONFIG_RESPONSE_PARAMETER_TYPE: { + struct sctp_reconfig_response_parameter *response; + response = (struct sctp_reconfig_response_parameter *)parameter; + response->respsn = htonl(htonl(response->respsn) + local_diff); + if (htons(response->length) >= 16) { + response->receiver_next_tsn = htonl(htonl(response->receiver_next_tsn) + local_diff); + } + if (htons(response->length) >= 20) { + response->sender_next_tsn = htonl(htonl(response->sender_next_tsn) + remote_diff); + } + break; } - if (htons(response->length) >= 20) { - response->sender_next_tsn = htonl(htonl(response->sender_next_tsn) + remote_diff); + case SCTP_ADD_OUTGOING_STREAMS_REQUEST_PARAMETER_TYPE: { + struct sctp_add_outgoing_streams_request_parameter *request; + request = (struct sctp_add_outgoing_streams_request_parameter *)parameter; + if (htons(request->length) >= 8) { + request->reqsn = htonl(htonl(request->reqsn) + remote_diff); + } + break; } - break; - } - case SCTP_ADD_OUTGOING_STREAMS_REQUEST_PARAMETER_TYPE: { - struct sctp_add_outgoing_streams_request_parameter *request; - request = (struct sctp_add_outgoing_streams_request_parameter *)parameter; - if (htons(request->length) >= 8) { - request->reqsn = htonl(htonl(request->reqsn) + remote_diff); + case SCTP_ADD_INCOMING_STREAMS_REQUEST_PARAMETER_TYPE: { + struct sctp_add_incoming_streams_request_parameter *request; + request = (struct sctp_add_incoming_streams_request_parameter *)parameter; + if (htons(request->length) >= 8) { + request->reqsn = htonl(htonl(request->reqsn) + remote_diff); + } + break; } - break; - } - case SCTP_ADD_INCOMING_STREAMS_REQUEST_PARAMETER_TYPE: { - struct sctp_add_incoming_streams_request_parameter *request; - request = (struct sctp_add_incoming_streams_request_parameter *)parameter; - if (htons(request->length) >= 8) { - request->reqsn = htonl(htonl(request->reqsn) + remote_diff); + default: + //do nothing + break; } - break; - } - default: - //do nothing - break; } } } @@ -3264,7 +3300,7 @@ static int do_inbound_script_packet( struct _sctp_init_ack_chunk *init_ack; struct sctp_chunk_list_item *item; int result = STATUS_ERR; /* return value */ - u16 offset = 0, temp_offset; + u16 offset = 0, temp_offset, chunk_length; u16 i; DEBUGP("do_inbound_script_packet\n"); @@ -3286,17 +3322,20 @@ static int do_inbound_script_packet( for (item = packet->chunk_list->first; item != NULL; item = item->next) { + chunk_length = ntohs(item->chunk->length); switch (item->chunk->type) { case SCTP_INIT_ACK_CHUNK_TYPE: - if (socket->state == SOCKET_ACTIVE_INIT_SENT) { - init_ack = (struct _sctp_init_ack_chunk *)item->chunk; - DEBUGP("Moving socket in SOCKET_ACTIVE_INIT_ACK_RECEIVED\n"); - socket->state = SOCKET_ACTIVE_INIT_ACK_RECEIVED; - socket->script.remote_initiate_tag = ntohl(init_ack->initiate_tag); - socket->script.remote_initial_tsn = ntohl(init_ack->initial_tsn); - socket->live.remote_initiate_tag = ntohl(init_ack->initiate_tag); - socket->live.remote_initial_tsn = ntohl(init_ack->initial_tsn); - DEBUGP("remote_initiate_tag 0x%08x, remote_initial_tsn 0x%08x\n", ntohl(init_ack->initiate_tag), ntohl(init_ack->initial_tsn)); + if (chunk_length >= sizeof(struct _sctp_init_ack_chunk)) { + if (socket->state == SOCKET_ACTIVE_INIT_SENT) { + init_ack = (struct _sctp_init_ack_chunk *)item->chunk; + DEBUGP("Moving socket in SOCKET_ACTIVE_INIT_ACK_RECEIVED\n"); + socket->state = SOCKET_ACTIVE_INIT_ACK_RECEIVED; + socket->script.remote_initiate_tag = ntohl(init_ack->initiate_tag); + socket->script.remote_initial_tsn = ntohl(init_ack->initial_tsn); + socket->live.remote_initiate_tag = ntohl(init_ack->initiate_tag); + socket->live.remote_initial_tsn = ntohl(init_ack->initial_tsn); + DEBUGP("remote_initiate_tag 0x%08x, remote_initial_tsn 0x%08x\n", ntohl(init_ack->initiate_tag), ntohl(init_ack->initial_tsn)); + } } break; case SCTP_COOKIE_ECHO_CHUNK_TYPE: -- GitLab