Bug 22183

Summary: commit 5554304f0ddd ("posix: Allow glob to match dangling symlinks") cause "make" segfaults
Product: glibc Reporter: Markus Trippelsdorf <markus>
Component: globAssignee: Adhemerval Zanella <adhemerval.zanella>
Status: RESOLVED FIXED    
Severity: normal CC: adhemerval.zanella
Priority: P2 Flags: fweimer: security-
Version: unspecified   
Target Milestone: 2.27   
Host: Target:
Build: Last reconfirmed:

Description Markus Trippelsdorf 2017-09-22 08:16:06 UTC
Since:

commit 5554304f0dddf75dc27cc6250fc53355161fd16a                                          
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>                               
Date:   Mon Sep 4 16:22:28 2017 -0300       

    posix: Allow glob to match dangling symlinks [BZ #866] 

I get, e.g.:

markus@x4 linux % make
[1]    303 segmentation fault  nice -n 19 make

...
52590 8275  openat(AT_FDCWD, "/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = 3                                                                                                             
52591 8275  read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0@q\2\0\0\0\0\0"..., 832) = 832                                                                                  
52592 8275  fstat(3, {st_mode=S_IFREG|0755, st_size=16657728, ...}) = 0                                                                                                            
52593 8275  mmap(NULL, 1779696, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f3861552000                                                                             
52594 8275  mprotect(0x7f38616fa000, 4096, PROT_NONE) = 0                                                                                                                          
52595 8275  mmap(0x7f38616fb000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1a8000) = 0x7f38616fb000                                                   
52596 8275  mmap(0x7f3861701000, 14320, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f3861701000                                                         
52597 8275  close(3)                          = 0                                                                                                                                  
52598 8275  mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f386154f000                                                                             
52599 8275  arch_prctl(ARCH_SET_FS, 0x7f386154f740) = 0                                                                                                                            
52600 8275  mprotect(0x7f38616fb000, 12288, PROT_READ) = 0                                                                                                                         
52601 8275  mprotect(0x414000, 4096, PROT_READ) = 0                                                                                                                                
52602 8275  mprotect(0x7f386175a000, 4096, PROT_READ) = 0                                                                                                                          
52603 8275  munmap(0x7f3861705000, 171226)    = 0                                                                                                                                  
52604 8275  brk(NULL)                         = 0x1fba000                                                                                                                          
52605 8275  brk(0x1fdb000)                    = 0x1fdb000                                                                                                                          
52606 8275  openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3                                                                                             
52607 8275  fstat(3, {st_mode=S_IFREG|0644, st_size=3155424, ...}) = 0                                                                                                             
52608 8275  mmap(NULL, 3155424, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f386124c000                                                                                                     
52609 8275  close(3)                          = 0                                                                                                                                  
52610 8275  ioctl(0, TCGETS, {B38400 opost isig icanon echo ...}) = 0                                                                                                              
52611 8275  newfstatat(AT_FDCWD, ".8267.tmp", 0x1fbc5b8, AT_SYMLINK_NOFOLLOW) = -1 ENOENT (No such file or directory)                                                              
52612 8275  unlinkat(AT_FDCWD, ".8267.tmp", 0) = -1 ENOENT (No such file or directory)                                                                                             
52613 8275  newfstatat(AT_FDCWD, ".8267.o", 0x1fbc6d8, AT_SYMLINK_NOFOLLOW) = -1 ENOENT (No such file or directory)                                                                
52614 8275  unlinkat(AT_FDCWD, ".8267.o", 0)  = -1 ENOENT (No such file or directory)                                                                                              
52615 8275  lseek(0, 0, SEEK_CUR)             = -1 ESPIPE (Illegal seek)                                                                                                           
52616 8275  close(0)                          = 0                                                                                                                                  
52617 8275  close(1)                          = 0                                                                                                                                  
52618 8275  close(2)                          = 0                                                                                                                                  
52619 8275  exit_group(0)                     = ?                                                                                                                                  
52620 8275  +++ exited with 0 +++                                                                                                                                                  
52621 8267  <... wait4 resumed> [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 8275                                                                                           
52622 8267  rt_sigaction(SIGINT, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7fc196ed8070}, {sa_handler=0x43ca80, sa_mask=[], sa_flags=SA_RESTORER, sa_res      torer=0x7fc196ed8070}, 8) = 0                                                                                                                                                
52623 8267  rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0                                                                                                                           
52624 8267  --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=8275, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---                                                  
52625 8267  wait4(-1, 0x7ffdd4d28a58, WNOHANG, NULL) = -1 ECHILD (No child processes)                                                                                              
52626 8267  rt_sigreturn({mask=[]})           = 0                                                                                                                                  
52627 8267  rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0                                                                                                                           
52628 8267  rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0                                                                                                                           
52629 8267  exit_group(0)                     = ?                                                                                                                                  
52630 8267  +++ exited with 0 +++                                                                                                                                                  
52631 7948  <... read resumed> "", 198)       = 0                                                                                                                                  
52632 7948  close(4)                          = 0                                                                                                                                  
52633 7948  wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 8267                                                                                                     
52634 7948  read(3, "rch/$(SRCARCH)/kernel/vmlinux.ld"..., 4096) = 4096                                                                                                            
52635 7948  --- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0xc8} ---                                                                                                  
52636 7948  +++ killed by SIGSEGV +++
Comment 1 Markus Trippelsdorf 2017-09-22 08:44:13 UTC
Ah, I see that this issue is already being discussed on the mailing-list.
Feel free to close this bug.
Comment 2 Adhemerval Zanella 2017-09-22 12:15:21 UTC
Yes, it was pointed out by Andreas Schwab that this recent modification would break GNUmake in some scenarios.

The current approach to fix it is in twofold [1]:

  * Bump _GNU_GLOB_INTERFACE_VERSION to 2 and forcing new GNUmake build to use its internal glob implementation.  

  * Add a compat symbol with previous semantic that avoid calling gl_lstat and thus avoid breaking make.

Paul Eggert already sent an initial patch to fix it on make side [2], but I think we should also change make configure script to check for _GNU_GLOB_INTERFACE_VERSION 1 and 2 and enable glob for newer implementations as well (with the fix along it).

I will keep the patch open to track this issue, thanks for reporting it. 

[1] https://sourceware.org/ml/libc-alpha/2017-09/msg00718.html
[2] http://lists.gnu.org/archive/html/bug-make/2017-09/msg00014.html
Comment 3 Sourceware Commits 2017-09-26 01:05:03 UTC
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU C Library master sources".

The branch, master has been updated
       via  5f9f31ad129d97e6fc548954c9b97e27dd332600 (commit)
       via  ccf970c7a77e86f4f5ef8ecc5e637114b1c0136a (commit)
      from  b4396163aa8666f970aaf43eaca25f3a92b18c1b (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=5f9f31ad129d97e6fc548954c9b97e27dd332600

commit 5f9f31ad129d97e6fc548954c9b97e27dd332600
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date:   Mon Sep 18 09:26:00 2017 -0300

    scratch_buffer: use union for internal buffer
    
    Problem reported by Florian Weimer [1] and solution suggested by
    Andreas Schwab [2].  It also set the same buffer size independent
    of architecture max_align_t size.
    
    Checked on x86_64-linux-gnu and i686-linux-gnu.
    
    	* lib/malloc/scratch_buffer.h (struct scratch_buffer):
    	Use an union instead of a max_align_t array for __space,
    	so that __space is the same size on all platforms.
    	* malloc/scratch_buffer_grow_preserve.c
    	(__libc_scratch_buffer_grow_preserve): Likewise.
    
    [1] https://sourceware.org/ml/libc-alpha/2017-09/msg00693.html
    [2] https://sourceware.org/ml/libc-alpha/2017-09/msg00695.html

https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=ccf970c7a77e86f4f5ef8ecc5e637114b1c0136a

commit ccf970c7a77e86f4f5ef8ecc5e637114b1c0136a
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date:   Fri Sep 15 11:31:13 2017 -0300

    posix: Add compat glob symbol to not follow dangling symbols
    
    This patch follows commit 5554304f0 (posix: Allow glob to match dangling
    symlinks [BZ #866]) by adding a compat symbol that follow previous
    semantic of not following dangling symlinks and thus avoiding call
    gl_lstat with GLOB_ALTDIRFUNC.
    
    It avoids failure with old binaries that not set the alternate function
    pointer for lstat (GNUmake for instance).  The following scenario, for
    instance, fails with current GNUmake because glibc will access unitialized
    memory when calling gl_lstat:
    
      $ cat src/t/t.c
      int main ()
      {
        return 0;
      }
      $ cat Makefile
      SRC = $(wildcard src/*/t.c)
      OBJ = $(patsubst src/%.c, obj/%.o, $(SRC))
    
      prog:           $(OBJ)
                      $(CC) $(CFLAGS) $(LDFLAGS) $(LIBS) $(OBJ) -o prog
    
      obj/%.o:        src/%.c
                      $(CC) $(CFLAGS) -c $< -o $@
      $ make
    
    This works as expected with the patch applied.  Since it is for generic
    ABI, default compat symbols are added with override for Linux due LFS.
    Now we have two compat symbols for glob on Linux:
    
      1. sysdeps/unix/sysv/linux/oldglob.c which implements glob64 with
         the old dirent layout.  For this implementation I also set it to
         not follow dangling symlinks (which is the safest path).
    
      2. sysdeps/unix/sysv/linux/glob{64}-lstat-compat.c which implements
         the compat symbol for dangling symlinks.  As for generic glob,
         the implementation uses XSTAT_IS_XSTAT64 to define whether
         both __glob_lstat_compat and __glob64_lstat_compat should be
         different implementations.  For archictures that define
         XSTAT_IS_XSTAT64, __glob_lstat_compat is aliased to
         __glob64_lstat_compat.
    
      3. sysdeps/unix/sysv/linux/alpha/oldglob.c with a different glob_t
         layout.  As for 1. this patch changes it to not follow dangling
         symlinks.
    
    The patch also bumps _GNU_GLOB_INTERFACE_VERSION to 2 to advertise the
    new semantic.  On GNUmake, for instance, it will force to it use its
    internal glob implementation instead and avoiding triggering the same
    failure on builds against newer GLIBCs.
    
    Checked on x86_64-linux-gnu and i686-linux-gnu.  I also checked
    with a build against the major ABIs required to check for the abilist.
    
    The changes should also work on gnulib (I run gnulib-tool.py check glob
    and it shown no regressions).
    
    	[BZ #22183]
    	* include/gnu-versions.h (_GNU_GLOB_INTERFACE_VERSION): Increase
    	version to 2.
    	* posix/Makefile (routines): Add glob-lstat-compat and
    	glob64-lstat-compat.
    	* posix/Versions (GLIBC_2.27, glob, glob64): Add symbol version.
    	* posix/glob-lstat-compat.c: New file.
    	* posix/glob64-lstat-compat.c: Likewise.
    	* posix/tst-glob_lstat_compat.c: Likewise.
    	* sysdeps/unix/sysv/linux/glob-lstat-compat.c: Likewise.
    	* sysdeps/unix/sysv/linux/alpha/glob-lstat-compat.c: Likewise.
    	* sysdeps/unix/sysv/linux/glob64-lstat-compat.c: Likewise.
    	* sysdeps/unix/sysv/linux/alpha/glob.c: Remove file.
    	* posix/glob.c (glob_lstat): New function.
    	(glob): Rename to __glob and add versioned symbol to 2.27.
    	(glob_in_dir): Use glob_lstat.
    	* posix/glob64.c (glob64): Add GLOB_ATTRIBUTE.
    	* sysdeps/unix/sysv/linux/arm/libc.abilist: Likewise.
    	* sysdeps/unix/sysv/linux/glob.c (glob): Add versioned symbol for
    	2.27.
    	* sysdeps/unix/sysv/linux/glob64.c (glob64): Likewise.
    	* sysdeps/unix/sysv/linux/oldglob.c (GLOB_NO_LSTAT): Define.
    	* sysdeps/unix/sysv/linux/alpha/oldglob.c (__old_glob): Do not use
    	gl_lstat on glob call.
    	* sysdeps/unix/sysv/linux/aarch64/libc.abilist: Add GLIBC_2.27 glob
    	and glob64 symbols.
    	* sysdeps/unix/sysv/linux/alpha/libc.abilist: Likewise.
    	* sysdeps/unix/sysv/linux/hppa/libc.abilist: Likewise.
    	* sysdeps/unix/sysv/linux/i386/libc.abilist: Likewise.
    	* sysdeps/unix/sysv/linux/ia64/libc.abilist: Likewise.
    	* sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist: Likewise.
    	* sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist: Likewise.
    	* sysdeps/unix/sysv/linux/microblaze/libc.abilist: Likewise.
    	* sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist: Likewise.
    	* sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist: Likewise.
    	* sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist: Likewise.
    	* sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist: Likewise.
    	* sysdeps/unix/sysv/linux/nios2/libc.abilist: Likewise.
    	* sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist:
    	Likewise.
    	* sysdeps/unix/linux/powerpc/powerpc32/nofpu/libc.abilist: Likewise.
    	* sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist: Likewise.
    	* sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist: Likewise.
    	* sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist: Likewise.
    	* sysdeps/unix/sysv/linux/sh/libc.abilist: Likewise.
    	* sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist: Likewise.
    	* sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist: Likewise.
    	* sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist: Likewise.
    	* sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist: Likewise.
    	* sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist: Likewise.
    	* sysdeps/unix/sysv/linux/x86_64/64/libc.abilist: Likewise.
    	* sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist: Likewise.

-----------------------------------------------------------------------

Summary of changes:
 ChangeLog                                          |   64 +++++
 include/gnu-versions.h                             |    2 +-
 include/scratch_buffer.h                           |    6 +-
 malloc/scratch_buffer_grow_preserve.c              |    4 +-
 malloc/tst-scratch_buffer.c                        |    2 +-
 posix/Makefile                                     |    4 +-
 posix/Versions                                     |    3 +
 posix/glob-lstat-compat.c                          |   36 +++
 posix/glob.c                                       |   67 ++++--
 posix/glob64-lstat-compat.c                        |   36 +++
 posix/glob64.c                                     |    5 +
 posix/tst-glob_lstat_compat.c                      |  263 ++++++++++++++++++++
 sysdeps/unix/sysv/linux/aarch64/libc.abilist       |    3 +
 sysdeps/unix/sysv/linux/alpha/glob-lstat-compat.c  |    2 +
 sysdeps/unix/sysv/linux/alpha/glob.c               |   47 ----
 sysdeps/unix/sysv/linux/alpha/libc.abilist         |    3 +
 sysdeps/unix/sysv/linux/alpha/oldglob.c            |    6 +-
 sysdeps/unix/sysv/linux/arm/libc.abilist           |    3 +
 sysdeps/unix/sysv/linux/glob-lstat-compat.c        |   47 ++++
 sysdeps/unix/sysv/linux/glob.c                     |    5 +-
 sysdeps/unix/sysv/linux/glob64-lstat-compat.c      |   56 ++++
 sysdeps/unix/sysv/linux/glob64.c                   |    7 +-
 sysdeps/unix/sysv/linux/hppa/libc.abilist          |    3 +
 sysdeps/unix/sysv/linux/i386/libc.abilist          |    3 +
 sysdeps/unix/sysv/linux/ia64/libc.abilist          |    3 +
 sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist |    3 +
 sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist   |    3 +
 sysdeps/unix/sysv/linux/microblaze/libc.abilist    |    3 +
 .../unix/sysv/linux/mips/mips32/fpu/libc.abilist   |    3 +
 .../unix/sysv/linux/mips/mips32/nofpu/libc.abilist |    3 +
 .../unix/sysv/linux/mips/mips64/n32/libc.abilist   |    3 +
 .../unix/sysv/linux/mips/mips64/n64/libc.abilist   |    3 +
 sysdeps/unix/sysv/linux/nios2/libc.abilist         |    3 +
 sysdeps/unix/sysv/linux/oldglob.c                  |    5 +-
 .../sysv/linux/powerpc/powerpc32/fpu/libc.abilist  |    3 +
 .../linux/powerpc/powerpc32/nofpu/libc.abilist     |    3 +
 .../sysv/linux/powerpc/powerpc64/libc-le.abilist   |    3 +
 .../unix/sysv/linux/powerpc/powerpc64/libc.abilist |    3 +
 .../sysv/linux/s390/s390-32/glob64-lstat-compat.c  |    2 +
 sysdeps/unix/sysv/linux/s390/s390-32/glob64.c      |    2 -
 sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist  |    3 +
 sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist  |    3 +
 sysdeps/unix/sysv/linux/sh/libc.abilist            |    3 +
 sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist |    3 +
 sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist |    3 +
 .../sysv/linux/tile/tilegx/tilegx32/libc.abilist   |    3 +
 .../sysv/linux/tile/tilegx/tilegx64/libc.abilist   |    3 +
 sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist  |    3 +
 sysdeps/unix/sysv/linux/x86_64/64/libc.abilist     |    3 +
 sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist    |    3 +
 50 files changed, 666 insertions(+), 89 deletions(-)
 create mode 100644 posix/glob-lstat-compat.c
 create mode 100644 posix/glob64-lstat-compat.c
 create mode 100644 posix/tst-glob_lstat_compat.c
 create mode 100644 sysdeps/unix/sysv/linux/alpha/glob-lstat-compat.c
 delete mode 100644 sysdeps/unix/sysv/linux/alpha/glob.c
 create mode 100644 sysdeps/unix/sysv/linux/glob-lstat-compat.c
 create mode 100644 sysdeps/unix/sysv/linux/glob64-lstat-compat.c
 create mode 100644 sysdeps/unix/sysv/linux/s390/s390-32/glob64-lstat-compat.c
 delete mode 100644 sysdeps/unix/sysv/linux/s390/s390-32/glob64.c
Comment 4 Adhemerval Zanella 2017-09-26 01:05:43 UTC
Fixed by ccf970c7a77e86f4f5ef8ecc5e637114b1c0136a.