Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20190314165335.GJ28106@voyager>
Date: Thu, 14 Mar 2019 17:53:35 +0100
From: Markus Wichmann <nullplan@....net>
To: musl@...ts.openwall.com
Subject: Re: segfault on sscanf

On Thu, Mar 14, 2019 at 05:28:14PM +0100, Markus Wichmann wrote:
>   #include <stdio.h>
> 
>         int main(void) {
>                 const char *too_parse = "0";
>                 double f1;
>                 char dummy;
>                 sscanf(too_parse, "%f%c", &f1, &dummy);
> 
>                 printf("f1=%f, dummy=\"%c\"\n", f1, dummy);
> 
>                 return 0;
>         }
> 
> So, I'm off to read __floatscan(). As I recall, it was complicated, so
> expect me back in about 10 years or so...
> 
> Ciao,
> Markus

Actually, strike that, I think I have it. From __floatscan():


        [among other things c = shgetc(f)]
	if (c=='0') {
		c = shgetc(f);
		if ((c|32) == 'x')
			return hexfloat(f, bits, emin, sign, pok);
		shunget(f);
		c = '0';
	}

The input is just "0". So inside this if-clause, shgetc() will return
EOF and set the FILE's shend to 0. The shunget() therefore does nothing.
Then we continue on to decfloat(). decfloat() will call shget() at least
once. Unfortunately, this is shget()s definition:

#define shgetc(f) (((f)->rpos != (f)->shend) ? *(f)->rpos++ : __shgetc(f))

Since f->shend == 0, but f->rpos == "0"+1, this will start dereferencing
uncharted territory. But it will probably not crash immediately. That's
what the %c parser is for. For %c it will keep parsing forever,
eventually reaching unmapped memory and segfaulting.

Bonus: Since now f->rpos > f->rend, __shlim() does nothing to prevent
this issue.

Maybe the EOF status should be sticky. Like this? (Line break because
e-mail).

#define shgetc(f) (!(f)->shend ? EOF : \
    (f)->rpos != (f)->shend ?  *(f)->rpos++ : __shgetc(f))

That way shgetc() keeps returning EOF until the next call to shlim(), at
which point shgetc() will revert to __shgetc(), which might load more
data, or might go back to EOFing everywhere...

Ciao,
Markus

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.