A number of functions do not validate the length of arguments passed.

As a result of this a user could supply a bad 'sockaddr' structure to
clnp_route() via connect(2).
Issue found by Christer Oberg and patch from christos@ (NetBSD-SA2007-004)
This commit is contained in:
adrianp 2007-03-29 08:19:20 +00:00
parent a7b58a5e90
commit b02eb0fb91
1 changed files with 35 additions and 22 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: clnp_subr.c,v 1.26 2007/03/04 06:03:31 christos Exp $ */ /* $NetBSD: clnp_subr.c,v 1.27 2007/03/29 08:19:20 adrianp Exp $ */
/*- /*-
* Copyright (c) 1991, 1993 * Copyright (c) 1991, 1993
@ -59,7 +59,7 @@ SOFTWARE.
*/ */
#include <sys/cdefs.h> #include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: clnp_subr.c,v 1.26 2007/03/04 06:03:31 christos Exp $"); __KERNEL_RCSID(0, "$NetBSD: clnp_subr.c,v 1.27 2007/03/29 08:19:20 adrianp Exp $");
#include "opt_iso.h" #include "opt_iso.h"
@ -157,27 +157,27 @@ clnp_extract_addr(
struct iso_addr *destp) /* ptr to destination address struct iso_addr *destp) /* ptr to destination address
* buffer */ * buffer */
{ {
int len; /* argument to bcopy */ size_t len; /* argument to memcpy */
/* /*
* check that we have enough data. Plus1 is for length octet * check that we have enough data. Plus1 is for length octet
*/ */
if ((u_char) * bufp + 1 > buflen) { len = (u_char)*bufp++;
return ((void *) 0); if (len > buflen)
} return NULL;
len = destp->isoa_len = (u_char) * bufp++; destp->isoa_len = len;
(void) bcopy(bufp, (void *) destp, len); (void)memcpy(destp, bufp, len);
buflen -= len; buflen -= len;
bufp += len; bufp += len;
/* /*
* check that we have enough data. Plus1 is for length octet * check that we have enough data. Plus1 is for length octet
*/ */
if ((u_char) * bufp + 1 > buflen) { len = (u_char)*bufp++;
return ((void *) 0); if (len > buflen)
} return NULL;
len = srcp->isoa_len = (u_char) * bufp++; srcp->isoa_len = len;
(void) bcopy(bufp, (void *) srcp, len); (void)memcpy(srcp, bufp, len);
bufp += len; bufp += len;
/* /*
@ -186,7 +186,7 @@ clnp_extract_addr(
if (iso_ck_addr(srcp) && iso_ck_addr(destp)) if (iso_ck_addr(srcp) && iso_ck_addr(destp))
return bufp; return bufp;
else else
return (void *) 0; return NULL;
} }
#endif /* notdef */ #endif /* notdef */
@ -424,11 +424,11 @@ clnp_insert_addr(
struct iso_addr *dstp) /* ptr to dst addr */ struct iso_addr *dstp) /* ptr to dst addr */
{ {
*bufp++ = dstp->isoa_len; *bufp++ = dstp->isoa_len;
(void) bcopy((void *) dstp, bufp, dstp->isoa_len); (void)memcpy(bufp, dstp, dstp->isoa_len);
bufp += dstp->isoa_len; bufp += dstp->isoa_len;
*bufp++ = srcp->isoa_len; *bufp++ = srcp->isoa_len;
(void) bcopy((void *) srcp, bufp, srcp->isoa_len); (void)memcpy(bufp, srcp, srcp->isoa_len);
bufp += srcp->isoa_len; bufp += srcp->isoa_len;
return bufp; return bufp;
@ -466,10 +466,13 @@ clnp_route(
{ {
if (flags & SO_DONTROUTE) { if (flags & SO_DONTROUTE) {
struct iso_ifaddr *ia; struct iso_ifaddr *ia;
size_t len = 1 + (unsigned)dst->isoa_len;
rtcache_free((struct route *)ro); rtcache_free((struct route *)ro);
memset(&ro->ro_dst, 0, sizeof(ro->ro_dst)); if (sizeof(ro->ro_dst.siso_addr) < len)
memcpy(&ro->ro_dst.siso_addr, dst, 1 + (unsigned)dst->isoa_len); return EINVAL;
(void)memset(&ro->ro_dst, 0, sizeof(ro->ro_dst));
(void)memcpy(&ro->ro_dst.siso_addr, dst, len);
ro->ro_dst.siso_family = AF_ISO; ro->ro_dst.siso_family = AF_ISO;
ro->ro_dst.siso_len = sizeof(ro->ro_dst); ro->ro_dst.siso_len = sizeof(ro->ro_dst);
ia = iso_localifa(&ro->ro_dst); ia = iso_localifa(&ro->ro_dst);
@ -488,11 +491,15 @@ clnp_route(
rtcache_check((struct route *)ro); rtcache_check((struct route *)ro);
if (ro->ro_rt == NULL) { if (ro->ro_rt == NULL) {
size_t len = 1 + (unsigned)dst->isoa_len;
/* set up new route structure */ /* set up new route structure */
memset(&ro->ro_dst, 0, sizeof(ro->ro_dst)); if (sizeof(ro->ro_dst.siso_addr) < len)
return EINVAL;
(void)memset(&ro->ro_dst, 0, sizeof(ro->ro_dst));
ro->ro_dst.siso_len = sizeof(ro->ro_dst); ro->ro_dst.siso_len = sizeof(ro->ro_dst);
ro->ro_dst.siso_family = AF_ISO; ro->ro_dst.siso_family = AF_ISO;
memcpy(&ro->ro_dst.siso_addr, dst, 1 + dst->isoa_len); (void)memcpy(&ro->ro_dst.siso_addr, dst, len);
/* allocate new route */ /* allocate new route */
#ifdef ARGO_DEBUG #ifdef ARGO_DEBUG
if (argo_debug[D_ROUTE]) { if (argo_debug[D_ROUTE]) {
@ -554,13 +561,19 @@ clnp_srcroute(
if CLNPSRCRT_TERM if CLNPSRCRT_TERM
(oidx, options) { (oidx, options) {
dst.isoa_len = final_dst->isoa_len; dst.isoa_len = final_dst->isoa_len;
bcopy(final_dst->isoa_genaddr, dst.isoa_genaddr, dst.isoa_len); if (sizeof(dst.isoa_genaddr) < (size_t)dst.isoa_len)
return EINVAL;
(void)memcpy(dst.isoa_genaddr, final_dst->isoa_genaddr,
(size_t)dst.isoa_len);
} else { } else {
/* /*
* setup dst based on src rt specified * setup dst based on src rt specified
*/ */
dst.isoa_len = CLNPSRCRT_CLEN(oidx, options); dst.isoa_len = CLNPSRCRT_CLEN(oidx, options);
bcopy(CLNPSRCRT_CADDR(oidx, options), dst.isoa_genaddr, dst.isoa_len); if (sizeof(dst.isoa_genaddr) < (unsigned)dst.isoa_len)
return EINVAL;
(void)memcpy(dst.isoa_genaddr, CLNPSRCRT_CADDR(oidx, options),
(size_t)dst.isoa_len);
} }
/* /*