zsh-workers
 help / color / mirror / code / Atom feed
* free() error on simple input scripts
@ 2014-12-06  4:27 Dennis Felsing
  2014-12-06 23:07 ` Bart Schaefer
  0 siblings, 1 reply; 8+ messages in thread
From: Dennis Felsing @ 2014-12-06  4:27 UTC (permalink / raw)
  To: zsh-workers

[-- Attachment #1: Type: text/plain, Size: 2023 bytes --]

Hello,

Simply running zsh (from git) on each of the two attached files causes a
free() error for me:

*** Error in `/usr/local/bin/zsh': free(): invalid next size (fast): 0x00000000009708c0 ***

This has been found fuzzing using AFL: http://lcamtuf.coredump.cx/afl/

Dennis

gdb output:

Program received signal SIGABRT, Aborted.
0x00007ffff6eeb5e7 in raise () from /lib64/libc.so.6
(gdb) bt
#0  0x00007ffff6eeb5e7 in raise () from /lib64/libc.so.6
#1  0x00007ffff6eec9c8 in abort () from /lib64/libc.so.6
#2  0x00007ffff6f2a0d4 in __libc_message () from /lib64/libc.so.6
#3  0x00007ffff6f2f9fe in malloc_printerr () from /lib64/libc.so.6
#4  0x00007ffff6f30716 in _int_free () from /lib64/libc.so.6
#5  0x00000000006fccfd in unmeta (file_name=0x7fffffffc1d0 "/media/intel/vtune_amplifier_xe_2011/bin64/d\203")
    at utils.c:4238
#6  0x0000000000473137 in iscom (s=0x7fffffffc1d0 "/media/intel/vtune_amplifier_xe_2011/bin64/d\203")
    at exec.c:824
#7  hashcmd (arg0=0x7ffff7ff3560 "d\203", pp=0x969168, pp@entry=0x969160) at exec.c:878
#8  0x0000000000489575 in execcmd (state=0x7fffffffd820, input=0, output=0, how=<optimized out>, last1=2)
    at exec.c:2886
#9  0x000000000049059e in execpline2 (state=0x7fffffffd820, pcode=16729, pcode@entry=131, how=18, input=0, 
    output=0, last1=5798544, last1@entry=0) at exec.c:1698
#10 0x0000000000491294 in execpline (state=state@entry=0x7fffffffd820, slcode=<optimized out>, 
    how=how@entry=18, last1=<optimized out>) at exec.c:1485
#11 0x00000000004952ab in execlist (state=state@entry=0x7fffffffd820, dont_change_job=dont_change_job@entry=0, 
    exiting=exiting@entry=0) at exec.c:1268
#12 0x0000000000495ce7 in execode (p=0x7ffff7ff33f0, dont_change_job=0, exiting=0, context=0x72a141 "toplevel")
    at exec.c:1074
#13 0x0000000000515861 in loop (toplevel=1, justonce=0) at init.c:185
#14 zsh_main (argc=<optimized out>, argv=<optimized out>) at init.c:1649
#15 0x00007ffff6ed7dc5 in __libc_start_main () from /lib64/libc.so.6
#16 0x0000000000413829 in _start ()

