Uploaded image for project: 'RHEL'
  1. RHEL
  2. RHEL-22295

Async unsafe calls in bash EXIT trap

    • Icon: Bug Bug
    • Resolution: Won't Do
    • Icon: Undefined Undefined
    • None
    • rhel-7.9.z, rhel-8.8.0, rhel-9.3.0
    • bash
    • None
    • None
    • None
    • rhel-sst-cs-plumbers
    • ssg_core_services
    • None
    • False
    • Hide

      None

      Show
      None
    • None
    • Red Hat Enterprise Linux
    • None
    • None
    • None
    • All
    • None

        After providing a test package with the fix for bash hang due to unsafe call to malloc from signal handler - PIPESTATUS variable issue

      the customer experienced a new race condition:

      (gdb) bt
      #0  __lll_lock_wait_private () at ../nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:95
      #1  0x00007f6d3e94ab12 in _L_lock_16654 () at malloc.c:5190
      #2  0x00007f6d3e947753 in {}GI{}_libc_malloc (bytes=140107181496160, bytes@entry=8) at malloc.c:2903
      #3  0x000000000046a91b in xmalloc (bytes=8) at xmalloc.c:112
      #4  0x0000000000454cc3 in run_exit_trap () at trap.c:742
      #5  0x0000000000456d94 in termsig_handler (sig=15) at sig.c:562
      #6  0x0000000000440f6b in waitchld (block=block@entry=0, wpid=-1) at jobs.c:3090
      #7  0x0000000000441508 in sigchld_handler (sig=<optimized out>) at jobs.c:3053
      #8  <signal handler called>
      #9  _int_malloc (av=av@entry=0x7f6d3ec89760 <main_arena>, bytes=bytes@entry=128) at malloc.c:3464
      #10 0x00007f6d3e9476fc in {}GI{}_libc_malloc (bytes=bytes@entry=128) at malloc.c:2905
      #11 0x000000000046a9e5 in xrealloc (pointer=pointer@entry=0x0, bytes=bytes@entry=128) at xmalloc.c:133
      #12 0x000000000044a0c7 in read_comsub (rflag=<synthetic pointer>, quoted=<optimized out>, fd=<optimized out>) at subst.c:5193
      #13 command_substitute (string=string@entry=0x148fd20 "ls", quoted=quoted@entry=0) at subst.c:5443
      #14 0x000000000044cc7d in param_expand (string=string@entry=0x148f2e0 "$(ls)", sindex=sindex@entry=0x7ffe26a1296c, quoted=quoted@entry=0, expanded_something=expanded_something@entry=0x7ffe26a12a30, 
          contains_dollar_at=contains_dollar_at@entry=0x7ffe26a12978, quoted_dollar_at_p=quoted_dollar_at_p@entry=0x7ffe26a12970, had_quoted_null_p=had_quoted_null_p@entry=0x7ffe26a12974, pflags=0) at subst.c:7758
      #15 0x000000000044fe47 in expand_word_internal (word=<optimized out>, quoted=quoted@entry=0, isexp=isexp@entry=0, contains_dollar_at=contains_dollar_at@entry=0x7ffe26a12a34, 
          expanded_something=expanded_something@entry=0x7ffe26a12a30) at subst.c:8152
      #16 0x0000000000452032 in shell_expand_word_list (eflags=31, tlist=0x14912d0) at subst.c:9259
      #17 expand_word_list_internal (list=<optimized out>, eflags=eflags@entry=31) at subst.c:9376
      #18 0x000000000045282a in expand_words (list=<optimized out>) at subst.c:8998
      #19 0x0000000000430c70 in execute_simple_command (simple_command=<optimized out>, pipe_in=pipe_in@entry=-1, pipe_out=pipe_out@entry=-1, async=async@entry=0, fds_to_close=fds_to_close@entry=0x148f2c0)
          at execute_cmd.c:3833
      #20 0x0000000000432393 in execute_command_internal (command=0x1490be0, asynchronous=0, pipe_in=-1, pipe_out=-1, fds_to_close=0x148f2c0) at execute_cmd.c:765
      #21 0x0000000000433d7e in execute_command (command=0x1490be0) at execute_cmd.c:386
      #22 0x000000000041e3b5 in reader_loop () at eval.c:153
      #23 0x000000000041ca1e in main (argc=2, argv=0x7ffe26a12eb8, env=0x7ffe26a12ed0) at shell.c:759

      as you can see, the problem is the race condition in frame #4:

      (gdb) frame 4
      #4 0x0000000000454cc3 in run_exit_trap () at trap.c:742
      742 trap_command = savestring (trap_list[EXIT_TRAP]);

      The patch for the PIPESTATUS variable runs was not enough.
      A possible (untested) pseudo patch could be:

      trap.c:run_exit_trap ()
      ...

      • char *trap_command;

      + char trap_command[8192];

      ...
      + trap_command = savestring (trap_list[EXIT_TRAP]);

      {{+ if (trap_list[EXIT_TRAṔ])

      { strncpy (trap_command, trap_list[EXIT_TRAP], 8192); trap_command[8191] = 0; }

      }}else trap_command = "";
      ...

      8192 is hopefully a sane size for a exit trap. Could increase it, or cause an error if it is larger.

      The exit_trap () code does not release the trap_command string, and it is not
      released in the first levels of the code:

      parse_and_execute (trap_command, "exit trap", SEVAL_NONINT|SEVAL_NOHIST|SEVAL_RESETLINE);

      so, it might even be safe to just patch as:
      - trap_command = savestring (trap_list[EXIT_TRAP]);
      {{+ trap_command = trap_list[EXIT_TRAṔ] ? trap_list[EXIT_TRAP] : "";}}

      but possibly some other race condition will be found after such fix, and the string might be modified in the parse_and_execute call, what probably would not cause harm as it is exiting.

       

              rhn-support-svashish Siteshwar Vashisht
              rhn-support-pandrade Paulo Andrade
              Siteshwar Vashisht Siteshwar Vashisht
              Karel Volný Karel Volný
              Votes:
              0 Vote for this issue
              Watchers:
              4 Start watching this issue

                Created:
                Updated:
                Resolved: