library/5078: wcsncpy buffer overrun

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

library/5078: wcsncpy buffer overrun

ttakah
>Number:         5078
>Category:       library
>Synopsis:       wcsncpy buffer overrun
>Confidential:   yes
>Severity:       serious
>Priority:       medium
>Responsible:    bugs
>State:          open
>Quarter:        
>Keywords:      
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sat Apr 15 05:10:02 GMT 2006
>Closed-Date:
>Last-Modified:
>Originator:     TAKAHASHI Tamotsu
>Release:        OpenBSD 3.9 (rev. 1.3 of src/lib/libc/string/wcsncpy.c)
>Organization:
net
>Environment:
        System      : OpenBSD 3.9
        Architecture: OpenBSD.i386
        Machine     : i386
>Description:
wcsncpy always append '\0' even after LEN characters are written.

But "man strncpy" says "strncpy() copies not more than len characters into dst,
appending `\0' characters if src is less than len characters long,
and not terminating dst if the length of src is greater than or equal to len."

(reference: http://vimrc.hp.infoseek.co.jp/fish-wcsncpy.html [Japanese])

>How-To-Repeat:
wcsncpy(buf, longerstr, buflen);

For example, with the following code, dst[5] will be '\0'.
But wcsncpy doesn't have to modify dst[5].

============================================
#include <stdlib.h>
#include <wchar.h>
int main()
{
  wchar_t *dst;
  wchar_t src[] = { 1,2,3,4,5,6,7 };
  dst = malloc(sizeof(wchar_t) * 6);
  dst[4] = 11;
  dst[5] = 12;
  wcsncpy(dst, src, 5);
  dst[4] = 0;
}
============================================
(gdb) b main
Breakpoint 1 at 0x1c00062a: file wcsncpy.c, line 6.
(gdb) run
Starting program: /home/tamo/a.out

Breakpoint 1, main () at wcsncpy.c:6
6         wchar_t src[] = { 1,2,3,4,5,6,7 };
(gdb) next
7         dst = malloc(sizeof(wchar_t) * 6);
(gdb) next
8         dst[4] = 11;
(gdb) next
9         dst[5] = 12;
(gdb) next
10        wcsncpy(dst, src, 5);
(gdb) next
11        dst[4] = 0;
(gdb) print dst[4]
$1 = 5
(gdb) print dst[5]
$2 = 0
============================================


               
>Fix:
NetBSD has fixed it.
http://cvsweb.netbsd.org/bsdweb.cgi/src/lib/libc/string/wcsncpy.c.diff?r1=1.2&r2=1.3

The log seems irrelevant, though:
"wcsncpy - SUSv6 if s2 is shorter than n, s1 should be filled with L'\0' until n."


>Release-Note:
>Audit-Trail:
>Unformatted: