From 7b5ee3a038c869e773092834abaa8174e0d77514 Mon Sep 17 00:00:00 2001 From: Satyam Sharma Date: Mon, 3 Sep 2007 01:41:34 +0530 Subject: [PATCH] net/wireless/sysfs.c: Shut up build warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit net/wireless/sysfs.c:108: warning: ‘wiphy_uevent’ defined but not used when CONFIG_HOTPLUG=n is because the only usage site of this function is #ifdef'ed as such, so let's #ifdef the definition also. Signed-off-by: Satyam Sharma Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/sysfs.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net') diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c index 88aaacd9f822..2d5d2255a27c 100644 --- a/net/wireless/sysfs.c +++ b/net/wireless/sysfs.c @@ -52,12 +52,14 @@ static void wiphy_dev_release(struct device *dev) cfg80211_dev_free(rdev); } +#ifdef CONFIG_HOTPLUG static int wiphy_uevent(struct device *dev, char **envp, int num_envp, char *buf, int size) { /* TODO, we probably need stuff here */ return 0; } +#endif struct class ieee80211_class = { .name = "ieee80211", -- cgit v1.2.3 From 3a4624652e68ee897145ac698a85bfd2603367c3 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 10 Sep 2007 13:44:45 +0200 Subject: [PATCH] cfg80211: fix initialisation if built-in When cfg80211 is built into the kernel it needs to init earlier so that device registrations are run after it has initialised. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/wireless/core.c b/net/wireless/core.c index 7eabd55417a5..9771451eae21 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -213,7 +213,7 @@ out_fail_notifier: out_fail_sysfs: return err; } -module_init(cfg80211_init); +subsys_initcall(cfg80211_init); static void cfg80211_exit(void) { -- cgit v1.2.3 From 136e83d6b8999f4ef680ff9cf2a67e1e1ccbd94e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 10 Sep 2007 13:55:08 +0200 Subject: [PATCH] net/mac80211/wme.c: fix sparse warning wme.c triggers a sparse warning; it wasn't noticed before because until recently ARRAY_SIZE triggered a sparse error. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/wme.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 89ce81529694..7ab82b376e1b 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c @@ -424,7 +424,7 @@ static int wme_qdiscop_init(struct Qdisc *qd, struct rtattr *opt) skb_queue_head_init(&q->requeued[i]); q->queues[i] = qdisc_create_dflt(qd->dev, &pfifo_qdisc_ops, qd->handle); - if (q->queues[i] == 0) { + if (!q->queues[i]) { q->queues[i] = &noop_qdisc; printk(KERN_ERR "%s child qdisc %i creation failed", dev->name, i); } -- cgit v1.2.3 From ca9938fea576ebbb8d8c4fbe8a5bcc937e49e1ca Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 11 Sep 2007 12:50:32 +0200 Subject: [PATCH] mac80211: fix initialisation when built-in When mac80211 is built into the kernel it needs to init earlier so that device registrations are run after it has initialised. The same applies to rate control algorithms. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211.c | 2 +- net/mac80211/rc80211_simple.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 7286c389a4d0..ff2172ffd861 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -5259,7 +5259,7 @@ static void __exit ieee80211_exit(void) } -module_init(ieee80211_init); +subsys_initcall(ieee80211_init); module_exit(ieee80211_exit); MODULE_DESCRIPTION("IEEE 802.11 subsystem"); diff --git a/net/mac80211/rc80211_simple.c b/net/mac80211/rc80211_simple.c index f6780d63b342..17b9f46bbf2b 100644 --- a/net/mac80211/rc80211_simple.c +++ b/net/mac80211/rc80211_simple.c @@ -431,7 +431,7 @@ static void __exit rate_control_simple_exit(void) } -module_init(rate_control_simple_init); +subsys_initcall(rate_control_simple_init); module_exit(rate_control_simple_exit); MODULE_DESCRIPTION("Simple rate control algorithm for ieee80211"); -- cgit v1.2.3 From a09c83847b664dcd67a72613374061c900afb799 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Wed, 5 Sep 2007 15:53:58 -0400 Subject: SCTP: Validate buffer room when processing sequential chunks When we process bundled chunks, we need to make sure that the skb has the buffer for each header since we assume it's always there. Some malicious node can send us something like DATA + 2 bytes and we'll try to walk off the end refrencing potentially uninitialized memory. Signed-off-by: Vlad Yasevich --- net/sctp/inqueue.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'net') diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c index 88aa22407549..e4ea7fdf36ed 100644 --- a/net/sctp/inqueue.c +++ b/net/sctp/inqueue.c @@ -130,6 +130,14 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue) /* Force chunk->skb->data to chunk->chunk_end. */ skb_pull(chunk->skb, chunk->chunk_end - chunk->skb->data); + + /* Verify that we have at least chunk headers + * worth of buffer left. + */ + if (skb_headlen(chunk->skb) < sizeof(sctp_chunkhdr_t)) { + sctp_chunk_free(chunk); + chunk = queue->in_progress = NULL; + } } } -- cgit v1.2.3 From 02c4e12c6400b6dccdc6b5c2c18325551e4b2dc9 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 31 Aug 2007 10:03:58 +0800 Subject: SCTP: Send ABORT chunk with correct tag in response to INIT ACK When SCTP client received an INIT ACK chunk with missing mandatory parameter such as "cookie parameter", it will send back a ABORT with T-bit not set and verification tag is set to 0. This is because before we accept this INIT ACK chunk, we do not know the peer's tag. This patch change to reflect vtag when responding to INIT ACK with missing mandatory parameter. Signed-off-by: Wei Yongjun Signed-off-by: Vlad Yasevich --- net/sctp/sm_statefuns.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 177528ed3e1b..385f1757158a 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -5176,7 +5176,22 @@ static struct sctp_packet *sctp_ootb_pkt_new(const struct sctp_association *asoc * association exists, otherwise, use the peer's vtag. */ if (asoc) { - vtag = asoc->peer.i.init_tag; + /* Special case the INIT-ACK as there is no peer's vtag + * yet. + */ + switch(chunk->chunk_hdr->type) { + case SCTP_CID_INIT_ACK: + { + sctp_initack_chunk_t *initack; + + initack = (sctp_initack_chunk_t *)chunk->chunk_hdr; + vtag = ntohl(initack->init_hdr.init_tag); + break; + } + default: + vtag = asoc->peer.i.init_tag; + break; + } } else { /* Special case the INIT and stale COOKIE_ECHO as there is no * vtag yet. -- cgit v1.2.3 From d3f259687fd248aa4de477149481478c122ba48b Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Fri, 7 Sep 2007 11:47:45 -0400 Subject: SCTP: Explicitely discard OOTB chunks Explicitely discard OOTB chunks, whether the result is a SHUTDOWN COMPLETE or an ABORT. We need to discard the OOTB SHUTDOWN ACK to prevent bombing attackes since responsed MUST NOT be bundled. We also explicietely discard in the ABORT case since that function is widely used internally. Signed-off-by: Vlad Yasevich Acked-by: Neil Horman --- net/sctp/sm_statefuns.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 385f1757158a..5e7fb0f54b88 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -2965,6 +2965,7 @@ sctp_disposition_t sctp_sf_tabort_8_4_8(const struct sctp_endpoint *ep, SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS); + sctp_sf_pdiscard(ep, asoc, type, arg, commands); return SCTP_DISPOSITION_CONSUME; } @@ -3148,11 +3149,9 @@ sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep, } while (ch_end < skb_tail_pointer(skb)); if (ootb_shut_ack) - sctp_sf_shut_8_4_5(ep, asoc, type, arg, commands); + return sctp_sf_shut_8_4_5(ep, asoc, type, arg, commands); else - sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands); - - return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands); } /* @@ -3218,7 +3217,11 @@ static sctp_disposition_t sctp_sf_shut_8_4_5(const struct sctp_endpoint *ep, if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t))) return sctp_sf_pdiscard(ep, asoc, type, arg, commands); - return SCTP_DISPOSITION_CONSUME; + /* We need to discard the rest of the packet to prevent + * potential bomming attacks from additional bundled chunks. + * This is documented in SCTP Threats ID. + */ + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); } return SCTP_DISPOSITION_NOMEM; -- cgit v1.2.3 From ece25dfa0991f65c4e1d26beb1c3c45bda4239b8 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Fri, 7 Sep 2007 16:30:54 -0400 Subject: SCTP: Clean up OOTB handling and fix infinite loop processing While processing OOTB chunks as well as chunks with an invalid length of 0, it was possible to SCTP to get wedged inside an infinite loop because we didn't catch the condition correctly, or didn't mark the packet for discard correctly. This work is based on original findings and work by Wei Yongjun Signed-off-by: Vlad Yasevich --- include/net/sctp/sm.h | 1 - net/sctp/sm_statefuns.c | 163 +++++++++++++++++++++++++++++++++++++---------- net/sctp/sm_statetable.c | 16 ++--- 3 files changed, 138 insertions(+), 42 deletions(-) (limited to 'net') diff --git a/include/net/sctp/sm.h b/include/net/sctp/sm.h index 991c85bb9e36..cc71f366d1cd 100644 --- a/include/net/sctp/sm.h +++ b/include/net/sctp/sm.h @@ -114,7 +114,6 @@ sctp_state_fn_t sctp_sf_do_4_C; sctp_state_fn_t sctp_sf_eat_data_6_2; sctp_state_fn_t sctp_sf_eat_data_fast_4_4; sctp_state_fn_t sctp_sf_eat_sack_6_2; -sctp_state_fn_t sctp_sf_tabort_8_4_8; sctp_state_fn_t sctp_sf_operr_notify; sctp_state_fn_t sctp_sf_t1_init_timer_expire; sctp_state_fn_t sctp_sf_t1_cookie_timer_expire; diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 5e7fb0f54b88..caed19d90d06 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -90,6 +90,11 @@ static sctp_disposition_t sctp_sf_shut_8_4_5(const struct sctp_endpoint *ep, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands); +static sctp_disposition_t sctp_sf_tabort_8_4_8(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands); static struct sctp_sackhdr *sctp_sm_pull_sack(struct sctp_chunk *chunk); static sctp_disposition_t sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands, @@ -98,6 +103,7 @@ static sctp_disposition_t sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands, struct sctp_transport *transport); static sctp_disposition_t sctp_sf_abort_violation( + const struct sctp_endpoint *ep, const struct sctp_association *asoc, void *arg, sctp_cmd_seq_t *commands, @@ -118,6 +124,13 @@ static sctp_disposition_t sctp_sf_violation_ctsn( void *arg, sctp_cmd_seq_t *commands); +static sctp_disposition_t sctp_sf_violation_chunk( + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands); + /* Small helper function that checks if the chunk length * is of the appropriate length. The 'required_length' argument * is set to be the size of a specific chunk we are testing. @@ -181,16 +194,21 @@ sctp_disposition_t sctp_sf_do_4_C(const struct sctp_endpoint *ep, struct sctp_chunk *chunk = arg; struct sctp_ulpevent *ev; + if (!sctp_vtag_verify_either(chunk, asoc)) + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + /* RFC 2960 6.10 Bundling * * An endpoint MUST NOT bundle INIT, INIT ACK or * SHUTDOWN COMPLETE with any other chunks. */ if (!chunk->singleton) - return SCTP_DISPOSITION_VIOLATION; + return sctp_sf_violation_chunk(ep, asoc, type, arg, commands); - if (!sctp_vtag_verify_either(chunk, asoc)) - return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + /* Make sure that the SHUTDOWN_COMPLETE chunk has a valid length. */ + if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t))) + return sctp_sf_violation_chunklen(ep, asoc, type, arg, + commands); /* RFC 2960 10.2 SCTP-to-ULP * @@ -450,17 +468,17 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep, if (!sctp_vtag_verify(chunk, asoc)) return sctp_sf_pdiscard(ep, asoc, type, arg, commands); - /* Make sure that the INIT-ACK chunk has a valid length */ - if (!sctp_chunk_length_valid(chunk, sizeof(sctp_initack_chunk_t))) - return sctp_sf_violation_chunklen(ep, asoc, type, arg, - commands); /* 6.10 Bundling * An endpoint MUST NOT bundle INIT, INIT ACK or * SHUTDOWN COMPLETE with any other chunks. */ if (!chunk->singleton) - return SCTP_DISPOSITION_VIOLATION; + return sctp_sf_violation_chunk(ep, asoc, type, arg, commands); + /* Make sure that the INIT-ACK chunk has a valid length */ + if (!sctp_chunk_length_valid(chunk, sizeof(sctp_initack_chunk_t))) + return sctp_sf_violation_chunklen(ep, asoc, type, arg, + commands); /* Grab the INIT header. */ chunk->subh.init_hdr = (sctp_inithdr_t *) chunk->skb->data; @@ -585,7 +603,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep, * control endpoint, respond with an ABORT. */ if (ep == sctp_sk((sctp_get_ctl_sock()))->ep) - return sctp_sf_ootb(ep, asoc, type, arg, commands); + return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands); /* Make sure that the COOKIE_ECHO chunk has a valid length. * In this case, we check that we have enough for at least a @@ -2496,6 +2514,11 @@ sctp_disposition_t sctp_sf_do_9_2_reshutack(const struct sctp_endpoint *ep, struct sctp_chunk *chunk = (struct sctp_chunk *) arg; struct sctp_chunk *reply; + /* Make sure that the chunk has a valid length */ + if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t))) + return sctp_sf_violation_chunklen(ep, asoc, type, arg, + commands); + /* Since we are not going to really process this INIT, there * is no point in verifying chunk boundries. Just generate * the SHUTDOWN ACK. @@ -2929,7 +2952,7 @@ sctp_disposition_t sctp_sf_eat_sack_6_2(const struct sctp_endpoint *ep, * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_tabort_8_4_8(const struct sctp_endpoint *ep, +static sctp_disposition_t sctp_sf_tabort_8_4_8(const struct sctp_endpoint *ep, const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, @@ -3126,14 +3149,14 @@ sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep, ch = (sctp_chunkhdr_t *) chunk->chunk_hdr; do { - /* Break out if chunk length is less then minimal. */ + /* Report violation if the chunk is less then minimal */ if (ntohs(ch->length) < sizeof(sctp_chunkhdr_t)) - break; - - ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length)); - if (ch_end > skb_tail_pointer(skb)) - break; + return sctp_sf_violation_chunklen(ep, asoc, type, arg, + commands); + /* Now that we know we at least have a chunk header, + * do things that are type appropriate. + */ if (SCTP_CID_SHUTDOWN_ACK == ch->type) ootb_shut_ack = 1; @@ -3145,6 +3168,12 @@ sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep, if (SCTP_CID_ABORT == ch->type) return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + /* Report violation if chunk len overflows */ + ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length)); + if (ch_end > skb_tail_pointer(skb)) + return sctp_sf_violation_chunklen(ep, asoc, type, arg, + commands); + ch = (sctp_chunkhdr_t *) ch_end; } while (ch_end < skb_tail_pointer(skb)); @@ -3244,6 +3273,13 @@ sctp_disposition_t sctp_sf_do_8_5_1_E_sa(const struct sctp_endpoint *ep, void *arg, sctp_cmd_seq_t *commands) { + struct sctp_chunk *chunk = arg; + + /* Make sure that the SHUTDOWN_ACK chunk has a valid length. */ + if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t))) + return sctp_sf_violation_chunklen(ep, asoc, type, arg, + commands); + /* Although we do have an association in this case, it corresponds * to a restarted association. So the packet is treated as an OOTB * packet and the state function that handles OOTB SHUTDOWN_ACK is @@ -3658,6 +3694,16 @@ sctp_disposition_t sctp_sf_discard_chunk(const struct sctp_endpoint *ep, void *arg, sctp_cmd_seq_t *commands) { + struct sctp_chunk *chunk = arg; + + /* Make sure that the chunk has a valid length. + * Since we don't know the chunk type, we use a general + * chunkhdr structure to make a comparison. + */ + if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t))) + return sctp_sf_violation_chunklen(ep, asoc, type, arg, + commands); + SCTP_DEBUG_PRINTK("Chunk %d is discarded\n", type.chunk); return SCTP_DISPOSITION_DISCARD; } @@ -3713,6 +3759,13 @@ sctp_disposition_t sctp_sf_violation(const struct sctp_endpoint *ep, void *arg, sctp_cmd_seq_t *commands) { + struct sctp_chunk *chunk = arg; + + /* Make sure that the chunk has a valid length. */ + if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t))) + return sctp_sf_violation_chunklen(ep, asoc, type, arg, + commands); + return SCTP_DISPOSITION_VIOLATION; } @@ -3720,12 +3773,14 @@ sctp_disposition_t sctp_sf_violation(const struct sctp_endpoint *ep, * Common function to handle a protocol violation. */ static sctp_disposition_t sctp_sf_abort_violation( + const struct sctp_endpoint *ep, const struct sctp_association *asoc, void *arg, sctp_cmd_seq_t *commands, const __u8 *payload, const size_t paylen) { + struct sctp_packet *packet = NULL; struct sctp_chunk *chunk = arg; struct sctp_chunk *abort = NULL; @@ -3734,30 +3789,51 @@ static sctp_disposition_t sctp_sf_abort_violation( if (!abort) goto nomem; - sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort)); - SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS); + if (asoc) { + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort)); + SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS); - if (asoc->state <= SCTP_STATE_COOKIE_ECHOED) { - sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, - SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT)); - sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, - SCTP_ERROR(ECONNREFUSED)); - sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, - SCTP_PERR(SCTP_ERROR_PROTO_VIOLATION)); + if (asoc->state <= SCTP_STATE_COOKIE_ECHOED) { + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, + SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT)); + sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, + SCTP_ERROR(ECONNREFUSED)); + sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, + SCTP_PERR(SCTP_ERROR_PROTO_VIOLATION)); + } else { + sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, + SCTP_ERROR(ECONNABORTED)); + sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, + SCTP_PERR(SCTP_ERROR_PROTO_VIOLATION)); + SCTP_DEC_STATS(SCTP_MIB_CURRESTAB); + } } else { - sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, - SCTP_ERROR(ECONNABORTED)); - sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, - SCTP_PERR(SCTP_ERROR_PROTO_VIOLATION)); - SCTP_DEC_STATS(SCTP_MIB_CURRESTAB); + packet = sctp_ootb_pkt_new(asoc, chunk); + + if (!packet) + goto nomem_pkt; + + if (sctp_test_T_bit(abort)) + packet->vtag = ntohl(chunk->sctp_hdr->vtag); + + abort->skb->sk = ep->base.sk; + + sctp_packet_append_chunk(packet, abort); + + sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT, + SCTP_PACKET(packet)); + + SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS); } - sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET, SCTP_NULL()); + sctp_sf_pdiscard(ep, asoc, SCTP_ST_CHUNK(0), arg, commands); SCTP_INC_STATS(SCTP_MIB_ABORTEDS); return SCTP_DISPOSITION_ABORT; +nomem_pkt: + sctp_chunk_free(abort); nomem: return SCTP_DISPOSITION_NOMEM; } @@ -3790,7 +3866,7 @@ static sctp_disposition_t sctp_sf_violation_chunklen( { char err_str[]="The following chunk had invalid length:"; - return sctp_sf_abort_violation(asoc, arg, commands, err_str, + return sctp_sf_abort_violation(ep, asoc, arg, commands, err_str, sizeof(err_str)); } @@ -3809,10 +3885,31 @@ static sctp_disposition_t sctp_sf_violation_ctsn( { char err_str[]="The cumulative tsn ack beyond the max tsn currently sent:"; - return sctp_sf_abort_violation(asoc, arg, commands, err_str, + return sctp_sf_abort_violation(ep, asoc, arg, commands, err_str, sizeof(err_str)); } +/* Handle protocol violation of an invalid chunk bundling. For example, + * when we have an association and we recieve bundled INIT-ACK, or + * SHUDOWN-COMPLETE, our peer is clearly violationg the "MUST NOT bundle" + * statement from the specs. Additinally, there might be an attacker + * on the path and we may not want to continue this communication. + */ +static sctp_disposition_t sctp_sf_violation_chunk( + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + char err_str[]="The following chunk violates protocol:"; + + if (!asoc) + return sctp_sf_violation(ep, asoc, type, arg, commands); + + return sctp_sf_abort_violation(ep, asoc, arg, commands, err_str, + sizeof(err_str)); +} /*************************************************************************** * These are the state functions for handling primitive (Section 10) events. ***************************************************************************/ diff --git a/net/sctp/sm_statetable.c b/net/sctp/sm_statetable.c index 70a91ece3c49..ddb0ba3974b0 100644 --- a/net/sctp/sm_statetable.c +++ b/net/sctp/sm_statetable.c @@ -110,7 +110,7 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, /* SCTP_STATE_EMPTY */ \ TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_CLOSED */ \ - TYPE_SCTP_FUNC(sctp_sf_tabort_8_4_8), \ + TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_COOKIE_WAIT */ \ TYPE_SCTP_FUNC(sctp_sf_discard_chunk), \ /* SCTP_STATE_COOKIE_ECHOED */ \ @@ -173,7 +173,7 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, /* SCTP_STATE_EMPTY */ \ TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_CLOSED */ \ - TYPE_SCTP_FUNC(sctp_sf_tabort_8_4_8), \ + TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_COOKIE_WAIT */ \ TYPE_SCTP_FUNC(sctp_sf_discard_chunk), \ /* SCTP_STATE_COOKIE_ECHOED */ \ @@ -194,7 +194,7 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, /* SCTP_STATE_EMPTY */ \ TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_CLOSED */ \ - TYPE_SCTP_FUNC(sctp_sf_tabort_8_4_8), \ + TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_COOKIE_WAIT */ \ TYPE_SCTP_FUNC(sctp_sf_discard_chunk), \ /* SCTP_STATE_COOKIE_ECHOED */ \ @@ -216,7 +216,7 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, /* SCTP_STATE_EMPTY */ \ TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_CLOSED */ \ - TYPE_SCTP_FUNC(sctp_sf_tabort_8_4_8), \ + TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_COOKIE_WAIT */ \ TYPE_SCTP_FUNC(sctp_sf_violation), \ /* SCTP_STATE_COOKIE_ECHOED */ \ @@ -258,7 +258,7 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, /* SCTP_STATE_EMPTY */ \ TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_CLOSED */ \ - TYPE_SCTP_FUNC(sctp_sf_tabort_8_4_8), \ + TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_COOKIE_WAIT */ \ TYPE_SCTP_FUNC(sctp_sf_discard_chunk), \ /* SCTP_STATE_COOKIE_ECHOED */ \ @@ -300,7 +300,7 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, /* SCTP_STATE_EMPTY */ \ TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_CLOSED */ \ - TYPE_SCTP_FUNC(sctp_sf_tabort_8_4_8), \ + TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_COOKIE_WAIT */ \ TYPE_SCTP_FUNC(sctp_sf_discard_chunk), \ /* SCTP_STATE_COOKIE_ECHOED */ \ @@ -499,7 +499,7 @@ static const sctp_sm_table_entry_t addip_chunk_event_table[SCTP_NUM_ADDIP_CHUNK_ /* SCTP_STATE_EMPTY */ \ TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_CLOSED */ \ - TYPE_SCTP_FUNC(sctp_sf_tabort_8_4_8), \ + TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_COOKIE_WAIT */ \ TYPE_SCTP_FUNC(sctp_sf_discard_chunk), \ /* SCTP_STATE_COOKIE_ECHOED */ \ @@ -528,7 +528,7 @@ chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = { /* SCTP_STATE_EMPTY */ TYPE_SCTP_FUNC(sctp_sf_ootb), /* SCTP_STATE_CLOSED */ - TYPE_SCTP_FUNC(sctp_sf_tabort_8_4_8), + TYPE_SCTP_FUNC(sctp_sf_ootb), /* SCTP_STATE_COOKIE_WAIT */ TYPE_SCTP_FUNC(sctp_sf_unk_chunk), /* SCTP_STATE_COOKIE_ECHOED */ -- cgit v1.2.3 From 3c77f961b55b6060858c68a213d7f4470d7f3eb2 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Mon, 17 Sep 2007 15:14:28 -0400 Subject: SCTP: Discard OOTB packetes with bundled INIT early. RFC 4460 and future RFC 4960 (2960-bis) specify that packets with bundled INIT chunks need to be dropped. We currenlty do that only after processing any leading chunks. For OOTB chunks, since we already walk the entire packet, we should discard packets with bundled INITs. There are other chunks chunks that MUST NOT be bundled, but the spec is silent on theire treatment. Thus, we'll leave their teatment alone for the moment. Signed-off-by: Vlad Yasevich Acked-by: Wei Yongjun --- net/sctp/input.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'net') diff --git a/net/sctp/input.c b/net/sctp/input.c index 47e56017f4ce..f9a0c9276e3b 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -622,6 +622,14 @@ static int sctp_rcv_ootb(struct sk_buff *skb) if (SCTP_CID_SHUTDOWN_COMPLETE == ch->type) goto discard; + /* RFC 4460, 2.11.2 + * This will discard packets with INIT chunk bundled as + * subsequent chunks in the packet. When INIT is first, + * the normal INIT processing will discard the chunk. + */ + if (SCTP_CID_INIT == ch->type && (void *)ch != skb->data) + goto discard; + /* RFC 8.4, 7) If the packet contains a "Stale cookie" ERROR * or a COOKIE ACK the SCTP Packet should be silently * discarded. -- cgit v1.2.3 From 6f4c618ddb0e6b7e6d49cfc8134e694be1c0bc9b Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 19 Sep 2007 17:19:52 +0800 Subject: SCTP : Add paramters validity check for ASCONF chunk If ADDIP is enabled, when an ASCONF chunk is received with ASCONF paramter length set to zero, this will cause infinite loop. By the way, if an malformed ASCONF chunk is received, will cause processing to access memory without verifying. This is because of not check the validity of parameters in ASCONF chunk. This patch fixed this. Signed-off-by: Wei Yongjun Signed-off-by: Vlad Yasevich --- include/net/sctp/sm.h | 3 +++ include/net/sctp/structs.h | 1 + net/sctp/sm_make_chunk.c | 46 ++++++++++++++++++++++++++++++++++++++++++ net/sctp/sm_statefuns.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 100 insertions(+) (limited to 'net') diff --git a/include/net/sctp/sm.h b/include/net/sctp/sm.h index cc71f366d1cd..e8e3a64eb322 100644 --- a/include/net/sctp/sm.h +++ b/include/net/sctp/sm.h @@ -246,6 +246,9 @@ struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *, int, __be16); struct sctp_chunk *sctp_make_asconf_set_prim(struct sctp_association *asoc, union sctp_addr *addr); +int sctp_verify_asconf(const struct sctp_association *asoc, + struct sctp_paramhdr *param_hdr, void *chunk_end, + struct sctp_paramhdr **errp); struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc, struct sctp_chunk *asconf); int sctp_process_asconf_ack(struct sctp_association *asoc, diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index c2fe2dcc9afc..490a2928817c 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -421,6 +421,7 @@ struct sctp_signed_cookie { * internally. */ union sctp_addr_param { + struct sctp_paramhdr p; struct sctp_ipv4addr_param v4; struct sctp_ipv6addr_param v6; }; diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 2e34220d94cd..23ae37ec8711 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -2499,6 +2499,52 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc, return SCTP_ERROR_NO_ERROR; } +/* Verify the ASCONF packet before we process it. */ +int sctp_verify_asconf(const struct sctp_association *asoc, + struct sctp_paramhdr *param_hdr, void *chunk_end, + struct sctp_paramhdr **errp) { + sctp_addip_param_t *asconf_param; + union sctp_params param; + int length, plen; + + param.v = (sctp_paramhdr_t *) param_hdr; + while (param.v <= chunk_end - sizeof(sctp_paramhdr_t)) { + length = ntohs(param.p->length); + *errp = param.p; + + if (param.v > chunk_end - length || + length < sizeof(sctp_paramhdr_t)) + return 0; + + switch (param.p->type) { + case SCTP_PARAM_ADD_IP: + case SCTP_PARAM_DEL_IP: + case SCTP_PARAM_SET_PRIMARY: + asconf_param = (sctp_addip_param_t *)param.v; + plen = ntohs(asconf_param->param_hdr.length); + if (plen < sizeof(sctp_addip_param_t) + + sizeof(sctp_paramhdr_t)) + return 0; + break; + case SCTP_PARAM_SUCCESS_REPORT: + case SCTP_PARAM_ADAPTATION_LAYER_IND: + if (length != sizeof(sctp_addip_param_t)) + return 0; + + break; + default: + break; + } + + param.v += WORD_ROUND(length); + } + + if (param.v != chunk_end) + return 0; + + return 1; +} + /* Process an incoming ASCONF chunk with the next expected serial no. and * return an ASCONF_ACK chunk to be sent in response. */ diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index caed19d90d06..a583d67cab63 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -117,6 +117,13 @@ static sctp_disposition_t sctp_sf_violation_chunklen( void *arg, sctp_cmd_seq_t *commands); +static sctp_disposition_t sctp_sf_violation_paramlen( + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands); + static sctp_disposition_t sctp_sf_violation_ctsn( const struct sctp_endpoint *ep, const struct sctp_association *asoc, @@ -3296,8 +3303,11 @@ sctp_disposition_t sctp_sf_do_asconf(const struct sctp_endpoint *ep, { struct sctp_chunk *chunk = arg; struct sctp_chunk *asconf_ack = NULL; + struct sctp_paramhdr *err_param = NULL; sctp_addiphdr_t *hdr; + union sctp_addr_param *addr_param; __u32 serial; + int length; if (!sctp_vtag_verify(chunk, asoc)) { sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG, @@ -3313,6 +3323,20 @@ sctp_disposition_t sctp_sf_do_asconf(const struct sctp_endpoint *ep, hdr = (sctp_addiphdr_t *)chunk->skb->data; serial = ntohl(hdr->serial); + addr_param = (union sctp_addr_param *)hdr->params; + length = ntohs(addr_param->p.length); + if (length < sizeof(sctp_paramhdr_t)) + return sctp_sf_violation_paramlen(ep, asoc, type, + (void *)addr_param, commands); + + /* Verify the ASCONF chunk before processing it. */ + if (!sctp_verify_asconf(asoc, + (sctp_paramhdr_t *)((void *)addr_param + length), + (void *)chunk->chunk_end, + &err_param)) + return sctp_sf_violation_paramlen(ep, asoc, type, + (void *)&err_param, commands); + /* ADDIP 4.2 C1) Compare the value of the serial number to the value * the endpoint stored in a new association variable * 'Peer-Serial-Number'. @@ -3367,6 +3391,7 @@ sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep, struct sctp_chunk *asconf_ack = arg; struct sctp_chunk *last_asconf = asoc->addip_last_asconf; struct sctp_chunk *abort; + struct sctp_paramhdr *err_param = NULL; sctp_addiphdr_t *addip_hdr; __u32 sent_serial, rcvd_serial; @@ -3384,6 +3409,14 @@ sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep, addip_hdr = (sctp_addiphdr_t *)asconf_ack->skb->data; rcvd_serial = ntohl(addip_hdr->serial); + /* Verify the ASCONF-ACK chunk before processing it. */ + if (!sctp_verify_asconf(asoc, + (sctp_paramhdr_t *)addip_hdr->params, + (void *)asconf_ack->chunk_end, + &err_param)) + return sctp_sf_violation_paramlen(ep, asoc, type, + (void *)&err_param, commands); + if (last_asconf) { addip_hdr = (sctp_addiphdr_t *)last_asconf->subh.addip_hdr; sent_serial = ntohl(addip_hdr->serial); @@ -3870,6 +3903,23 @@ static sctp_disposition_t sctp_sf_violation_chunklen( sizeof(err_str)); } +/* + * Handle a protocol violation when the parameter length is invalid. + * "Invalid" length is identified as smaller then the minimal length a + * given parameter can be. + */ +static sctp_disposition_t sctp_sf_violation_paramlen( + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { + char err_str[] = "The following parameter had invalid length:"; + + return sctp_sf_abort_violation(ep, asoc, arg, commands, err_str, + sizeof(err_str)); +} + /* Handle a protocol violation when the peer trying to advance the * cumulative tsn ack to a point beyond the max tsn currently sent. * -- cgit v1.2.3