Skip to content

Commit 0c5dc07

Browse files
marceloleitnerdavem330
authored andcommitted
sctp: validate from_addr_param return
Ilja reported that, simply putting it, nothing was validating that from_addr_param functions were operating on initialized memory. That is, the parameter itself was being validated by sctp_walk_params, but it doesn't check for types and their specific sizes and it could be a 0-length one, causing from_addr_param to potentially work over the next parameter or even uninitialized memory. The fix here is to, in all calls to from_addr_param, check if enough space is there for the wanted IP address type. Reported-by: Ilja Van Sprundel <[email protected]> Signed-off-by: Marcelo Ricardo Leitner <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 9ea3e52 commit 0c5dc07

File tree

6 files changed

+44
-26
lines changed

6 files changed

+44
-26
lines changed

include/net/sctp/structs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,7 @@ struct sctp_af {
461461
int saddr);
462462
void (*from_sk) (union sctp_addr *,
463463
struct sock *sk);
464-
void (*from_addr_param) (union sctp_addr *,
464+
bool (*from_addr_param) (union sctp_addr *,
465465
union sctp_addr_param *,
466466
__be16 port, int iif);
467467
int (*to_addr_param) (const union sctp_addr *,

net/sctp/bind_addr.c

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -270,22 +270,19 @@ int sctp_raw_to_bind_addrs(struct sctp_bind_addr *bp, __u8 *raw_addr_list,
270270
rawaddr = (union sctp_addr_param *)raw_addr_list;
271271

272272
af = sctp_get_af_specific(param_type2af(param->type));
273-
if (unlikely(!af)) {
273+
if (unlikely(!af) ||
274+
!af->from_addr_param(&addr, rawaddr, htons(port), 0)) {
274275
retval = -EINVAL;
275-
sctp_bind_addr_clean(bp);
276-
break;
276+
goto out_err;
277277
}
278278

279-
af->from_addr_param(&addr, rawaddr, htons(port), 0);
280279
if (sctp_bind_addr_state(bp, &addr) != -1)
281280
goto next;
282281
retval = sctp_add_bind_addr(bp, &addr, sizeof(addr),
283282
SCTP_ADDR_SRC, gfp);
284-
if (retval) {
283+
if (retval)
285284
/* Can't finish building the list, clean up. */
286-
sctp_bind_addr_clean(bp);
287-
break;
288-
}
285+
goto out_err;
289286

290287
next:
291288
len = ntohs(param->length);
@@ -294,6 +291,12 @@ int sctp_raw_to_bind_addrs(struct sctp_bind_addr *bp, __u8 *raw_addr_list,
294291
}
295292

296293
return retval;
294+
295+
out_err:
296+
if (retval)
297+
sctp_bind_addr_clean(bp);
298+
299+
return retval;
297300
}
298301

299302
/********************************************************************

net/sctp/input.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1131,7 +1131,8 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct net *net,
11311131
if (!af)
11321132
continue;
11331133

1134-
af->from_addr_param(paddr, params.addr, sh->source, 0);
1134+
if (!af->from_addr_param(paddr, params.addr, sh->source, 0))
1135+
continue;
11351136

11361137
asoc = __sctp_lookup_association(net, laddr, paddr, transportp);
11371138
if (asoc)
@@ -1174,7 +1175,8 @@ static struct sctp_association *__sctp_rcv_asconf_lookup(
11741175
if (unlikely(!af))
11751176
return NULL;
11761177

1177-
af->from_addr_param(&paddr, param, peer_port, 0);
1178+
if (af->from_addr_param(&paddr, param, peer_port, 0))
1179+
return NULL;
11781180

11791181
return __sctp_lookup_association(net, laddr, &paddr, transportp);
11801182
}

net/sctp/ipv6.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -551,15 +551,20 @@ static void sctp_v6_to_sk_daddr(union sctp_addr *addr, struct sock *sk)
551551
}
552552

553553
/* Initialize a sctp_addr from an address parameter. */
554-
static void sctp_v6_from_addr_param(union sctp_addr *addr,
554+
static bool sctp_v6_from_addr_param(union sctp_addr *addr,
555555
union sctp_addr_param *param,
556556
__be16 port, int iif)
557557
{
558+
if (ntohs(param->v6.param_hdr.length) < sizeof(struct sctp_ipv6addr_param))
559+
return false;
560+
558561
addr->v6.sin6_family = AF_INET6;
559562
addr->v6.sin6_port = port;
560563
addr->v6.sin6_flowinfo = 0; /* BUG */
561564
addr->v6.sin6_addr = param->v6.addr;
562565
addr->v6.sin6_scope_id = iif;
566+
567+
return true;
563568
}
564569

565570
/* Initialize an address parameter from a sctp_addr and return the length

net/sctp/protocol.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,14 +254,19 @@ static void sctp_v4_to_sk_daddr(union sctp_addr *addr, struct sock *sk)
254254
}
255255

256256
/* Initialize a sctp_addr from an address parameter. */
257-
static void sctp_v4_from_addr_param(union sctp_addr *addr,
257+
static bool sctp_v4_from_addr_param(union sctp_addr *addr,
258258
union sctp_addr_param *param,
259259
__be16 port, int iif)
260260
{
261+
if (ntohs(param->v4.param_hdr.length) < sizeof(struct sctp_ipv4addr_param))
262+
return false;
263+
261264
addr->v4.sin_family = AF_INET;
262265
addr->v4.sin_port = port;
263266
addr->v4.sin_addr.s_addr = param->v4.addr.s_addr;
264267
memset(addr->v4.sin_zero, 0, sizeof(addr->v4.sin_zero));
268+
269+
return true;
265270
}
266271

267272
/* Initialize an address parameter from a sctp_addr and return the length

net/sctp/sm_make_chunk.c

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2346,11 +2346,13 @@ int sctp_process_init(struct sctp_association *asoc, struct sctp_chunk *chunk,
23462346

23472347
/* Process the initialization parameters. */
23482348
sctp_walk_params(param, peer_init, init_hdr.params) {
2349-
if (!src_match && (param.p->type == SCTP_PARAM_IPV4_ADDRESS ||
2350-
param.p->type == SCTP_PARAM_IPV6_ADDRESS)) {
2349+
if (!src_match &&
2350+
(param.p->type == SCTP_PARAM_IPV4_ADDRESS ||
2351+
param.p->type == SCTP_PARAM_IPV6_ADDRESS)) {
23512352
af = sctp_get_af_specific(param_type2af(param.p->type));
2352-
af->from_addr_param(&addr, param.addr,
2353-
chunk->sctp_hdr->source, 0);
2353+
if (!af->from_addr_param(&addr, param.addr,
2354+
chunk->sctp_hdr->source, 0))
2355+
continue;
23542356
if (sctp_cmp_addr_exact(sctp_source(chunk), &addr))
23552357
src_match = 1;
23562358
}
@@ -2531,7 +2533,8 @@ static int sctp_process_param(struct sctp_association *asoc,
25312533
break;
25322534
do_addr_param:
25332535
af = sctp_get_af_specific(param_type2af(param.p->type));
2534-
af->from_addr_param(&addr, param.addr, htons(asoc->peer.port), 0);
2536+
if (!af->from_addr_param(&addr, param.addr, htons(asoc->peer.port), 0))
2537+
break;
25352538
scope = sctp_scope(peer_addr);
25362539
if (sctp_in_scope(net, &addr, scope))
25372540
if (!sctp_assoc_add_peer(asoc, &addr, gfp, SCTP_UNCONFIRMED))
@@ -2632,15 +2635,13 @@ static int sctp_process_param(struct sctp_association *asoc,
26322635
addr_param = param.v + sizeof(struct sctp_addip_param);
26332636

26342637
af = sctp_get_af_specific(param_type2af(addr_param->p.type));
2635-
if (af == NULL)
2638+
if (!af)
26362639
break;
26372640

2638-
af->from_addr_param(&addr, addr_param,
2639-
htons(asoc->peer.port), 0);
2641+
if (!af->from_addr_param(&addr, addr_param,
2642+
htons(asoc->peer.port), 0))
2643+
break;
26402644

2641-
/* if the address is invalid, we can't process it.
2642-
* XXX: see spec for what to do.
2643-
*/
26442645
if (!af->addr_valid(&addr, NULL, NULL))
26452646
break;
26462647

@@ -3054,7 +3055,8 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc,
30543055
if (unlikely(!af))
30553056
return SCTP_ERROR_DNS_FAILED;
30563057

3057-
af->from_addr_param(&addr, addr_param, htons(asoc->peer.port), 0);
3058+
if (!af->from_addr_param(&addr, addr_param, htons(asoc->peer.port), 0))
3059+
return SCTP_ERROR_DNS_FAILED;
30583060

30593061
/* ADDIP 4.2.1 This parameter MUST NOT contain a broadcast
30603062
* or multicast address.
@@ -3331,7 +3333,8 @@ static void sctp_asconf_param_success(struct sctp_association *asoc,
33313333

33323334
/* We have checked the packet before, so we do not check again. */
33333335
af = sctp_get_af_specific(param_type2af(addr_param->p.type));
3334-
af->from_addr_param(&addr, addr_param, htons(bp->port), 0);
3336+
if (!af->from_addr_param(&addr, addr_param, htons(bp->port), 0))
3337+
return;
33353338

33363339
switch (asconf_param->param_hdr.type) {
33373340
case SCTP_PARAM_ADD_IP:

0 commit comments

Comments
 (0)