Project

General

Profile

Bug #6961

64-bit octal printf may overflow internal buffer

Added by Kiichi Ozaki almost 5 years ago. Updated almost 4 years ago.

Status:
Closed
Priority:
Normal
Category:
lib - userland libraries
Start date:
2016-05-10
Due date:
% Done:

100%

Estimated time:
Difficulty:
Medium
Tags:
Gerrit CR:

Description

There is a problem with printf family in 64bit libc.

[repro steps]

$ cat print.c
#include <stdio.h>
int main()
{
    printf("%lo", ~0L);
    return 0;
}
$ gcc -m64 print.c
$ ./a.out
777777777777777777777
$ ./a.out | od -Ax -tx1
000000 00 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37
000010 37 37 37 37 37 37
000016

Unexpectedly, first output character is NUL.

additional evidence:

#include <stdio.h>
#include <string.h>

int
main(void)
{
        int i;
        char buf[32];

        memset(buf, 'r', sizeof (buf));
        sprintf(buf + 4, "%lo", ~0L);

        for (i = 0; i < 32; i++) {
                printf("%2d: %2x\n", i, buf[i]);
        }

        return (0);
}

output:

 0: 72
 1: 72
 2: 72
 3: 72
 4:  0
 5: 37
 6: 37
 7: 37
 8: 37
 9: 37
10: 37
11: 37
12: 37
13: 37
14: 37
15: 37
16: 37
17: 37
18: 37
19: 37
20: 37
21: 37
22: 37
23: 37
24: 37
25: 37
26:  0
27: 72
28: 72
29: 72
30: 72
31: 72

[environment]

OpenIndiana (hipster) and maybe other illumos distributions.

[cause]

https://github.com/illumos/illumos-gate/blob/master/usr/src/lib/libc/port/print/doprnt.c#L1213
https://github.com/illumos/illumos-gate/blob/master/usr/src/lib/libc/port/print/print.h#L66

p = bp = buf + MAXLLDIGS;

This allocates MAXLLDIGS (==21) chars, but ~0 (64bit) otcal is 1777777777777777777777, 22 chars.

https://github.com/illumos/illumos-gate/blob/master/usr/src/lib/libc/port/print/doprnt.c#L1237-L1241

Finally,

buf[-1] is '1'
buf[ 0] is '7'
...
buf[20] is '7'

and bp points &buf[-1]. This is out-of-bound error.

https://github.com/illumos/illumos-gate/blob/master/usr/src/lib/libc/port/print/doprnt.c#L2098

Stack layout is maybe below (OpenIndiana, 64bit libc):

%rbp-0xff0  char   *p     (declared at #L457)
...
%rbp-0xfd8  ssize_t n     (declared at #L661)
%rbp-0xfd0  char    buf[] (declared at #L509)
n = p - bp;

Thus n becomes 22 and buf[-1] becomes 0.

[solution]

I think, simply, we should set MAXLLDIGS to 22.

Also available in: Atom PDF