[-- Attachment #2: id:000000,sig:06,src:000000,op:havoc,rep:16 --]
[-- Type: application/octet-stream, Size: 26 bytes --]

[-- Attachment #3: id:000001,sig:06,src:000002,op:havoc,rep:8 --]
[-- Type: application/octet-stream, Size: 7 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: free() error on simple input scripts
  2014-12-06  4:27 free() error on simple input scripts Dennis Felsing
@ 2014-12-06 23:07 ` Bart Schaefer
  2014-12-07  6:36   ` Bart Schaefer
  2014-12-08 12:51   ` Jun T.
  0 siblings, 2 replies; 8+ messages in thread
From: Bart Schaefer @ 2014-12-06 23:07 UTC (permalink / raw)
  To: Dennis Felsing, zsh-workers

On Dec 6,  5:27am, Dennis Felsing wrote:
}
} Simply running zsh (from git) on each of the two attached files causes a
} free() error for me:

These are both unicode files, at least one in 16-bit with a byte-order
prefix, and are therefore not valid input to the shell.

If you're in a situation where you're being caused to feed the shell
unknown or invalid input, you're already way worse off than can be
helped by avoiding a bad free() ...

However, it appears that both unmeta() and unmetafy() have trouble with
this input, e.g., unmeta() sees a META byte immediately before the end
of string NUL and therefore runs off the end at the second *t++ in this
loop:

    for (t = file_name, p = fn; *t; p++)
	if ((*p = *t++) == Meta)
	    *p = *t++ ^ 32;

This ought to get caught well before we reach this part of the function,
but I'm not sure what the correct reaction is.  Anyway, the failure of
unmeta[fy] cascades into errors in metafy() later.

Maybe this?  Though how we ended up with a bad metafied string in the
first place might also be worth investigating.

diff --git a/Src/utils.c b/Src/utils.c
index 9268147..5c90638 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -4164,7 +4164,7 @@ unmetafy(char *s, int *len)
 
     for (p = s; *p && *p != Meta; p++);
     for (t = p; (*t = *p++);)
-	if (*t++ == Meta)
+	if (*t++ == Meta && *p)
 	    t[-1] = *p++ ^ 32;
     if (len)
 	*len = t - s;
@@ -4208,8 +4208,10 @@ unmeta(const char *file_name)
     
     meta = 0;
     for (t = file_name; *t; t++) {
-	if (*t == Meta)
-	    meta = 1;
+	if (*t == Meta) {
+	    meta = t[1];
+	    break;
+	}
     }
     if (!meta) {
 	/*


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: free() error on simple input scripts
  2014-12-06 23:07 ` Bart Schaefer
@ 2014-12-07  6:36   ` Bart Schaefer
  2014-12-09 15:45     ` Jun T.
  2014-12-08 12:51   ` Jun T.
  1 sibling, 1 reply; 8+ messages in thread
From: Bart Schaefer @ 2014-12-07  6:36 UTC (permalink / raw)
  To: zsh-workers

On Dec 6,  3:07pm, Bart Schaefer wrote:
}
} Though how we ended up with a bad metafied string in the
} first place might also be worth investigating.

I can reproduce the bad free with

    source =(<<<$'d\\\0')

There seems to be some problem with lexing the sequence backslash-nul,
which results in the bad meta-pair.  I haven't been able to isolate.


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: free() error on simple input scripts
  2014-12-06 23:07 ` Bart Schaefer
  2014-12-07  6:36   ` Bart Schaefer
@ 2014-12-08 12:51   ` Jun T.
  2014-12-08 16:37     ` Bart Schaefer
  1 sibling, 1 reply; 8+ messages in thread
From: Jun T. @ 2014-12-08 12:51 UTC (permalink / raw)
  To: zsh-workers

After the commit
48cd1b6c3b51a7bc6d45d4aeb7ff8c55d97a6f2a
    33894: boundary conditions in unmeta(), unmetafy()

test D07multibyte fails on my Mac as follows:

./D07multibyte.ztst: starting.
Testing multibyte with locale en_US.UTF-8
Test ./D07multibyte.ztst failed: bad status 134, expected 0 from:
  mkdir 梶浦由記 'Пётр Ильич Чайковский'
  (cd 梶浦由記; print ${${(%):-%~}:t})
  (cd 'Пётр Ильич Чайковский'; print ${${(%):-%~}:t})
Error output:
zsh(74285,0x7fff72bb3310) malloc: *** error for object 0x7f8162504998: incorrect checksum for freed object - object was probably modified after being freed.
*** set a breakpoint in malloc_error_break to debug
Was testing: Metafied characters in prompt expansion
./D07multibyte.ztst: test failed.

It seems the problem is in the following hunk:

> @@ -4208,8 +4208,10 @@ unmeta(const char *file_name)
> 
>     meta = 0;
>     for (t = file_name; *t; t++) {
> -	if (*t == Meta)
> -	    meta = 1;
> +	if (*t == Meta) {
> +	    meta = t[1];
> +	    break;
> +	}
>     }

Breaking out of the for-loop leaves the pointer t at the first Meta
in file_name, and the value of newsz becomes too small.

How about the following?

diff --git a/Src/utils.c b/Src/utils.c
index 5c90638..ab3d3da 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -4208,10 +4208,8 @@ unmeta(const char *file_name)
     
     meta = 0;
     for (t = file_name; *t; t++) {
-	if (*t == Meta) {
-	    meta = t[1];
-	    break;
-	}
+	if (*t == Meta)
+	    meta = 1;
     }
     if (!meta) {
 	/*
@@ -4250,7 +4248,7 @@ unmeta(const char *file_name)
     }
 
     for (t = file_name, p = fn; *t; p++)
-	if ((*p = *t++) == Meta)
+	if ((*p = *t++) == Meta && *t)
 	    *p = *t++ ^ 32;
     *p = '\0';
     return fn;




^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: free() error on simple input scripts
  2014-12-08 12:51   ` Jun T.
@ 2014-12-08 16:37     ` Bart Schaefer
  0 siblings, 0 replies; 8+ messages in thread
From: Bart Schaefer @ 2014-12-08 16:37 UTC (permalink / raw)
  To: Jun T., zsh-workers

On Dec 8,  9:51pm, Jun T. wrote:
}
} Breaking out of the for-loop leaves the pointer t at the first Meta
} in file_name, and the value of newsz becomes too small.
} 
} How about the following?

Yes, that would be better.  I didn't notice that t was being used to
compute a length.


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: free() error on simple input scripts
  2014-12-07  6:36   ` Bart Schaefer
@ 2014-12-09 15:45     ` Jun T.
  2014-12-09 17:30       ` Peter Stephenson
  2014-12-09 22:13       ` Bart Schaefer
  0 siblings, 2 replies; 8+ messages in thread
From: Jun T. @ 2014-12-09 15:45 UTC (permalink / raw)
  To: zsh-workers


2014/12/07 15:36, Bart Schaefer <schaefer@brasslantern.com> wrote:

>    source =(<<<$'d\\\0')

The input backslash-null is metafiled by shingetline() to
backslash-meta-space (since 0 xor 32 = 32 = ' '), but it seems
the lexer does not treat the meta after backslash specially and
interprets the space as a word separator; this results in a
word ending with meta.

What is the "correct" behavior for the input backslash-null?
The following may be a possibility but I'm not sure.
(The ifdef DEBUG part is copied from line 1059 in the same file)


diff --git a/Src/lex.c b/Src/lex.c
index 1a854f5..b2a0544 100644
--- a/Src/lex.c
+++ b/Src/lex.c
@@ -1326,8 +1326,20 @@ gettokstr(int c, int sub)
 		c = hgetc();
 		if (!lexstop)
 		    continue;
-	    } else
+	    } else {
 		add(Bnull);
+		if (c == STOUC(Meta)) {
+		    c = hgetc();
+#ifdef DEBUG
+		    if (lexstop) {
+			fputs("BUG: input terminated by Meta\n", stderr);
+			fflush(stderr);
+			goto brk;
+		    }
+#endif
+		    add(Meta);
+		}
+	    }
 	    if (lexstop)
 		goto brk;
 	    break;



^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: free() error on simple input scripts
  2014-12-09 15:45     ` Jun T.
@ 2014-12-09 17:30       ` Peter Stephenson
  2014-12-09 22:13       ` Bart Schaefer
  1 sibling, 0 replies; 8+ messages in thread
From: Peter Stephenson @ 2014-12-09 17:30 UTC (permalink / raw)
  To: zsh-workers

On Wed, 10 Dec 2014 00:45:42 +0900
Jun T. <takimoto-j@kba.biglobe.ne.jp> wrote:
> 2014/12/07 15:36, Bart Schaefer <schaefer@brasslantern.com> wrote:
> 
> >    source =(<<<$'d\\\0')
> 
> The input backslash-null is metafiled by shingetline() to
> backslash-meta-space (since 0 xor 32 = 32 = ' '), but it seems
> the lexer does not treat the meta after backslash specially and
> interprets the space as a word separator; this results in a
> word ending with meta.
> 
> What is the "correct" behavior for the input backslash-null?
> The following may be a possibility but I'm not sure.
> (The ifdef DEBUG part is copied from line 1059 in the same file)

I *think* your patch is correct.

Certainly, it is valid to get metafied input at the lexer.  See for
example the end of zleread() which calls zlegetline() which calls
zlelineasstring (typically --- unless we already have a metafied line)
which metafies the line that's about to be returned.

I'm a bit surprised the lexer doesn't have more cases like this, or a
more general way of dealing with metafied characters, but handling a
backslash the way you suggest looks perfectly OK.  However, wait and see
what Bart says, too.

pws


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: free() error on simple input scripts
  2014-12-09 15:45     ` Jun T.
  2014-12-09 17:30       ` Peter Stephenson
@ 2014-12-09 22:13       ` Bart Schaefer
  1 sibling, 0 replies; 8+ messages in thread
From: Bart Schaefer @ 2014-12-09 22:13 UTC (permalink / raw)
  To: zsh-workers

On Dec 10, 12:45am, Jun T. wrote:
}
} What is the "correct" behavior for the input backslash-null?

Meta should always be Meta, even after a backslash; the whole point
of the Meta byte is that it introduces a two-character pair that
represents a single character, and the backslash should precede
whatever the represented character is, resulting in a 3-byte token
when backslash means "quote the next character" (which I think it
always does mean during gettokstr).

} The following may be a possibility but I'm not sure.
} (The ifdef DEBUG part is copied from line 1059 in the same file)

I agree with Peter that this patch looks correct.


^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2014-12-09 22:13 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-12-06  4:27 free() error on simple input scripts Dennis Felsing
2014-12-06 23:07 ` Bart Schaefer
2014-12-07  6:36   ` Bart Schaefer
2014-12-09 15:45     ` Jun T.
2014-12-09 17:30       ` Peter Stephenson
2014-12-09 22:13       ` Bart Schaefer
2014-12-08 12:51   ` Jun T.
2014-12-08 16:37     ` Bart Schaefer

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).