diff options
author | Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> | 2016-03-08 08:34:28 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-03-08 15:04:08 -0500 |
commit | 133800d1f0288b9ddfc0d0aded10d9efa82d5b8c (patch) | |
tree | fa156a2753d1c80c12910790cb12ddf6db7da30b /net/sctp/bind_addr.c | |
parent | e2857b8f11a289ed2b61d18d0665e05c1053c446 (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>
Diffstat (limited to 'net/sctp/bind_addr.c')
-rw-r--r-- | net/sctp/bind_addr.c | 14 |
1 files changed, 8 insertions, 6 deletions
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. */ |
152 | int sctp_add_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *new, | 153 | int 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; |