|
Message-ID: <CAOG6P-OY69pdfs8-Q=0ZkNcSnEK6WCpZhX16YCTWa_j3vSBXoA@mail.gmail.com> Date: Wed, 7 Nov 2018 14:54:02 -0600 From: CM Graff <cm0graff@...il.com> To: musl@...ts.openwall.com Subject: Re: printf family handling of INT_MAX +1 tested on aarch64 RIch, It just produces a segfault on debian aarch64 in my test case. Whereas INTMAX + 2 does not. So I thought it worth reporting. graff@...b-debian-arm:~/hlibc-test/tests-emperical/musl$ ./usr/bin/musl-gcc ../printf_overflow.c graff@...b-debian-arm:~/hlibc-test/tests-emperical/musl$ ./usr/bin/musl-gcc -static ../printf_overflow.c graff@...b-debian-arm:~/hlibc-test/tests-emperical/musl$ ./a.out > logfile Segmentation fault graff@...b-debian-arm:~/hlibc-test/tests-emperical/musl$ uname -a Linux hlib-debian-arm 4.9.0-8-arm64 #1 SMP Debian 4.9.110-3+deb9u6 (2018-10-08) aarch64 GNU/Linux graff@...b-debian-arm:~/hlibc-test/tests-emperical/musl$ I can supply access to the 96 core 124 GB RAM aarch64 debian test box if it would help reproduce the segfault. Just email me a public key if you want access. Graff On 11/7/18, Rich Felker <dalias@...c.org> wrote: > On Wed, Nov 07, 2018 at 01:33:13PM -0600, CM Graff wrote: >> Hello everyone, >> >> The C standard states that: >> "The number of characters or wide characters transmitted by a formatted >> output >> function (or written to an array, or that would have been written to an >> array) >> is greater >> than INT_MAX" is undefined behavior. >> >> POSIX states that: >> >> "In addition, all forms of fprintf() shall fail if: >> >> [...] >> [EOVERFLOW] >> [CX] [Option Start] The value to be returned is greater than >> {INT_MAX}. >> [Option End] >> " >> >> Though arguments of over INT_MAX are undefined behavior it seems like >> some >> provisions have been made in musl to handle it, and the method for >> handling >> such appear similar in effect to that of glibc and freebsd's libc. INT_MAX >> + 2 >> appears to represent this case, however INT_MAX + 1 produces a segfault on >> my >> aarch64 test box running debian version 9.5. > ^^^^^^^^^^^^^^^^^^^^^^^^^^ > > At first this sounded like you were using glibc, but based on the > below test program it seems you're using the musl-gcc wrapper, then > running musl binaries on the same box. Ok, this should work. > >> I do not have a suggested fix other than to either carefully inspect the >> EOVERFLOW semantics or to mitigate the need for more complex mathematics >> by >> using a size_t as the primary counter for the stdio family instead of an >> int. > > The counter is not incremented without seeing that the increment would > not cause overflow. See vfprintf.c lines 447-450: > > /* This error is only specified for snprintf, but since it's > * unspecified for other forms, do the same. Stop immediately > * on overflow; otherwise %n could produce wrong results. */ > if (l > INT_MAX - cnt) goto overflow; > >> This segfault was discovered when testing my own small libc >> (https://github.com/hlibc/hlibc) against the various robust production >> grade >> libc to understand more about how to properly handle EOVERFLOW and in >> general >> the cases of INT_MAX related undefined behavior for the formatted stdio >> functions as per specified in the C standard and POSIX. >> >> I am not sure that handling this is an important case for musl, however I >> thought it best to report the scenario as best I could describe it. > > I don't understand exactly what you're claiming is wrong. If it's a > segfault, where does it occur? > >> Here is a script and a small C program to verify this segfault on >> aarch64, >> I apologize for not testing on other architectures but my time is limited >> lately as I'm working toward my degree in mathematics. >> >> #!/bin/sh >> git clone git://git.musl-libc.org/musl >> cd musl >> ../configure --prefix=$(pwd)/usr >> make -j4 > log 2>&1 >> make install >> log 2>&1 >> ../usr/bin/musl-gcc -static ../printf_overflow.c >> ../a.out > log2 >> >> >> >> #include <stdio.h> >> #include <limits.h> >> #include <errno.h> >> #include <string.h> >> #include <stdlib.h> >> int main(void) >> { >> size_t i = INT_MAX; >> ++i; >> char *s = malloc(i); >> if (!(s)) >> { >> fprintf(stderr, "unable to allocate enough memory\n"); >> return 1; >> } >> memset(s, 'A', i - 1); >> s[i] = 0; >> /* make sure printf is not changed to puts() by the compiler */ >> int len = printf("%s", s, 1); >> >> if (errno == EOVERFLOW) >> fprintf(stderr, "printf set EOVERFLOW\n"); >> else >> fprintf(stderr, "printf did not set EOVERFLOW\n"); >> >> fprintf(stderr, "printf returned %d\n", len); >> return 0; >> } > > There is nothing in this test program that overflows. printf produces > precisely INT_MAX bytes of output, which is representable, and > therefore it succeeds and returns INT_MAX. I tested this on x86_64 > (it's not possible as written on 32-bit archs since INT_MAX+1 is not > allocatable, although you could do similar tests like using %s%s to > print the same INT_MAX/2-size string twice) and it worked as expected. > > Rich >
Powered by blists - more mailing lists
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.