severity 1078556 grave
tags 1078556 + upstream patch
forwarded 1078556 
https://lists.gnu.org/archive/html/bug-bash/2024-08/msg00087.html
forcemerge 1078556 1078583
thanks

it's crazy to me that these were allowed to stay as normal
(I'd say it's critical, since it "makes unrelated software on the system [...] 
break";
 call it grave since actual usage of printf %f in system-provided
 programs is pretty rare),
or that bash with this bug was allowed to migrate to testing.

My analysis agrees with the mailing list:
  # valgrind bash -c 'printf %f 2'
  ==4136153== Memcheck, a memory error detector
  ==4136153== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
  ==4136153== Using Valgrind-3.20.0 and LibVEX; rerun with -h for copyright info
  ==4136153== Command: bash -c printf\ %f\ 2
  ==4136153==
  ==4136153== Conditional jump or move depends on uninitialised value(s)
  ==4136153==    at 0x48E5435: __printf_fp_buffer_1.isra.0 (printf_fp.c:227)
  ==4136153==    by 0x48E745B: __printf_fp_l_buffer (printf_fp.c:1122)
  ==4136153==    by 0x48EDE4C: __printf_fp_spec (vfprintf-internal.c:266)
  ==4136153==    by 0x48EDE4C: __printf_buffer (vfprintf-internal.c:999)
  ==4136153==    by 0x48EECA0: __vfprintf_internal (vfprintf-internal.c:1544)
  ==4136153==    by 0x49A16A6: __printf_chk (printf_chk.c:33)
  ==4136153==    by 0x1C00A4: printf (stdio2.h:86)
  ==4136153==    by 0x1C00A4: printf_builtin (printf.def:721)
  ==4136153==    by 0x14E969: execute_builtin (execute_cmd.c:4971)
  ==4136153==    by 0x154B24: execute_builtin_or_function (execute_cmd.c:5485)
  ==4136153==    by 0x154B24: execute_simple_command (execute_cmd.c:4737)
  ==4136153==    by 0x154B24: execute_command_internal (execute_cmd.c:866)
  ==4136153==    by 0x1AEF58: parse_and_execute (evalstring.c:539)
  ==4136153==    by 0x139FD9: run_one_command.isra.0 (shell.c:1473)
  ==4136153==    by 0x138AA1: main (shell.c:763)
  ==4136153==
  ==4136153== Conditional jump or move depends on uninitialised value(s)
  ==4136153==    at 0x48E538C: __printf_fp_buffer_1.isra.0 (printf_fp.c:238)
  ==4136153==    by 0x48E745B: __printf_fp_l_buffer (printf_fp.c:1122)
  ==4136153==    by 0x48EDE4C: __printf_fp_spec (vfprintf-internal.c:266)
  ==4136153==    by 0x48EDE4C: __printf_buffer (vfprintf-internal.c:999)
  ==4136153==    by 0x48EECA0: __vfprintf_internal (vfprintf-internal.c:1544)
  ==4136153==    by 0x49A16A6: __printf_chk (printf_chk.c:33)
  ==4136153==    by 0x1C00A4: printf (stdio2.h:86)
  ==4136153==    by 0x1C00A4: printf_builtin (printf.def:721)
  ==4136153==    by 0x14E969: execute_builtin (execute_cmd.c:4971)
  ==4136153==    by 0x154B24: execute_builtin_or_function (execute_cmd.c:5485)
  ==4136153==    by 0x154B24: execute_simple_command (execute_cmd.c:4737)
  ==4136153==    by 0x154B24: execute_command_internal (execute_cmd.c:866)
  ==4136153==    by 0x1AEF58: parse_and_execute (evalstring.c:539)
  ==4136153==    by 0x139FD9: run_one_command.isra.0 (shell.c:1473)
  ==4136153==    by 0x138AA1: main (shell.c:763)
  ==4136153==
  -nan==4136153==
  ==4136153== HEAP SUMMARY:
  ==4136153==     in use at exit: 53,517 bytes in 422 blocks
  ==4136153==   total heap usage: 459 allocs, 37 frees, 57,384 bytes allocated
  ==4136153==
  ==4136153== LEAK SUMMARY:
  ==4136153==    definitely lost: 0 bytes in 0 blocks
  ==4136153==    indirectly lost: 0 bytes in 0 blocks
  ==4136153==      possibly lost: 0 bytes in 0 blocks
  ==4136153==    still reachable: 53,517 bytes in 422 blocks
  ==4136153==         suppressed: 0 bytes in 0 blocks
  ==4136153== Rerun with --leak-check=full to see details of leaked memory
  ==4136153==
  ==4136153== Use --track-origins=yes to see where uninitialised values come 
