Fix double free in __printf_fp_l (bug 26214)

Adhemerval Zanella adhemerval.zanella@linaro.org
Thu Jul 9 20:53:12 GMT 2020



On 08/07/2020 15:01, Joseph Myers wrote:
> __printf_fp_l has a double free bug in the case where it allocates
> memory with malloc internally, then has an I/O error while outputting
> trailing padding and tries to free that already-freed memory when the
> error occurs.  This patch fixes this by setting the relevant pointer
> to NULL after the first free (the only free of this pointer that isn't
> immediately followed by returning from the function).
> 
> Tested for x86_64 and x86.

LGTM, thanks.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>

> 
> diff --git a/stdio-common/Makefile b/stdio-common/Makefile
> index 73bf0da296..dc3fd38a19 100644
> --- a/stdio-common/Makefile
> +++ b/stdio-common/Makefile
> @@ -67,7 +67,8 @@ tests := tstscanf test_rdwr test-popen tstgetln test-fseek \
>  	 tst-renameat2 tst-bz11319 tst-bz11319-fortify2 \
>  	 scanf14a scanf16a \
>  	 tst-printf-bz25691 \
> -	 tst-vfprintf-width-prec-alloc
> +	 tst-vfprintf-width-prec-alloc \
> +	 tst-printf-fp-free
>  
>  
>  test-srcs = tst-unbputc tst-printf tst-printfsz-islongdouble

Ok.

> @@ -78,11 +79,13 @@ tests-special += $(objpfx)tst-unbputc.out $(objpfx)tst-printf.out \
>  		 $(objpfx)tst-setvbuf1-cmp.out \
>  		 $(objpfx)tst-vfprintf-width-prec-mem.out \
>  		 $(objpfx)tst-printfsz-islongdouble.out \
> -		 $(objpfx)tst-printf-bz25691-mem.out
> +		 $(objpfx)tst-printf-bz25691-mem.out \
> +		 $(objpfx)tst-printf-fp-free-mem.out
>  generated += tst-printf-bz18872.c tst-printf-bz18872.mtrace \
>  	     tst-printf-bz18872-mem.out \
>  	     tst-vfprintf-width-prec.mtrace tst-vfprintf-width-prec-mem.out \
> -	     tst-printf-bz25691.mtrace tst-printf-bz25691-mem.out
> +	     tst-printf-bz25691.mtrace tst-printf-bz25691-mem.out \
> +	     tst-printf-fp-free.mtrace tst-printf-fp-free-mem.out
>  endif
>  
>  tests-special += $(objpfx)tst-errno-manual.out
> @@ -108,6 +111,8 @@ tst-vfprintf-width-prec-ENV = \
>    MALLOC_TRACE=$(objpfx)tst-vfprintf-width-prec.mtrace
>  tst-printf-bz25691-ENV = \
>    MALLOC_TRACE=$(objpfx)tst-printf-bz25691.mtrace
> +tst-printf-fp-free-ENV = \
> +  MALLOC_TRACE=$(objpfx)tst-printf-fp-free.mtrace
>  
>  $(objpfx)tst-unbputc.out: tst-unbputc.sh $(objpfx)tst-unbputc
>  	$(SHELL) $< $(common-objpfx) '$(test-program-prefix)' > $@; \

Ok.

> diff --git a/stdio-common/printf_fp.c b/stdio-common/printf_fp.c
> index 9e0ce962f2..49c693575e 100644
> --- a/stdio-common/printf_fp.c
> +++ b/stdio-common/printf_fp.c
> @@ -1250,6 +1250,9 @@ __printf_fp_l (FILE *fp, locale_t loc,
>  	{
>  	  free (buffer);
>  	  free (wbuffer);
> +	  /* Avoid a double free if the subsequent PADN encounters an
> +	     I/O error.  */
> +	  wbuffer = NULL;
>  	}
>      }
>  

Ok.

> diff --git a/stdio-common/tst-printf-fp-free.c b/stdio-common/tst-printf-fp-free.c
> new file mode 100644
> index 0000000000..fea52248e0
> --- /dev/null
> +++ b/stdio-common/tst-printf-fp-free.c
> @@ -0,0 +1,37 @@
> +/* Test double free bug in __printf_fp_l (bug 26214).
> +   Copyright (C) 2020 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <mcheck.h>
> +#include <stdio.h>
> +#include <sys/resource.h>
> +#include <support/check.h>
> +
> +static int
> +do_test (void)
> +{
> +  mtrace ();
> +  FILE *fp = fopen ("/dev/full", "w");
> +  TEST_VERIFY_EXIT (fp != NULL);
> +  char buf[131072];
> +  TEST_VERIFY_EXIT (setvbuf (fp, buf, _IOFBF, sizeof buf) == 0);
> +  TEST_COMPARE (fprintf (fp, "%-1000000.65536f", 1.0), -1);
> +  fclose (fp);
> +  return 0;
> +}
> +
> +#include <support/test-driver.c>
> 

Ok.


More information about the Libc-alpha mailing list