[PATCH] top: fix double free causing a SIGABRT storm after SIGPIPE

Luca Ceresoli luca at lucaceresoli.net
Thu Aug 18 21:04:37 UTC 2016


On some platforms the command 'top -n1 | head' goes very often into an
infinite loop of SIGABRT and double free()s.

This happens only if FEATURE_TOP_CPU_USAGE_PERCENTAGE,
CONFIG_FEATURE_CLEAN_UP and FEATURE_USE_TERMIOS are all set.

What happens is that, at the very end of top_main(), reset_term() is
called to free allocated memory. reset_term() calls free(prev_hist)
without setting prev_hist to NULL, which _looks_ OK since we're about
to exit.

Immediately after we receive SIGPIPE because 'tail' discarded some of
our output. Thus the sig_catcher() handler is called, which calls
reset_term() to free allocated memory... which calls free(prev_hist)
again on the same address. glibc detects the double free and
complains:

  *** Error in `top': double free or corruption (!prev): 0x000c9110 ***

And here we get SIGABRT. sig_catcher() is invoked again, leading to
another free(prev_hist). This repeats for several minutes, until the
process get a SIGSEGV and is finally killed.

Fix the bug by setting prev_hist to NULL after free()ing it.

On ARM926 platform with a glibc toolchain the bug is very frequent (at
least 50% of the times). I was not able to reproduce it on my x86_64
Ubuntu laptop. It does not happen with uClibc either, but I guess
that's because it just does not detect the double free and goes on
until the process exits.

Signed-off-by: Luca Ceresoli <luca at lucaceresoli.net>
Cc: "Yann E. MORIN" <yann.morin.1998 at free.fr>

---

Not sure it should be mentioned in the official commit message, but
here's the simplest way I could find to reproduce the bug. It exibits
with one of the qemu defconfigs shipped with Buildroot, modified to
use glibc (or an external Code Sourcery ARM toolchain).

Steps to reproduce with a Buildroot internal toolchain:

  wget -O - https://buildroot.org/downloads/buildroot-2016.05.tar.bz2 | tar xjf
  cd buildroot-2016.05/
  cp configs/qemu_arm_versatile_defconfig  .config
  echo 'BR2_TOOLCHAIN_BUILDROOT_GLIBC=y' >>.config
  make olddefconfig
  make
  # go grab a coffee...
  qemu-system-arm -M versatilepb -kernel output/images/zImage \
    -dtb output/images/versatile-pb.dtb \
    -drive file=output/images/rootfs.ext2,if=scsi,format=raw \
    -append "root=/dev/sda console=ttyAMA0,115200" -serial stdio \
    -net nic,model=rtl8139 -net user -display vnc=localhost:0
---
 procps/top.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/procps/top.c b/procps/top.c
index 73cd285f0fc5..38728af97b3a 100644
--- a/procps/top.c
+++ b/procps/top.c
@@ -732,6 +732,7 @@ static void reset_term(void)
 		clearmems();
 # if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
 		free(prev_hist);
+		prev_hist = NULL;
 # endif
 	}
 }
-- 
2.7.4



More information about the busybox mailing list