diff options
author | Todd C. Miller <millert@cvs.openbsd.org> | 2016-12-06 22:32:59 +0000 |
---|---|---|
committer | Todd C. Miller <millert@cvs.openbsd.org> | 2016-12-06 22:32:59 +0000 |
commit | 8050ae785ff25fb051f2861b23b86887bccab5aa (patch) | |
tree | 3052bbe601c86eac419ed53222477b5d05ce6979 | |
parent | daad54a1e46f7cd844dbe60344527bd578aa8112 (diff) |
CVE-2016-6559: fix potential buffer overflow(s) in link_ntoa(3).
A specially crafted struct sockaddr_dl argument can trigger a stack
overflow of a static buffer in libc. An attacker may be able to
use this to write to arbitrary locations in the data segment.
From FreeBSD (glebius); OK deraadt@ mestre@
-rw-r--r-- | lib/libc/net/linkaddr.c | 54 |
1 files changed, 35 insertions, 19 deletions
diff --git a/lib/libc/net/linkaddr.c b/lib/libc/net/linkaddr.c index 8f90aca8f52..5b74d982190 100644 --- a/lib/libc/net/linkaddr.c +++ b/lib/libc/net/linkaddr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: linkaddr.c,v 1.6 2015/09/10 08:55:03 mpi Exp $ */ +/* $OpenBSD: linkaddr.c,v 1.7 2016/12/06 22:32:58 millert Exp $ */ /*- * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. @@ -30,40 +30,56 @@ #include <sys/types.h> #include <sys/socket.h> +#include <net/if.h> #include <net/if_dl.h> #include <string.h> -static char hexlist[] = "0123456789abcdef"; +static const char hexlist[] = "0123456789abcdef"; char * link_ntoa(const struct sockaddr_dl *sdl) { static char obuf[64]; - char *out = obuf; - int i; - u_char *in = (u_char *)LLADDR(sdl); - u_char *inlim = in + sdl->sdl_alen; - int firsttime = 1; + char *out; + const char *in, *inlim; + int namelen, i, rem; - if (sdl->sdl_nlen) { - bcopy(sdl->sdl_data, obuf, sdl->sdl_nlen); - out += sdl->sdl_nlen; - if (sdl->sdl_alen) + namelen = (sdl->sdl_nlen <= IFNAMSIZ) ? sdl->sdl_nlen : IFNAMSIZ; + + out = obuf; + rem = sizeof(obuf); + if (namelen > 0) { + memcpy(out, sdl->sdl_data, namelen); + out += namelen; + rem -= namelen; + if (sdl->sdl_alen > 0) { *out++ = ':'; + rem--; + } } - while (in < inlim) { - if (firsttime) - firsttime = 0; - else + + in = (const char *)sdl->sdl_data + sdl->sdl_nlen; + inlim = in + sdl->sdl_alen; + + while (in < inlim && rem > 1) { + if (in != (const char *)sdl->sdl_data + sdl->sdl_nlen) { *out++ = '.'; + rem--; + } i = *in++; if (i > 0xf) { - out[1] = hexlist[i & 0xf]; + if (rem < 3) + break; + *out++ = hexlist[i & 0xf]; i >>= 4; - out[0] = hexlist[i]; - out += 2; - } else *out++ = hexlist[i]; + rem -= 2; + } else { + if (rem < 2) + break; + *out++ = hexlist[i]; + rem++; + } } *out = 0; return (obuf); |