from
  ==4136153== For lists of detected and suppressed errors, rerun with: -s
  ==4136153== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
and this clearly shows that bash is actually using a normal-length
double (strtod()):
  strchr("#'-+ 0", 'f')                                                         
                            = nil
  strchr("hjlLtz", 'f')                                                         
                            = nil
  __errno_location()                                                            
                            = 0x7fdd273a86c8
  strtod("2", "")                                                               
                            = 2.000000
  strlen("%f")                                                                  
                            = 2
  malloc(1024)                                                                  
                            = 0x55ce477f5ee0
  memcpy(0x55ce477f5ee0, "%", 1)                                                
                            = 0x55ce477f5ee0
  clearerr(0x7fdd275825c0, 76, 0, 1)                                            
                            = 0xfbad2284
  __printf_chk(1, 0x55ce477f5ee0, 0, 1)                                         
                            = 2094
and if it's giving that to %Lf then that's obviously wrong and the
other half of the long double is uninitialised.

This bug is only made visible because the configuration script
is /also/ broken, since bookworm bash uses strtold().
This was identified by upstream and a patch is given in
  https://lists.gnu.org/archive/html/bug-bash/2024-08/msg00090.html

I've verified that on sid with 5.2.21-2.1 prior to this patch,
strtold() is not detected (and this triggers the bug, per valgrind):
  checking whether strtold is declared... yes
  checking for broken strtold... yes
but with this patch strtold() is detected
  checking whether strtold is declared... yes
  checking for broken strtold... no
and the bug is not triggered
  # valgrind ./debian/bash/usr/bin/bash -c 'printf %f 2'
  ==148139== Memcheck, a memory error detector
  ==148139== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
  ==148139== Using Valgrind-3.20.0 and LibVEX; rerun with -h for copyright info
  ==148139== Command: ./debian/bash/usr/bin/bash -c printf\ %f\ 2
  ==148139==
  2.000000==148139==
  ==148139== HEAP SUMMARY:
  ==148139==     in use at exit: 53,735 bytes in 425 blocks
  ==148139==   total heap usage: 460 allocs, 35 frees, 57,631 bytes allocated
  ==148139==
  ==148139== LEAK SUMMARY:
  ==148139==    definitely lost: 0 bytes in 0 blocks
  ==148139==    indirectly lost: 0 bytes in 0 blocks
  ==148139==      possibly lost: 0 bytes in 0 blocks
  ==148139==    still reachable: 53,735 bytes in 425 blocks
  ==148139==         suppressed: 0 bytes in 0 blocks
  ==148139== Rerun with --leak-check=full to see details of leaked memory
  ==148139==
  ==148139== For lists of detected and suppressed errors, rerun with: -s
  ==148139== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

I'm attaching upstream's configure-strtold-check (reformatted to unified
debian/patches/-compatible format, tested against 5.2.21-2.1).

Best,
--- bash-5.2.21.orig/configure
+++ bash-5.2.21/configure
@@ -15676,7 +15676,7 @@ else $as_nop
 int
 main (void)
 {
-long double r; char *foo, bar; r = strtold(foo, &bar);
+long double r; char *foo, *bar; r = strtold(foo, &bar);
 
   ;
   return 0;
--- bash-5.2.21.orig/configure.ac
+++ bash-5.2.21/configure.ac
@@ -885,7 +885,7 @@ AC_CHECK_DECLS([strtold], [
        [AC_COMPILE_IFELSE(
                [AC_LANG_PROGRAM(
                [[#include <stdlib.h>]],
-               [[long double r; char *foo, bar; r = strtold(foo, &bar);]]
+               [[long double r; char *foo, *bar; r = strtold(foo, &bar);]]
        )],
        [bash_cv_strtold_broken=no],[bash_cv_strtold_broken=yes])
         ]

Attachment: signature.asc
Description: PGP signature

Reply via email to