Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

sctp: handle errors when updating asoc

It's a bad thing not to handle errors when updating asoc. The memory
allocation failure in any of the functions called in sctp_assoc_update()
would cause sctp to work unexpectedly.

This patch is to fix it by aborting the asoc and reporting the error when
any of these functions fails.

Signed-off-by: Xin Long <lucien.xin@gmail.com>
Acked-by: Neil Horman <nhorman@tuxdriver.com>
Acked-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Xin Long and committed by
David S. Miller
5ee8aa68 8cd5c25f

+39 -14
+2 -2
include/net/sctp/structs.h
··· 1953 1953 const union sctp_addr *, 1954 1954 const union sctp_addr *); 1955 1955 void sctp_assoc_migrate(struct sctp_association *, struct sock *); 1956 - void sctp_assoc_update(struct sctp_association *old, 1957 - struct sctp_association *new); 1956 + int sctp_assoc_update(struct sctp_association *old, 1957 + struct sctp_association *new); 1958 1958 1959 1959 __u32 sctp_association_get_next_tsn(struct sctp_association *); 1960 1960
+14 -11
net/sctp/associola.c
··· 1112 1112 } 1113 1113 1114 1114 /* Update an association (possibly from unexpected COOKIE-ECHO processing). */ 1115 - void sctp_assoc_update(struct sctp_association *asoc, 1116 - struct sctp_association *new) 1115 + int sctp_assoc_update(struct sctp_association *asoc, 1116 + struct sctp_association *new) 1117 1117 { 1118 1118 struct sctp_transport *trans; 1119 1119 struct list_head *pos, *temp; ··· 1124 1124 asoc->peer.sack_needed = new->peer.sack_needed; 1125 1125 asoc->peer.auth_capable = new->peer.auth_capable; 1126 1126 asoc->peer.i = new->peer.i; 1127 - sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_INITIAL, 1128 - asoc->peer.i.initial_tsn, GFP_ATOMIC); 1127 + 1128 + if (!sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_INITIAL, 1129 + asoc->peer.i.initial_tsn, GFP_ATOMIC)) 1130 + return -ENOMEM; 1129 1131 1130 1132 /* Remove any peer addresses not present in the new association. */ 1131 1133 list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { ··· 1171 1169 } else { 1172 1170 /* Add any peer addresses from the new association. */ 1173 1171 list_for_each_entry(trans, &new->peer.transport_addr_list, 1174 - transports) { 1175 - if (!sctp_assoc_lookup_paddr(asoc, &trans->ipaddr)) 1176 - sctp_assoc_add_peer(asoc, &trans->ipaddr, 1177 - GFP_ATOMIC, trans->state); 1178 - } 1172 + transports) 1173 + if (!sctp_assoc_lookup_paddr(asoc, &trans->ipaddr) && 1174 + !sctp_assoc_add_peer(asoc, &trans->ipaddr, 1175 + GFP_ATOMIC, trans->state)) 1176 + return -ENOMEM; 1179 1177 1180 1178 asoc->ctsn_ack_point = asoc->next_tsn - 1; 1181 1179 asoc->adv_peer_ack_point = asoc->ctsn_ack_point; ··· 1184 1182 sctp_stream_update(&asoc->stream, &new->stream); 1185 1183 1186 1184 /* get a new assoc id if we don't have one yet. */ 1187 - sctp_assoc_set_id(asoc, GFP_ATOMIC); 1185 + if (sctp_assoc_set_id(asoc, GFP_ATOMIC)) 1186 + return -ENOMEM; 1188 1187 } 1189 1188 1190 1189 /* SCTP-AUTH: Save the peer parameters from the new associations ··· 1203 1200 asoc->peer.peer_hmacs = new->peer.peer_hmacs; 1204 1201 new->peer.peer_hmacs = NULL; 1205 1202 1206 - sctp_auth_asoc_init_active_key(asoc, GFP_ATOMIC); 1203 + return sctp_auth_asoc_init_active_key(asoc, GFP_ATOMIC); 1207 1204 } 1208 1205 1209 1206 /* Update the retran path for sending a retransmitted packet.
+23 -1
net/sctp/sm_sideeffect.c
··· 818 818 asoc->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] = t->rto; 819 819 } 820 820 821 + static void sctp_cmd_assoc_update(sctp_cmd_seq_t *cmds, 822 + struct sctp_association *asoc, 823 + struct sctp_association *new) 824 + { 825 + struct net *net = sock_net(asoc->base.sk); 826 + struct sctp_chunk *abort; 827 + 828 + if (!sctp_assoc_update(asoc, new)) 829 + return; 830 + 831 + abort = sctp_make_abort(asoc, NULL, sizeof(sctp_errhdr_t)); 832 + if (abort) { 833 + sctp_init_cause(abort, SCTP_ERROR_RSRC_LOW, 0); 834 + sctp_add_cmd_sf(cmds, SCTP_CMD_REPLY, SCTP_CHUNK(abort)); 835 + } 836 + sctp_add_cmd_sf(cmds, SCTP_CMD_SET_SK_ERR, SCTP_ERROR(ECONNABORTED)); 837 + sctp_add_cmd_sf(cmds, SCTP_CMD_ASSOC_FAILED, 838 + SCTP_PERR(SCTP_ERROR_RSRC_LOW)); 839 + SCTP_INC_STATS(net, SCTP_MIB_ABORTEDS); 840 + SCTP_DEC_STATS(net, SCTP_MIB_CURRESTAB); 841 + } 842 + 821 843 /* Helper function to change the state of an association. */ 822 844 static void sctp_cmd_new_state(sctp_cmd_seq_t *cmds, 823 845 struct sctp_association *asoc, ··· 1316 1294 break; 1317 1295 1318 1296 case SCTP_CMD_UPDATE_ASSOC: 1319 - sctp_assoc_update(asoc, cmd->obj.asoc); 1297 + sctp_cmd_assoc_update(commands, asoc, cmd->obj.asoc); 1320 1298 break; 1321 1299 1322 1300 case SCTP_CMD_PURGE_OUTQUEUE: