aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarcelo Ricardo Leitner <marcelo.leitner@gmail.com>2016-03-08 08:34:28 -0500
committerDavid S. Miller <davem@davemloft.net>2016-03-08 15:04:08 -0500
commit133800d1f0288b9ddfc0d0aded10d9efa82d5b8c (patch)
treefa156a2753d1c80c12910790cb12ddf6db7da30b
parente2857b8f11a289ed2b61d18d0665e05c1053c446 (diff)
sctp: fix copying more bytes than expected in sctp_add_bind_addr
Dmitry reported that sctp_add_bind_addr may read more bytes than expected in case the parameter is a IPv4 addr supplied by the user through calls such as sctp_bindx_add(), because it always copies sizeof(union sctp_addr) while the buffer may be just a struct sockaddr_in, which is smaller. This patch then fixes it by limiting the memcpy to the min between the union size and a (new parameter) provided addr size. Where possible this parameter still is the size of that union, except for reading from user-provided buffers, which then it accounts for protocol type. Reported-by: Dmitry Vyukov <dvyukov@google.com> Tested-by: Dmitry Vyukov <dvyukov@google.com> Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/sctp/structs.h2
-rw-r--r--net/sctp/bind_addr.c14
-rw-r--r--net/sctp/protocol.c1
-rw-r--r--net/sctp/sm_make_chunk.c3
-rw-r--r--net/sctp/socket.c4
5 files changed, 15 insertions, 9 deletions
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index 205630bb5010..f816344f65f2 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -1098,7 +1098,7 @@ int sctp_bind_addr_dup(struct sctp_bind_addr *dest,
1098 const struct sctp_bind_addr *src, 1098 const struct sctp_bind_addr *src,
1099 gfp_t gfp); 1099 gfp_t gfp);
1100int sctp_add_bind_addr(struct sctp_bind_addr *, union sctp_addr *, 1100int sctp_add_bind_addr(struct sctp_bind_addr *, union sctp_addr *,
1101 __u8 addr_state, gfp_t gfp); 1101 int new_size, __u8 addr_state, gfp_t gfp);
1102int sctp_del_bind_addr(struct sctp_bind_addr *, union sctp_addr *); 1102int sctp_del_bind_addr(struct sctp_bind_addr *, union sctp_addr *);
1103int sctp_bind_addr_match(struct sctp_bind_addr *, const union sctp_addr *, 1103int sctp_bind_addr_match(struct sctp_bind_addr *, const union sctp_addr *,
1104 struct sctp_sock *); 1104 struct sctp_sock *);
diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c
index 871cdf9567e6..401c60750b20 100644
--- a/net/sctp/bind_addr.c
+++ b/net/sctp/bind_addr.c
@@ -111,7 +111,8 @@ int sctp_bind_addr_dup(struct sctp_bind_addr *dest,
111 dest->port = src->port; 111 dest->port = src->port;
112 112
113 list_for_each_entry(addr, &src->address_list, list) { 113 list_for_each_entry(addr, &src->address_list, list) {
114 error = sctp_add_bind_addr(dest, &addr->a, 1, gfp); 114 error = sctp_add_bind_addr(dest, &addr->a, sizeof(addr->a),
115 1, gfp);
115 if (error < 0) 116 if (error < 0)
116 break; 117 break;
117 } 118 }
@@ -150,7 +151,7 @@ void sctp_bind_addr_free(struct sctp_bind_addr *bp)
150 151
151/* Add an address to the bind address list in the SCTP_bind_addr structure. */ 152/* Add an address to the bind address list in the SCTP_bind_addr structure. */
152int sctp_add_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *new, 153int sctp_add_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *new,
153 __u8 addr_state, gfp_t gfp) 154 int new_size, __u8 addr_state, gfp_t gfp)
154{ 155{
155 struct sctp_sockaddr_entry *addr; 156 struct sctp_sockaddr_entry *addr;
156 157
@@ -159,7 +160,7 @@ int sctp_add_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *new,
159 if (!addr) 160 if (!addr)
160 return -ENOMEM; 161 return -ENOMEM;
161 162
162 memcpy(&addr->a, new, sizeof(*new)); 163 memcpy(&addr->a, new, min_t(size_t, sizeof(*new), new_size));
163 164
164 /* Fix up the port if it has not yet been set. 165 /* Fix up the port if it has not yet been set.
165 * Both v4 and v6 have the port at the same offset. 166 * Both v4 and v6 have the port at the same offset.
@@ -291,7 +292,8 @@ int sctp_raw_to_bind_addrs(struct sctp_bind_addr *bp, __u8 *raw_addr_list,
291 } 292 }
292 293
293 af->from_addr_param(&addr, rawaddr, htons(port), 0); 294 af->from_addr_param(&addr, rawaddr, htons(port), 0);
294 retval = sctp_add_bind_addr(bp, &addr, SCTP_ADDR_SRC, gfp); 295 retval = sctp_add_bind_addr(bp, &addr, sizeof(addr),
296 SCTP_ADDR_SRC, gfp);
295 if (retval) { 297 if (retval) {
296 /* Can't finish building the list, clean up. */ 298 /* Can't finish building the list, clean up. */
297 sctp_bind_addr_clean(bp); 299 sctp_bind_addr_clean(bp);
@@ -453,8 +455,8 @@ static int sctp_copy_one_addr(struct net *net, struct sctp_bind_addr *dest,
453 (((AF_INET6 == addr->sa.sa_family) && 455 (((AF_INET6 == addr->sa.sa_family) &&
454 (flags & SCTP_ADDR6_ALLOWED) && 456 (flags & SCTP_ADDR6_ALLOWED) &&
455 (flags & SCTP_ADDR6_PEERSUPP)))) 457 (flags & SCTP_ADDR6_PEERSUPP))))
456 error = sctp_add_bind_addr(dest, addr, SCTP_ADDR_SRC, 458 error = sctp_add_bind_addr(dest, addr, sizeof(*addr),
457 gfp); 459 SCTP_ADDR_SRC, gfp);
458 } 460 }
459 461
460 return error; 462 return error;
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index 1099e99a53c4..d3d50daa248b 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -216,6 +216,7 @@ int sctp_copy_local_addr_list(struct net *net, struct sctp_bind_addr *bp,
216 (copy_flags & SCTP_ADDR6_ALLOWED) && 216 (copy_flags & SCTP_ADDR6_ALLOWED) &&
217 (copy_flags & SCTP_ADDR6_PEERSUPP)))) { 217 (copy_flags & SCTP_ADDR6_PEERSUPP)))) {
218 error = sctp_add_bind_addr(bp, &addr->a, 218 error = sctp_add_bind_addr(bp, &addr->a,
219 sizeof(addr->a),
219 SCTP_ADDR_SRC, GFP_ATOMIC); 220 SCTP_ADDR_SRC, GFP_ATOMIC);
220 if (error) 221 if (error)
221 goto end_copy; 222 goto end_copy;
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index 5d6a03fad378..7fe971e30ad6 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -1830,7 +1830,8 @@ no_hmac:
1830 /* Also, add the destination address. */ 1830 /* Also, add the destination address. */
1831 if (list_empty(&retval->base.bind_addr.address_list)) { 1831 if (list_empty(&retval->base.bind_addr.address_list)) {
1832 sctp_add_bind_addr(&retval->base.bind_addr, &chunk->dest, 1832 sctp_add_bind_addr(&retval->base.bind_addr, &chunk->dest,
1833 SCTP_ADDR_SRC, GFP_ATOMIC); 1833 sizeof(chunk->dest), SCTP_ADDR_SRC,
1834 GFP_ATOMIC);
1834 } 1835 }
1835 1836
1836 retval->next_tsn = retval->c.initial_tsn; 1837 retval->next_tsn = retval->c.initial_tsn;
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index e878da0949db..0e3de0c71137 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -386,7 +386,8 @@ static int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
386 /* Add the address to the bind address list. 386 /* Add the address to the bind address list.
387 * Use GFP_ATOMIC since BHs will be disabled. 387 * Use GFP_ATOMIC since BHs will be disabled.
388 */ 388 */
389 ret = sctp_add_bind_addr(bp, addr, SCTP_ADDR_SRC, GFP_ATOMIC); 389 ret = sctp_add_bind_addr(bp, addr, af->sockaddr_len,
390 SCTP_ADDR_SRC, GFP_ATOMIC);
390 391
391 /* Copy back into socket for getsockname() use. */ 392 /* Copy back into socket for getsockname() use. */
392 if (!ret) { 393 if (!ret) {
@@ -577,6 +578,7 @@ static int sctp_send_asconf_add_ip(struct sock *sk,
577 af = sctp_get_af_specific(addr->v4.sin_family); 578 af = sctp_get_af_specific(addr->v4.sin_family);
578 memcpy(&saveaddr, addr, af->sockaddr_len); 579 memcpy(&saveaddr, addr, af->sockaddr_len);
579 retval = sctp_add_bind_addr(bp, &saveaddr, 580 retval = sctp_add_bind_addr(bp, &saveaddr,
581 sizeof(saveaddr),
580 SCTP_ADDR_NEW, GFP_ATOMIC); 582 SCTP_ADDR_NEW, GFP_ATOMIC);
581 addr_buf += af->sockaddr_len; 583 addr_buf += af->sockaddr_len;
582 } 584 }