On Tue, Dec 06, 2016 at 06:50:34PM +0000, Gleb Smirnoff wrote:
> Author: glebius
> Date: Tue Dec  6 18:50:33 2016
> New Revision: 309639
> URL: https://svnweb.freebsd.org/changeset/base/309639
> 
> Log:
>   Fix possible buffer overflow(s) in link_ntoa(3).
>   
>   A specially crafted sockaddr_dl argument can trigger a static buffer 
> overflow
>   in the libc library, with possibility to rewrite with arbitrary data 
> following
>   static buffers that belong to other library functions.
>   
>   Reviewed by:        kib
>   Security:   FreeBSD-SA-16:37.libc
> 
> Modified:
>   head/lib/libc/net/linkaddr.c
> 
> Modified: head/lib/libc/net/linkaddr.c
> ==============================================================================
> --- head/lib/libc/net/linkaddr.c      Tue Dec  6 18:50:22 2016        
> (r309638)
> +++ head/lib/libc/net/linkaddr.c      Tue Dec  6 18:50:33 2016        
> (r309639)
> @@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$");
>  
>  #include <sys/types.h>
>  #include <sys/socket.h>
> +#include <net/if.h>
>  #include <net/if_dl.h>
>  #include <string.h>
>  
> @@ -122,31 +123,47 @@ 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;
> -
> -     if (sdl->sdl_nlen) {
> -             bcopy(sdl->sdl_data, obuf, sdl->sdl_nlen);
> -             out += sdl->sdl_nlen;
> -             if (sdl->sdl_alen)
> +     _Static_assert(sizeof(obuf) >= IFNAMSIZ + 20, "obuf is too small");
> +     char *out;
> +     const char *in, *inlim;
> +     int namelen, i, rem;
> +
> +     namelen = (sdl->sdl_nlen <= IFNAMSIZ) ? sdl->sdl_nlen : IFNAMSIZ;
> +
> +     out = obuf;
> +     rem = sizeof(obuf);
> +     if (namelen > 0) {
> +             bcopy(sdl->sdl_data, out, 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++;

rem++ is incorrect. It should be rem--. HardenedBSD has a fix here:

https://github.com/HardenedBSD/hardenedBSD/commit/fb823297fbced336b6beeeb624e2dc65b67aa0eb

> +             }
>       }
>       *out = 0;
>       return (obuf);

Thanks,

-- 
Shawn Webb
Cofounder and Security Engineer
HardenedBSD

GPG Key ID:          0x6A84658F52456EEE
GPG Key Fingerprint: 2ABA B6BD EF6A F486 BE89  3D9E 6A84 658F 5245 6EEE

Attachment: signature.asc
Description: PGP signature

Reply via email to