Bug#1036302: free(): double free detected in tcache 2 during history search

2023-08-08 Thread Ben Wong
Thank you for narrowing it down, Bernhard. I’ve further isolated the
problem to libreadline. I have attached a program based on the sample code
from the libreadline documentation which exhibits the same behaviour.

Example run:

$ make
cc rlgets.c  -lreadline -o rlgets

$ make test
bash -c "echo $'foo\nbar\n\cp\cu\cp\cu\cn\cj' | ./rlgets"
prompt> foo
prompt> bar
prompt>
free(): double free detected in tcache 2
bash: line 1: 556449 Doneecho 'foo
bar

'
 556450 Aborted (core dumped) | ./rlgets
make: *** [Makefile:5: test] Error 134

Ben Wong
rlgets.c

#include /* readline() */#include
/* add_history() */#include 
/* free() */
/* A static variable for holding the line. */static char *line_read =
(char *)NULL;
/* Read a string, and return a pointer to it.
   Returns NULL on EOF. */char *
rl_gets (char *prompt)
{
  /* If the buffer has already been allocated,
 return the memory to the free pool. */
  if (line_read)
{
  free (line_read);
  line_read = (char *)NULL;
}

  /* Get a line from the user. */
  line_read = readline (prompt);

  /* If the line has any text in it,
 save it on the history. */
  if (line_read && *line_read)
add_history (line_read);

  return (line_read);
}
int main(int argc, char *argv[]) {
  char *buf;

  rl_bind_key ('p'-'a'+1, rl_history_search_backward);
  rl_bind_key ('n'-'a'+1, rl_history_search_forward);
  read_history("history_file");

  while (1) {
buf = rl_gets("prompt> ");
if (!buf) { break; }
if ( !strncmp(buf, "exit", 4) || !strncmp(buf, "quit", 4) ) { break; }
  }

  write_history ("history_file");
  return 0;
}

Makefile

LDLIBS+=-lreadline
rlgets:rlgets.c

test:rlgets
bash -c "echo $$'foo\nbar\n\cp\cu\cp\cu\cn\cj' | ./rlgets"

clean:
rm rlgets history_file core *~ 2>/dev/null || true

On Fri, Jun 2, 2023 at 3:01 AM Bernhard Übelacker bernha...@mailbox.org
 wrote:

Hello,
> below is the top of a valgrind run
> with dbgsym package installed.
>
> Kind regards,
> Bernhard
>
>
#include 	/* readline() */
#include 	/* add_history() */
#include 		/* free() */

/* A static variable for holding the line. */
static char *line_read = (char *)NULL;

/* Read a string, and return a pointer to it.
   Returns NULL on EOF. */
char *
rl_gets (char *prompt)
{
  /* If the buffer has already been allocated,
 return the memory to the free pool. */
  if (line_read)
{
  free (line_read);
  line_read = (char *)NULL;
}

  /* Get a line from the user. */
  line_read = readline (prompt);

  /* If the line has any text in it,
 save it on the history. */
  if (line_read && *line_read)
add_history (line_read);

  return (line_read);
}

int main(int argc, char *argv[]) {
  char *buf;

  rl_bind_key ('p'-'a'+1, rl_history_search_backward);
  rl_bind_key ('n'-'a'+1, rl_history_search_forward);
  read_history("history_file");


  while (1) {
buf = rl_gets("prompt> ");
if (!buf) { break; }
if ( !strncmp(buf, "exit", 4) || !strncmp(buf, "quit", 4) ) { break; }
  }

  write_history ("history_file");
  return 0;
}
  


Makefile
Description: Binary data


Bug#1036302: free(): double free detected in tcache 2 during history search

2023-06-02 Thread Bernhard Übelacker

Hello,
below is the top of a valgrind run
with dbgsym package installed.

Kind regards,
Bernhard



benutzer@debian:~$ valgrind bash
==1114== Memcheck, a memory error detector
==1114== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
==1114== Using Valgrind-3.19.0 and LibVEX; rerun with -h for copyright info
==1114== Command: bash
==1114==
benutzer@debian:~$ bind '"\C-p": history-search-backward'
benutzer@debian:~$ bind '"\C-n": history-search-forward'
benutzer@debian:~$

Control-P   # history-search-backward
Control-U   # unix-line-discard
Control-P   # history-search-backward
Control-U   # unix-line-discard
Control-N   # history-search-forward
Control-J   # accept-line

