diff options
Diffstat (limited to 'net/sctp')
-rw-r--r-- | net/sctp/input.c | 76 | ||||
-rw-r--r-- | net/sctp/inqueue.c | 4 | ||||
-rw-r--r-- | net/sctp/ipv6.c | 26 | ||||
-rw-r--r-- | net/sctp/proc.c | 32 | ||||
-rw-r--r-- | net/sctp/sm_make_chunk.c | 18 | ||||
-rw-r--r-- | net/sctp/sm_sideeffect.c | 7 | ||||
-rw-r--r-- | net/sctp/sm_statefuns.c | 6 | ||||
-rw-r--r-- | net/sctp/socket.c | 11 | ||||
-rw-r--r-- | net/sctp/sysctl.c | 7 | ||||
-rw-r--r-- | net/sctp/transport.c | 2 |
10 files changed, 120 insertions, 69 deletions
diff --git a/net/sctp/input.c b/net/sctp/input.c index 238f1bffa684..cb78b50868ee 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -225,6 +225,7 @@ int sctp_rcv(struct sk_buff *skb) if (!xfrm_policy_check(sk, XFRM_POLICY_IN, skb, family)) goto discard_release; + nf_reset(skb); ret = sk_filter(sk, skb, 1); if (ret) @@ -256,20 +257,26 @@ int sctp_rcv(struct sk_buff *skb) */ sctp_bh_lock_sock(sk); + /* It is possible that the association could have moved to a different + * socket if it is peeled off. If so, update the sk. + */ + if (sk != rcvr->sk) { + sctp_bh_lock_sock(rcvr->sk); + sctp_bh_unlock_sock(sk); + sk = rcvr->sk; + } + if (sock_owned_by_user(sk)) sk_add_backlog(sk, skb); else sctp_backlog_rcv(sk, skb); - /* Release the sock and any reference counts we took in the - * lookup calls. + /* Release the sock and the sock ref we took in the lookup calls. + * The asoc/ep ref will be released in sctp_backlog_rcv. */ sctp_bh_unlock_sock(sk); - if (asoc) - sctp_association_put(asoc); - else - sctp_endpoint_put(ep); sock_put(sk); + return ret; discard_it: @@ -295,12 +302,50 @@ discard_release: int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb) { struct sctp_chunk *chunk = SCTP_INPUT_CB(skb)->chunk; - struct sctp_inq *inqueue = &chunk->rcvr->inqueue; - - sctp_inq_push(inqueue, chunk); + struct sctp_inq *inqueue = NULL; + struct sctp_ep_common *rcvr = NULL; + + rcvr = chunk->rcvr; + + BUG_TRAP(rcvr->sk == sk); + + if (rcvr->dead) { + sctp_chunk_free(chunk); + } else { + inqueue = &chunk->rcvr->inqueue; + sctp_inq_push(inqueue, chunk); + } + + /* Release the asoc/ep ref we took in the lookup calls in sctp_rcv. */ + if (SCTP_EP_TYPE_ASSOCIATION == rcvr->type) + sctp_association_put(sctp_assoc(rcvr)); + else + sctp_endpoint_put(sctp_ep(rcvr)); + return 0; } +void sctp_backlog_migrate(struct sctp_association *assoc, + struct sock *oldsk, struct sock *newsk) +{ + struct sk_buff *skb; + struct sctp_chunk *chunk; + + skb = oldsk->sk_backlog.head; + oldsk->sk_backlog.head = oldsk->sk_backlog.tail = NULL; + while (skb != NULL) { + struct sk_buff *next = skb->next; + + chunk = SCTP_INPUT_CB(skb)->chunk; + skb->next = NULL; + if (&assoc->base == chunk->rcvr) + sk_add_backlog(newsk, skb); + else + sk_add_backlog(oldsk, skb); + skb = next; + } +} + /* Handle icmp frag needed error. */ void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc, struct sctp_transport *t, __u32 pmtu) @@ -543,10 +588,16 @@ int sctp_rcv_ootb(struct sk_buff *skb) sctp_errhdr_t *err; ch = (sctp_chunkhdr_t *) skb->data; - ch_end = ((__u8 *) ch) + WORD_ROUND(ntohs(ch->length)); /* Scan through all the chunks in the packet. */ - while (ch_end > (__u8 *)ch && ch_end < skb->tail) { + do { + /* Break out if chunk length 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) + break; /* RFC 8.4, 2) If the OOTB packet contains an ABORT chunk, the * receiver MUST silently discard the OOTB packet and take no @@ -577,8 +628,7 @@ int sctp_rcv_ootb(struct sk_buff *skb) } ch = (sctp_chunkhdr_t *) ch_end; - ch_end = ((__u8 *) ch) + WORD_ROUND(ntohs(ch->length)); - } + } while (ch_end < skb->tail); return 0; diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c index 2d33922c044b..297b8951463e 100644 --- a/net/sctp/inqueue.c +++ b/net/sctp/inqueue.c @@ -73,8 +73,10 @@ void sctp_inq_free(struct sctp_inq *queue) /* If there is a packet which is currently being worked on, * free it as well. */ - if (queue->in_progress) + if (queue->in_progress) { sctp_chunk_free(queue->in_progress); + queue->in_progress = NULL; + } if (queue->malloced) { /* Dump the master memory segment. */ diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 15c05165c905..2e266129a764 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -180,8 +180,7 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport, } SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, " - "src:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x " - "dst:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", + "src:" NIP6_FMT " dst:" NIP6_FMT "\n", __FUNCTION__, skb, skb->len, NIP6(fl.fl6_src), NIP6(fl.fl6_dst)); @@ -206,13 +205,13 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc, fl.oif = daddr->v6.sin6_scope_id; - SCTP_DEBUG_PRINTK("%s: DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", + SCTP_DEBUG_PRINTK("%s: DST=" NIP6_FMT " ", __FUNCTION__, NIP6(fl.fl6_dst)); if (saddr) { ipv6_addr_copy(&fl.fl6_src, &saddr->v6.sin6_addr); SCTP_DEBUG_PRINTK( - "SRC=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x - ", + "SRC=" NIP6_FMT " - ", NIP6(fl.fl6_src)); } @@ -221,8 +220,7 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc, struct rt6_info *rt; rt = (struct rt6_info *)dst; SCTP_DEBUG_PRINTK( - "rt6_dst:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x " - "rt6_src:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", + "rt6_dst:" NIP6_FMT " rt6_src:" NIP6_FMT "\n", NIP6(rt->rt6i_dst.addr), NIP6(rt->rt6i_src.addr)); } else { SCTP_DEBUG_PRINTK("NO ROUTE\n"); @@ -271,13 +269,12 @@ static void sctp_v6_get_saddr(struct sctp_association *asoc, __u8 bmatchlen; SCTP_DEBUG_PRINTK("%s: asoc:%p dst:%p " - "daddr:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", + "daddr:" NIP6_FMT " ", __FUNCTION__, asoc, dst, NIP6(daddr->v6.sin6_addr)); if (!asoc) { ipv6_get_saddr(dst, &daddr->v6.sin6_addr,&saddr->v6.sin6_addr); - SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: " - "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", + SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: " NIP6_FMT "\n", NIP6(saddr->v6.sin6_addr)); return; } @@ -305,13 +302,11 @@ static void sctp_v6_get_saddr(struct sctp_association *asoc, if (baddr) { memcpy(saddr, baddr, sizeof(union sctp_addr)); - SCTP_DEBUG_PRINTK("saddr: " - "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", + SCTP_DEBUG_PRINTK("saddr: " NIP6_FMT "\n", NIP6(saddr->v6.sin6_addr)); } else { printk(KERN_ERR "%s: asoc:%p Could not find a valid source " - "address for the " - "dest:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", + "address for the dest:" NIP6_FMT "\n", __FUNCTION__, asoc, NIP6(daddr->v6.sin6_addr)); } @@ -675,8 +670,7 @@ static int sctp_v6_is_ce(const struct sk_buff *skb) /* Dump the v6 addr to the seq file. */ static void sctp_v6_seq_dump_addr(struct seq_file *seq, union sctp_addr *addr) { - seq_printf(seq, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", - NIP6(addr->v6.sin6_addr)); + seq_printf(seq, NIP6_FMT " ", NIP6(addr->v6.sin6_addr)); } /* Initialize a PF_INET6 socket msg_name. */ @@ -905,7 +899,7 @@ static struct inet_protosw sctpv6_stream_protosw = { .flags = SCTP_PROTOSW_FLAG, }; -static int sctp6_rcv(struct sk_buff **pskb, unsigned int *nhoffp) +static int sctp6_rcv(struct sk_buff **pskb) { return sctp_rcv(*pskb) ? -1 : 0; } diff --git a/net/sctp/proc.c b/net/sctp/proc.c index 6e4dc28874d7..d47a52c303a8 100644 --- a/net/sctp/proc.c +++ b/net/sctp/proc.c @@ -176,7 +176,7 @@ static void sctp_seq_dump_remote_addrs(struct seq_file *seq, struct sctp_associa static void * sctp_eps_seq_start(struct seq_file *seq, loff_t *pos) { - if (*pos > sctp_ep_hashsize) + if (*pos >= sctp_ep_hashsize) return NULL; if (*pos < 0) @@ -185,8 +185,6 @@ static void * sctp_eps_seq_start(struct seq_file *seq, loff_t *pos) if (*pos == 0) seq_printf(seq, " ENDPT SOCK STY SST HBKT LPORT UID INODE LADDRS\n"); - ++*pos; - return (void *)pos; } @@ -198,11 +196,9 @@ static void sctp_eps_seq_stop(struct seq_file *seq, void *v) static void * sctp_eps_seq_next(struct seq_file *seq, void *v, loff_t *pos) { - if (*pos > sctp_ep_hashsize) + if (++*pos >= sctp_ep_hashsize) return NULL; - ++*pos; - return pos; } @@ -214,19 +210,19 @@ static int sctp_eps_seq_show(struct seq_file *seq, void *v) struct sctp_ep_common *epb; struct sctp_endpoint *ep; struct sock *sk; - int hash = *(int *)v; + int hash = *(loff_t *)v; - if (hash > sctp_ep_hashsize) + if (hash >= sctp_ep_hashsize) return -ENOMEM; - head = &sctp_ep_hashtable[hash-1]; + head = &sctp_ep_hashtable[hash]; sctp_local_bh_disable(); read_lock(&head->lock); for (epb = head->chain; epb; epb = epb->next) { ep = sctp_ep(epb); sk = epb->sk; seq_printf(seq, "%8p %8p %-3d %-3d %-4d %-5d %5d %5lu ", ep, sk, - sctp_sk(sk)->type, sk->sk_state, hash-1, + sctp_sk(sk)->type, sk->sk_state, hash, epb->bind_addr.port, sock_i_uid(sk), sock_i_ino(sk)); @@ -283,7 +279,7 @@ void sctp_eps_proc_exit(void) static void * sctp_assocs_seq_start(struct seq_file *seq, loff_t *pos) { - if (*pos > sctp_assoc_hashsize) + if (*pos >= sctp_assoc_hashsize) return NULL; if (*pos < 0) @@ -293,8 +289,6 @@ static void * sctp_assocs_seq_start(struct seq_file *seq, loff_t *pos) seq_printf(seq, " ASSOC SOCK STY SST ST HBKT ASSOC-ID TX_QUEUE RX_QUEUE UID INODE LPORT " "RPORT LADDRS <-> RADDRS\n"); - ++*pos; - return (void *)pos; } @@ -306,11 +300,9 @@ static void sctp_assocs_seq_stop(struct seq_file *seq, void *v) static void * sctp_assocs_seq_next(struct seq_file *seq, void *v, loff_t *pos) { - if (*pos > sctp_assoc_hashsize) + if (++*pos >= sctp_assoc_hashsize) return NULL; - ++*pos; - return pos; } @@ -321,12 +313,12 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v) struct sctp_ep_common *epb; struct sctp_association *assoc; struct sock *sk; - int hash = *(int *)v; + int hash = *(loff_t *)v; - if (hash > sctp_assoc_hashsize) + if (hash >= sctp_assoc_hashsize) return -ENOMEM; - head = &sctp_assoc_hashtable[hash-1]; + head = &sctp_assoc_hashtable[hash]; sctp_local_bh_disable(); read_lock(&head->lock); for (epb = head->chain; epb; epb = epb->next) { @@ -335,7 +327,7 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v) seq_printf(seq, "%8p %8p %-3d %-3d %-2d %-4d %4d %8d %8d %7d %5lu %-5d %5d ", assoc, sk, sctp_sk(sk)->type, sk->sk_state, - assoc->state, hash-1, assoc->assoc_id, + assoc->state, hash, assoc->assoc_id, (sk->sk_rcvbuf - assoc->rwnd), assoc->sndbuf_used, sock_i_uid(sk), sock_i_ino(sk), diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index f9573eba5c7a..5e0de3c0eead 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -1275,7 +1275,12 @@ static sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep, unsigned int keylen; char *key; - headersize = sizeof(sctp_paramhdr_t) + SCTP_SECRET_SIZE; + /* Header size is static data prior to the actual cookie, including + * any padding. + */ + headersize = sizeof(sctp_paramhdr_t) + + (sizeof(struct sctp_signed_cookie) - + sizeof(struct sctp_cookie)); bodysize = sizeof(struct sctp_cookie) + ntohs(init_chunk->chunk_hdr->length) + addrs_len; @@ -1287,7 +1292,7 @@ static sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep, - (bodysize % SCTP_COOKIE_MULTIPLE); *cookie_len = headersize + bodysize; - retval = (sctp_cookie_param_t *)kmalloc(*cookie_len, GFP_ATOMIC); + retval = kmalloc(*cookie_len, GFP_ATOMIC); if (!retval) { *cookie_len = 0; @@ -1354,7 +1359,7 @@ struct sctp_association *sctp_unpack_cookie( struct sctp_signed_cookie *cookie; struct sctp_cookie *bear_cookie; int headersize, bodysize, fixed_size; - __u8 digest[SCTP_SIGNATURE_SIZE]; + __u8 *digest = ep->digest; struct scatterlist sg; unsigned int keylen, len; char *key; @@ -1362,7 +1367,12 @@ struct sctp_association *sctp_unpack_cookie( struct sk_buff *skb = chunk->skb; struct timeval tv; - headersize = sizeof(sctp_chunkhdr_t) + SCTP_SECRET_SIZE; + /* Header size is static data prior to the actual cookie, including + * any padding. + */ + headersize = sizeof(sctp_chunkhdr_t) + + (sizeof(struct sctp_signed_cookie) - + sizeof(struct sctp_cookie)); bodysize = ntohs(chunk->chunk_hdr->length) - headersize; fixed_size = headersize + sizeof(struct sctp_cookie); diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 2d7d8a5db2ac..8d1dc24bab4c 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -1250,8 +1250,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, case SCTP_CMD_TIMER_START: timer = &asoc->timers[cmd->obj.to]; timeout = asoc->timeouts[cmd->obj.to]; - if (!timeout) - BUG(); + BUG_ON(!timeout); timer->expires = jiffies + timeout; sctp_association_hold(asoc); @@ -1301,7 +1300,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, "T1 INIT Timeout adjustment" " init_err_counter: %d" " cycle: %d" - " timeout: %d\n", + " timeout: %ld\n", asoc->init_err_counter, asoc->init_cycle, asoc->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT]); @@ -1329,7 +1328,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, SCTP_DEBUG_PRINTK( "T1 COOKIE Timeout adjustment" " init_err_counter: %d" - " timeout: %d\n", + " timeout: %ld\n", asoc->init_err_counter, asoc->timeouts[SCTP_EVENT_TIMEOUT_T1_COOKIE]); diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 557a7d90b92a..71c9a961c321 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -1036,14 +1036,14 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const struct sctp_endpoint *ep, if (from_addr.sa.sa_family == AF_INET6) { printk(KERN_WARNING "%s association %p could not find address " - "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", + NIP6_FMT "\n", __FUNCTION__, asoc, NIP6(from_addr.v6.sin6_addr)); } else { printk(KERN_WARNING "%s association %p could not find address " - "%u.%u.%u.%u\n", + NIPQUAD_FMT "\n", __FUNCTION__, asoc, NIPQUAD(from_addr.v4.sin_addr.s_addr)); @@ -3090,6 +3090,8 @@ sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep, break; ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length)); + if (ch_end > skb->tail) + break; if (SCTP_CID_SHUTDOWN_ACK == ch->type) ootb_shut_ack = 1; diff --git a/net/sctp/socket.c b/net/sctp/socket.c index fc04d185fa33..fb1821d9f338 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -63,6 +63,7 @@ #include <linux/wait.h> #include <linux/time.h> #include <linux/ip.h> +#include <linux/capability.h> #include <linux/fcntl.h> #include <linux/poll.h> #include <linux/init.h> @@ -860,7 +861,7 @@ SCTP_STATIC int sctp_setsockopt_bindx(struct sock* sk, return -EFAULT; /* Alloc space for the address array in kernel memory. */ - kaddrs = (struct sockaddr *)kmalloc(addrs_size, GFP_KERNEL); + kaddrs = kmalloc(addrs_size, GFP_KERNEL); if (unlikely(!kaddrs)) return -ENOMEM; @@ -1150,7 +1151,7 @@ SCTP_STATIC int sctp_setsockopt_connectx(struct sock* sk, return -EFAULT; /* Alloc space for the address array in kernel memory. */ - kaddrs = (struct sockaddr *)kmalloc(addrs_size, GFP_KERNEL); + kaddrs = kmalloc(addrs_size, GFP_KERNEL); if (unlikely(!kaddrs)) return -ENOMEM; @@ -2994,7 +2995,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) sp->hbinterval = jiffies_to_msecs(sctp_hb_interval); sp->pathmaxrxt = sctp_max_retrans_path; sp->pathmtu = 0; // allow default discovery - sp->sackdelay = sctp_sack_timeout; + sp->sackdelay = jiffies_to_msecs(sctp_sack_timeout); sp->param_flags = SPP_HB_ENABLE | SPP_PMTUD_ENABLE | SPP_SACKDELAY_ENABLE; @@ -5601,8 +5602,12 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, */ newsp->type = type; + spin_lock_bh(&oldsk->sk_lock.slock); + /* Migrate the backlog from oldsk to newsk. */ + sctp_backlog_migrate(assoc, oldsk, newsk); /* Migrate the association to the new socket. */ sctp_assoc_migrate(assoc, newsk); + spin_unlock_bh(&oldsk->sk_lock.slock); /* If the association on the newsk is already closed before accept() * is called, set RCV_SHUTDOWN flag. diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c index fcd7096c953d..dc6f3ff32358 100644 --- a/net/sctp/sysctl.c +++ b/net/sctp/sysctl.c @@ -159,12 +159,9 @@ static ctl_table sctp_table[] = { .ctl_name = NET_SCTP_PRESERVE_ENABLE, .procname = "cookie_preserve_enable", .data = &sctp_cookie_preserve_enable, - .maxlen = sizeof(long), + .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_doulongvec_ms_jiffies_minmax, - .strategy = &sctp_sysctl_jiffies_ms, - .extra1 = &rto_timer_min, - .extra2 = &rto_timer_max + .proc_handler = &proc_dointvec }, { .ctl_name = NET_SCTP_RTO_ALPHA, diff --git a/net/sctp/transport.c b/net/sctp/transport.c index 68d73e2dd155..160f62ad1cc5 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c @@ -350,7 +350,7 @@ void sctp_transport_update_rto(struct sctp_transport *tp, __u32 rtt) tp->rto_pending = 0; SCTP_DEBUG_PRINTK("%s: transport: %p, rtt: %d, srtt: %d " - "rttvar: %d, rto: %d\n", __FUNCTION__, + "rttvar: %d, rto: %ld\n", __FUNCTION__, tp, rtt, tp->srtt, tp->rttvar, tp->rto); } |