Skip to content

Commit 133800d

Browse files
marceloleitnerdavem330
authored andcommitted
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>
1 parent e2857b8 commit 133800d

File tree

5 files changed

+15
-9
lines changed

5 files changed

+15
-9
lines changed

include/net/sctp/structs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1098,7 +1098,7 @@ int sctp_bind_addr_dup(struct sctp_bind_addr *dest,
10981098
const struct sctp_bind_addr *src,
10991099
gfp_t gfp);
11001100
int 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);
11021102
int sctp_del_bind_addr(struct sctp_bind_addr *, union sctp_addr *);
11031103
int sctp_bind_addr_match(struct sctp_bind_addr *, const union sctp_addr *,
11041104
struct sctp_sock *);

net/sctp/bind_addr.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,8 @@ int sctp_bind_addr_dup(struct sctp_bind_addr *dest,
111111
dest->port = src->port;
112112

113113
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);
115116
if (error < 0)
116117
break;
117118
}
@@ -150,7 +151,7 @@ void sctp_bind_addr_free(struct sctp_bind_addr *bp)
150151

151152
/* Add an address to the bind address list in the SCTP_bind_addr structure. */
152153
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)
154155
{
155156
struct sctp_sockaddr_entry *addr;
156157

@@ -159,7 +160,7 @@ int sctp_add_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *new,
159160
if (!addr)
160161
return -ENOMEM;
161162

162-
memcpy(&addr->a, new, sizeof(*new));
163+
memcpy(&addr->a, new, min_t(size_t, sizeof(*new), new_size));
163164

164165
/* Fix up the port if it has not yet been set.
165166
* 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,
291292
}
292293

293294
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);
295297
if (retval) {
296298
/* Can't finish building the list, clean up. */
297299
sctp_bind_addr_clean(bp);
@@ -453,8 +455,8 @@ static int sctp_copy_one_addr(struct net *net, struct sctp_bind_addr *dest,
453455
(((AF_INET6 == addr->sa.sa_family) &&
454456
(flags & SCTP_ADDR6_ALLOWED) &&
455457
(flags & SCTP_ADDR6_PEERSUPP))))
456-
error = sctp_add_bind_addr(dest, addr, SCTP_ADDR_SRC,
457-
gfp);
458+
error = sctp_add_bind_addr(dest, addr, sizeof(*addr),
459+
SCTP_ADDR_SRC, gfp);
458460
}
459461

460462
return error;

net/sctp/protocol.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ int sctp_copy_local_addr_list(struct net *net, struct sctp_bind_addr *bp,
216216
(copy_flags & SCTP_ADDR6_ALLOWED) &&
217217
(copy_flags & SCTP_ADDR6_PEERSUPP)))) {
218218
error = sctp_add_bind_addr(bp, &addr->a,
219+
sizeof(addr->a),
219220
SCTP_ADDR_SRC, GFP_ATOMIC);
220221
if (error)
221222
goto end_copy;

net/sctp/sm_make_chunk.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1830,7 +1830,8 @@ struct sctp_association *sctp_unpack_cookie(
18301830
/* Also, add the destination address. */
18311831
if (list_empty(&retval->base.bind_addr.address_list)) {
18321832
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);
18341835
}
18351836

18361837
retval->next_tsn = retval->c.initial_tsn;

net/sctp/socket.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,8 @@ static int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
386386
/* Add the address to the bind address list.
387387
* Use GFP_ATOMIC since BHs will be disabled.
388388
*/
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);
390391

391392
/* Copy back into socket for getsockname() use. */
392393
if (!ret) {
@@ -577,6 +578,7 @@ static int sctp_send_asconf_add_ip(struct sock *sk,
577578
af = sctp_get_af_specific(addr->v4.sin_family);
578579
memcpy(&saveaddr, addr, af->sockaddr_len);
579580
retval = sctp_add_bind_addr(bp, &saveaddr,
581+
sizeof(saveaddr),
580582
SCTP_ADDR_NEW, GFP_ATOMIC);
581583
addr_buf += af->sockaddr_len;
582584
}

0 commit comments

Comments
 (0)