==1114== Invalid read of size 4
==1114==at 0x1E9D04: rl_do_undo (undo.c:186)
==1114==by 0x1EA0B4: rl_revert_line (undo.c:337)
==1114==by 0x1CD86C: readline_internal_teardown (readline.c:498)
==1114==by 0x1CEC7B: readline_internal (readline.c:734)
==1114==by 0x1CEC7B: readline (readline.c:387)
==1114==by 0x13AFE1: yy_readline_get (parse.y:1528)
==1114==by 0x13DAE0: yy_getc (parse.y:1462)
==1114==by 0x13DAE0: shell_getc (parse.y:2393)
==1114==by 0x13FF5A: read_token.constprop.0 (parse.y:3402)
==1114==by 0x1440BA: yylex (parse.y:2890)
==1114==by 0x1440BA: yyparse (y.tab.c:1854)
==1114==by 0x13A5B5: parse_command (eval.c:348)
==1114==by 0x13A743: read_command (eval.c:392)
==1114==by 0x13A8F5: reader_loop (eval.c:139)
==1114==by 0x1393D8: main (shell.c:833)
==1114==  Address 0x53ba808 is 24 bytes inside a block of size 32 free'd
==1114==at 0x484317B: free (vg_replace_malloc.c:872)
==1114==by 0x1E9ABA: _rl_free_undo_list (undo.c:111)
==1114==by 0x1F03DF: _rl_free_saved_history_line (misc.c:396)
==1114==by 0x1D4286: rl_history_search_forward (search.c:647)
==1114==by 0x1CDD96: _rl_dispatch_subseq (readline.c:916)
==1114==by 0x1CE371: _rl_dispatch (readline.c:860)
==1114==by 0x1CE371: readline_internal_char (readline.c:675)
==1114==by 0x1CEC64: readline_internal_charloop (readline.c:721)
==1114==by 0x1CEC64: readline_internal (readline.c:733)
==1114==by 0x1CEC64: readline (readline.c:387)
==1114==by 0x13AFE1: yy_readline_get (parse.y:1528)
==1114==by 0x13DAE0: yy_getc (parse.y:1462)
==1114==by 0x13DAE0: shell_getc (parse.y:2393)
==1114==by 0x13FF5A: read_token.constprop.0 (parse.y:3402)
==1114==by 0x1440BA: yylex (parse.y:2890)
==1114==by 0x1440BA: yyparse (y.tab.c:1854)
==1114==by 0x13A5B5: parse_command (eval.c:348)
==1114==  Block was alloc'd at
==1114==at 0x48407B4: malloc (vg_replace_malloc.c:381)
==1114==by 0x1A2C8D: xmalloc (xmalloc.c:114)
==1114==by 0x1E9A4E: alloc_undo_entry (undo.c:75)
==1114==by 0x1E9A4E: rl_add_undo (undo.c:92)
==1114==by 0x1EDB41: rl_delete_text (text.c:152)
==1114==by 0x1E8E4C: rl_kill_text (kill.c:177)
==1114==by 0x1E9466: rl_unix_line_discard (kill.c:412)
==1114==by 0x1CDD96: _rl_dispatch_subseq (readline.c:916)
==1114==by 0x1CE371: _rl_dispatch (readline.c:860)
==1114==by 0x1CE371: readline_internal_char (readline.c:675)
==1114==by 0x1CEC64: readline_internal_charloop (readline.c:721)
==1114==by 0x1CEC64: readline_internal (readline.c:733)
==1114==by 0x1CEC64: readline (readline.c:387)
==1114==by 0x13AFE1: yy_readline_get (parse.y:1528)
==1114==by 0x13DAE0: yy_getc (parse.y:1462)
==1114==by 0x13DAE0: shell_getc (parse.y:2393)
==1114==by 0x13FF5A: read_token.constprop.0 (parse.y:3402)
==1114==
==1114== Invalid read of size 4
...
==1114==
benutzer@debian:~$ exit
...
==1114== ERROR SUMMARY: 85 errors from 13 contexts (suppressed: 0 from 0)
benutzer@debian:~$



Bug#1036302: free(): double free detected in tcache 2 during history search

2023-05-18 Thread Ben Wong
Package: bash
Version: 5.2.15-2+b2
Severity: normal
X-Debbugs-Cc: bugs.debian@wongs.net

Dear Maintainer,

Using history-search-backward and -forward can cause bash to die with
an error:

free(): double free detected in tcache 2
Aborted (core dumped)

This is easily replicated by binding keys to run the history-search-
functions. Start up a fresh bash shell and type the following.

bind '"\C-p": history-search-backward'
bind '"\C-n": history-search-forward'
^P^U^P^U^N^J

Bash will immediately crash.

Note ^ means hold down the control key while pressing the next letter.
So, in the above example, you'd by hitting:

Control-P   # history-search-backward
Control-U   # unix-line-discard
Control-P   # history-search-backward
Control-U   # unix-line-discard
Control-N   # history-search-forward
Control-J   # accept-line


-- System Information:
Debian Release: 12.0
  APT prefers testing-security
  APT policy: (500, 'testing-security'), (500, 'testing')
Architecture: amd64 (x86_64)

Kernel: Linux 6.1.0-9-amd64 (SMP w/8 CPU threads; PREEMPT)
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8), LANGUAGE not set
Shell: /bin/sh linked to /usr/bin/dash
Init: systemd (via /run/systemd/system)
LSM: AppArmor: enabled

Versions of packages bash depends on:
ii  base-files   12.4
ii  debianutils  5.7-0.4
ii  libc62.36-9
ii  libtinfo66.4-4

Versions of packages bash recommends:
ii  bash-completion  1:2.11-6

Versions of packages bash suggests:
ii  bash-doc  5.2.15-2

-- no debconf information