diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-18 12:31:37 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-18 12:31:37 -0400 |
commit | 2e923b0251932ad4a82cc87ec1443a1f1d17073e (patch) | |
tree | d12032bc9bcfbb8a57659275d1b9b582f23f2ecc /net/sctp | |
parent | ffd8221bc348f8c282d1271883dbe629ea8ae289 (diff) | |
parent | f2d9da1a8375cbe53df5b415d059429013a3a79f (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
Pull networking fixes from David Miller:
1) Include fixes for netrom and dsa (Fabian Frederick and Florian
Fainelli)
2) Fix FIXED_PHY support in stmmac, from Giuseppe CAVALLARO.
3) Several SKB use after free fixes (vxlan, openvswitch, vxlan,
ip_tunnel, fou), from Li ROngQing.
4) fec driver PTP support fixes from Luwei Zhou and Nimrod Andy.
5) Use after free in virtio_net, from Michael S Tsirkin.
6) Fix flow mask handling for megaflows in openvswitch, from Pravin B
Shelar.
7) ISDN gigaset and capi bug fixes from Tilman Schmidt.
8) Fix route leak in ip_send_unicast_reply(), from Vasily Averin.
9) Fix two eBPF JIT bugs on x86, from Alexei Starovoitov.
10) TCP_SKB_CB() reorganization caused a few regressions, fixed by Cong
Wang and Eric Dumazet.
11) Don't overwrite end of SKB when parsing malformed sctp ASCONF
chunks, from Daniel Borkmann.
12) Don't call sock_kfree_s() with NULL pointers, this function also has
the side effect of adjusting the socket memory usage. From Cong Wang.
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net: (90 commits)
bna: fix skb->truesize underestimation
net: dsa: add includes for ethtool and phy_fixed definitions
openvswitch: Set flow-key members.
netrom: use linux/uaccess.h
dsa: Fix conversion from host device to mii bus
tipc: fix bug in bundled buffer reception
ipv6: introduce tcp_v6_iif()
sfc: add support for skb->xmit_more
r8152: return -EBUSY for runtime suspend
ipv4: fix a potential use after free in fou.c
ipv4: fix a potential use after free in ip_tunnel_core.c
hyperv: Add handling of IP header with option field in netvsc_set_hash()
openvswitch: Create right mask with disabled megaflows
vxlan: fix a free after use
openvswitch: fix a use after free
ipv4: dst_entry leak in ip_send_unicast_reply()
ipv4: clean up cookie_v4_check()
ipv4: share tcp_v4_save_options() with cookie_v4_check()
ipv4: call __ip_options_echo() in cookie_v4_check()
atm: simplify lanai.c by using module_pci_driver
...
Diffstat (limited to 'net/sctp')
-rw-r--r-- | net/sctp/associola.c | 2 | ||||
-rw-r--r-- | net/sctp/inqueue.c | 33 | ||||
-rw-r--r-- | net/sctp/sm_make_chunk.c | 99 | ||||
-rw-r--r-- | net/sctp/sm_statefuns.c | 21 |
4 files changed, 69 insertions, 86 deletions
diff --git a/net/sctp/associola.c b/net/sctp/associola.c index a88b8524846e..f791edd64d6c 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c | |||
@@ -1668,6 +1668,8 @@ struct sctp_chunk *sctp_assoc_lookup_asconf_ack( | |||
1668 | * ack chunk whose serial number matches that of the request. | 1668 | * ack chunk whose serial number matches that of the request. |
1669 | */ | 1669 | */ |
1670 | list_for_each_entry(ack, &asoc->asconf_ack_list, transmitted_list) { | 1670 | list_for_each_entry(ack, &asoc->asconf_ack_list, transmitted_list) { |
1671 | if (sctp_chunk_pending(ack)) | ||
1672 | continue; | ||
1671 | if (ack->subh.addip_hdr->serial == serial) { | 1673 | if (ack->subh.addip_hdr->serial == serial) { |
1672 | sctp_chunk_hold(ack); | 1674 | sctp_chunk_hold(ack); |
1673 | return ack; | 1675 | return ack; |
diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c index 4de12afa13d4..7e8a16c77039 100644 --- a/net/sctp/inqueue.c +++ b/net/sctp/inqueue.c | |||
@@ -140,18 +140,9 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue) | |||
140 | } else { | 140 | } else { |
141 | /* Nothing to do. Next chunk in the packet, please. */ | 141 | /* Nothing to do. Next chunk in the packet, please. */ |
142 | ch = (sctp_chunkhdr_t *) chunk->chunk_end; | 142 | ch = (sctp_chunkhdr_t *) chunk->chunk_end; |
143 | |||
144 | /* Force chunk->skb->data to chunk->chunk_end. */ | 143 | /* Force chunk->skb->data to chunk->chunk_end. */ |
145 | skb_pull(chunk->skb, | 144 | skb_pull(chunk->skb, chunk->chunk_end - chunk->skb->data); |
146 | chunk->chunk_end - chunk->skb->data); | 145 | /* We are guaranteed to pull a SCTP header. */ |
147 | |||
148 | /* Verify that we have at least chunk headers | ||
149 | * worth of buffer left. | ||
150 | */ | ||
151 | if (skb_headlen(chunk->skb) < sizeof(sctp_chunkhdr_t)) { | ||
152 | sctp_chunk_free(chunk); | ||
153 | chunk = queue->in_progress = NULL; | ||
154 | } | ||
155 | } | 146 | } |
156 | } | 147 | } |
157 | 148 | ||
@@ -187,24 +178,14 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue) | |||
187 | skb_pull(chunk->skb, sizeof(sctp_chunkhdr_t)); | 178 | skb_pull(chunk->skb, sizeof(sctp_chunkhdr_t)); |
188 | chunk->subh.v = NULL; /* Subheader is no longer valid. */ | 179 | chunk->subh.v = NULL; /* Subheader is no longer valid. */ |
189 | 180 | ||
190 | if (chunk->chunk_end < skb_tail_pointer(chunk->skb)) { | 181 | if (chunk->chunk_end + sizeof(sctp_chunkhdr_t) < |
182 | skb_tail_pointer(chunk->skb)) { | ||
191 | /* This is not a singleton */ | 183 | /* This is not a singleton */ |
192 | chunk->singleton = 0; | 184 | chunk->singleton = 0; |
193 | } else if (chunk->chunk_end > skb_tail_pointer(chunk->skb)) { | 185 | } else if (chunk->chunk_end > skb_tail_pointer(chunk->skb)) { |
194 | /* RFC 2960, Section 6.10 Bundling | 186 | /* Discard inside state machine. */ |
195 | * | 187 | chunk->pdiscard = 1; |
196 | * Partial chunks MUST NOT be placed in an SCTP packet. | 188 | chunk->chunk_end = skb_tail_pointer(chunk->skb); |
197 | * If the receiver detects a partial chunk, it MUST drop | ||
198 | * the chunk. | ||
199 | * | ||
200 | * Since the end of the chunk is past the end of our buffer | ||
201 | * (which contains the whole packet, we can freely discard | ||
202 | * the whole packet. | ||
203 | */ | ||
204 | sctp_chunk_free(chunk); | ||
205 | chunk = queue->in_progress = NULL; | ||
206 | |||
207 | return NULL; | ||
208 | } else { | 189 | } else { |
209 | /* We are at the end of the packet, so mark the chunk | 190 | /* We are at the end of the packet, so mark the chunk |
210 | * in case we need to send a SACK. | 191 | * in case we need to send a SACK. |
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index ae0e616a7ca5..ab734be8cb20 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c | |||
@@ -3110,50 +3110,63 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc, | |||
3110 | return SCTP_ERROR_NO_ERROR; | 3110 | return SCTP_ERROR_NO_ERROR; |
3111 | } | 3111 | } |
3112 | 3112 | ||
3113 | /* Verify the ASCONF packet before we process it. */ | 3113 | /* Verify the ASCONF packet before we process it. */ |
3114 | int sctp_verify_asconf(const struct sctp_association *asoc, | 3114 | bool sctp_verify_asconf(const struct sctp_association *asoc, |
3115 | struct sctp_paramhdr *param_hdr, void *chunk_end, | 3115 | struct sctp_chunk *chunk, bool addr_param_needed, |
3116 | struct sctp_paramhdr **errp) { | 3116 | struct sctp_paramhdr **errp) |
3117 | sctp_addip_param_t *asconf_param; | 3117 | { |
3118 | sctp_addip_chunk_t *addip = (sctp_addip_chunk_t *) chunk->chunk_hdr; | ||
3118 | union sctp_params param; | 3119 | union sctp_params param; |
3119 | int length, plen; | 3120 | bool addr_param_seen = false; |
3120 | |||
3121 | param.v = (sctp_paramhdr_t *) param_hdr; | ||
3122 | while (param.v <= chunk_end - sizeof(sctp_paramhdr_t)) { | ||
3123 | length = ntohs(param.p->length); | ||
3124 | *errp = param.p; | ||
3125 | 3121 | ||
3126 | if (param.v > chunk_end - length || | 3122 | sctp_walk_params(param, addip, addip_hdr.params) { |
3127 | length < sizeof(sctp_paramhdr_t)) | 3123 | size_t length = ntohs(param.p->length); |
3128 | return 0; | ||
3129 | 3124 | ||
3125 | *errp = param.p; | ||
3130 | switch (param.p->type) { | 3126 | switch (param.p->type) { |
3127 | case SCTP_PARAM_ERR_CAUSE: | ||
3128 | break; | ||
3129 | case SCTP_PARAM_IPV4_ADDRESS: | ||
3130 | if (length != sizeof(sctp_ipv4addr_param_t)) | ||
3131 | return false; | ||
3132 | addr_param_seen = true; | ||
3133 | break; | ||
3134 | case SCTP_PARAM_IPV6_ADDRESS: | ||
3135 | if (length != sizeof(sctp_ipv6addr_param_t)) | ||
3136 | return false; | ||
3137 | addr_param_seen = true; | ||
3138 | break; | ||
3131 | case SCTP_PARAM_ADD_IP: | 3139 | case SCTP_PARAM_ADD_IP: |
3132 | case SCTP_PARAM_DEL_IP: | 3140 | case SCTP_PARAM_DEL_IP: |
3133 | case SCTP_PARAM_SET_PRIMARY: | 3141 | case SCTP_PARAM_SET_PRIMARY: |
3134 | asconf_param = (sctp_addip_param_t *)param.v; | 3142 | /* In ASCONF chunks, these need to be first. */ |
3135 | plen = ntohs(asconf_param->param_hdr.length); | 3143 | if (addr_param_needed && !addr_param_seen) |
3136 | if (plen < sizeof(sctp_addip_param_t) + | 3144 | return false; |
3137 | sizeof(sctp_paramhdr_t)) | 3145 | length = ntohs(param.addip->param_hdr.length); |
3138 | return 0; | 3146 | if (length < sizeof(sctp_addip_param_t) + |
3147 | sizeof(sctp_paramhdr_t)) | ||
3148 | return false; | ||
3139 | break; | 3149 | break; |
3140 | case SCTP_PARAM_SUCCESS_REPORT: | 3150 | case SCTP_PARAM_SUCCESS_REPORT: |
3141 | case SCTP_PARAM_ADAPTATION_LAYER_IND: | 3151 | case SCTP_PARAM_ADAPTATION_LAYER_IND: |
3142 | if (length != sizeof(sctp_addip_param_t)) | 3152 | if (length != sizeof(sctp_addip_param_t)) |
3143 | return 0; | 3153 | return false; |
3144 | |||
3145 | break; | 3154 | break; |
3146 | default: | 3155 | default: |
3147 | break; | 3156 | /* This is unkown to us, reject! */ |
3157 | return false; | ||
3148 | } | 3158 | } |
3149 | |||
3150 | param.v += WORD_ROUND(length); | ||
3151 | } | 3159 | } |
3152 | 3160 | ||
3153 | if (param.v != chunk_end) | 3161 | /* Remaining sanity checks. */ |
3154 | return 0; | 3162 | if (addr_param_needed && !addr_param_seen) |
3163 | return false; | ||
3164 | if (!addr_param_needed && addr_param_seen) | ||
3165 | return false; | ||
3166 | if (param.v != chunk->chunk_end) | ||
3167 | return false; | ||
3155 | 3168 | ||
3156 | return 1; | 3169 | return true; |
3157 | } | 3170 | } |
3158 | 3171 | ||
3159 | /* Process an incoming ASCONF chunk with the next expected serial no. and | 3172 | /* Process an incoming ASCONF chunk with the next expected serial no. and |
@@ -3162,16 +3175,17 @@ int sctp_verify_asconf(const struct sctp_association *asoc, | |||
3162 | struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc, | 3175 | struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc, |
3163 | struct sctp_chunk *asconf) | 3176 | struct sctp_chunk *asconf) |
3164 | { | 3177 | { |
3178 | sctp_addip_chunk_t *addip = (sctp_addip_chunk_t *) asconf->chunk_hdr; | ||
3179 | bool all_param_pass = true; | ||
3180 | union sctp_params param; | ||
3165 | sctp_addiphdr_t *hdr; | 3181 | sctp_addiphdr_t *hdr; |
3166 | union sctp_addr_param *addr_param; | 3182 | union sctp_addr_param *addr_param; |
3167 | sctp_addip_param_t *asconf_param; | 3183 | sctp_addip_param_t *asconf_param; |
3168 | struct sctp_chunk *asconf_ack; | 3184 | struct sctp_chunk *asconf_ack; |
3169 | |||
3170 | __be16 err_code; | 3185 | __be16 err_code; |
3171 | int length = 0; | 3186 | int length = 0; |
3172 | int chunk_len; | 3187 | int chunk_len; |
3173 | __u32 serial; | 3188 | __u32 serial; |
3174 | int all_param_pass = 1; | ||
3175 | 3189 | ||
3176 | chunk_len = ntohs(asconf->chunk_hdr->length) - sizeof(sctp_chunkhdr_t); | 3190 | chunk_len = ntohs(asconf->chunk_hdr->length) - sizeof(sctp_chunkhdr_t); |
3177 | hdr = (sctp_addiphdr_t *)asconf->skb->data; | 3191 | hdr = (sctp_addiphdr_t *)asconf->skb->data; |
@@ -3199,9 +3213,14 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc, | |||
3199 | goto done; | 3213 | goto done; |
3200 | 3214 | ||
3201 | /* Process the TLVs contained within the ASCONF chunk. */ | 3215 | /* Process the TLVs contained within the ASCONF chunk. */ |
3202 | while (chunk_len > 0) { | 3216 | sctp_walk_params(param, addip, addip_hdr.params) { |
3217 | /* Skip preceeding address parameters. */ | ||
3218 | if (param.p->type == SCTP_PARAM_IPV4_ADDRESS || | ||
3219 | param.p->type == SCTP_PARAM_IPV6_ADDRESS) | ||
3220 | continue; | ||
3221 | |||
3203 | err_code = sctp_process_asconf_param(asoc, asconf, | 3222 | err_code = sctp_process_asconf_param(asoc, asconf, |
3204 | asconf_param); | 3223 | param.addip); |
3205 | /* ADDIP 4.1 A7) | 3224 | /* ADDIP 4.1 A7) |
3206 | * If an error response is received for a TLV parameter, | 3225 | * If an error response is received for a TLV parameter, |
3207 | * all TLVs with no response before the failed TLV are | 3226 | * all TLVs with no response before the failed TLV are |
@@ -3209,28 +3228,20 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc, | |||
3209 | * the failed response are considered unsuccessful unless | 3228 | * the failed response are considered unsuccessful unless |
3210 | * a specific success indication is present for the parameter. | 3229 | * a specific success indication is present for the parameter. |
3211 | */ | 3230 | */ |
3212 | if (SCTP_ERROR_NO_ERROR != err_code) | 3231 | if (err_code != SCTP_ERROR_NO_ERROR) |
3213 | all_param_pass = 0; | 3232 | all_param_pass = false; |
3214 | |||
3215 | if (!all_param_pass) | 3233 | if (!all_param_pass) |
3216 | sctp_add_asconf_response(asconf_ack, | 3234 | sctp_add_asconf_response(asconf_ack, param.addip->crr_id, |
3217 | asconf_param->crr_id, err_code, | 3235 | err_code, param.addip); |
3218 | asconf_param); | ||
3219 | 3236 | ||
3220 | /* ADDIP 4.3 D11) When an endpoint receiving an ASCONF to add | 3237 | /* ADDIP 4.3 D11) When an endpoint receiving an ASCONF to add |
3221 | * an IP address sends an 'Out of Resource' in its response, it | 3238 | * an IP address sends an 'Out of Resource' in its response, it |
3222 | * MUST also fail any subsequent add or delete requests bundled | 3239 | * MUST also fail any subsequent add or delete requests bundled |
3223 | * in the ASCONF. | 3240 | * in the ASCONF. |
3224 | */ | 3241 | */ |
3225 | if (SCTP_ERROR_RSRC_LOW == err_code) | 3242 | if (err_code == SCTP_ERROR_RSRC_LOW) |
3226 | goto done; | 3243 | goto done; |
3227 | |||
3228 | /* Move to the next ASCONF param. */ | ||
3229 | length = ntohs(asconf_param->param_hdr.length); | ||
3230 | asconf_param = (void *)asconf_param + length; | ||
3231 | chunk_len -= length; | ||
3232 | } | 3244 | } |
3233 | |||
3234 | done: | 3245 | done: |
3235 | asoc->peer.addip_serial++; | 3246 | asoc->peer.addip_serial++; |
3236 | 3247 | ||
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index c8f606324134..3ee27b7704ff 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c | |||
@@ -170,6 +170,9 @@ sctp_chunk_length_valid(struct sctp_chunk *chunk, | |||
170 | { | 170 | { |
171 | __u16 chunk_length = ntohs(chunk->chunk_hdr->length); | 171 | __u16 chunk_length = ntohs(chunk->chunk_hdr->length); |
172 | 172 | ||
173 | /* Previously already marked? */ | ||
174 | if (unlikely(chunk->pdiscard)) | ||
175 | return 0; | ||
173 | if (unlikely(chunk_length < required_length)) | 176 | if (unlikely(chunk_length < required_length)) |
174 | return 0; | 177 | return 0; |
175 | 178 | ||
@@ -3591,9 +3594,7 @@ sctp_disposition_t sctp_sf_do_asconf(struct net *net, | |||
3591 | struct sctp_chunk *asconf_ack = NULL; | 3594 | struct sctp_chunk *asconf_ack = NULL; |
3592 | struct sctp_paramhdr *err_param = NULL; | 3595 | struct sctp_paramhdr *err_param = NULL; |
3593 | sctp_addiphdr_t *hdr; | 3596 | sctp_addiphdr_t *hdr; |
3594 | union sctp_addr_param *addr_param; | ||
3595 | __u32 serial; | 3597 | __u32 serial; |
3596 | int length; | ||
3597 | 3598 | ||
3598 | if (!sctp_vtag_verify(chunk, asoc)) { | 3599 | if (!sctp_vtag_verify(chunk, asoc)) { |
3599 | sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG, | 3600 | sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG, |
@@ -3618,17 +3619,8 @@ sctp_disposition_t sctp_sf_do_asconf(struct net *net, | |||
3618 | hdr = (sctp_addiphdr_t *)chunk->skb->data; | 3619 | hdr = (sctp_addiphdr_t *)chunk->skb->data; |
3619 | serial = ntohl(hdr->serial); | 3620 | serial = ntohl(hdr->serial); |
3620 | 3621 | ||
3621 | addr_param = (union sctp_addr_param *)hdr->params; | ||
3622 | length = ntohs(addr_param->p.length); | ||
3623 | if (length < sizeof(sctp_paramhdr_t)) | ||
3624 | return sctp_sf_violation_paramlen(net, ep, asoc, type, arg, | ||
3625 | (void *)addr_param, commands); | ||
3626 | |||
3627 | /* Verify the ASCONF chunk before processing it. */ | 3622 | /* Verify the ASCONF chunk before processing it. */ |
3628 | if (!sctp_verify_asconf(asoc, | 3623 | if (!sctp_verify_asconf(asoc, chunk, true, &err_param)) |
3629 | (sctp_paramhdr_t *)((void *)addr_param + length), | ||
3630 | (void *)chunk->chunk_end, | ||
3631 | &err_param)) | ||
3632 | return sctp_sf_violation_paramlen(net, ep, asoc, type, arg, | 3624 | return sctp_sf_violation_paramlen(net, ep, asoc, type, arg, |
3633 | (void *)err_param, commands); | 3625 | (void *)err_param, commands); |
3634 | 3626 | ||
@@ -3745,10 +3737,7 @@ sctp_disposition_t sctp_sf_do_asconf_ack(struct net *net, | |||
3745 | rcvd_serial = ntohl(addip_hdr->serial); | 3737 | rcvd_serial = ntohl(addip_hdr->serial); |
3746 | 3738 | ||
3747 | /* Verify the ASCONF-ACK chunk before processing it. */ | 3739 | /* Verify the ASCONF-ACK chunk before processing it. */ |
3748 | if (!sctp_verify_asconf(asoc, | 3740 | if (!sctp_verify_asconf(asoc, asconf_ack, false, &err_param)) |
3749 | (sctp_paramhdr_t *)addip_hdr->params, | ||
3750 | (void *)asconf_ack->chunk_end, | ||
3751 | &err_param)) | ||
3752 | return sctp_sf_violation_paramlen(net, ep, asoc, type, arg, | 3741 | return sctp_sf_violation_paramlen(net, ep, asoc, type, arg, |
3753 | (void *)err_param, commands); | 3742 | (void *)err_param, commands); |
3754 | 3743 | ||