Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Segmentation fault when executing statically compiled linux appliction with musl #105

Closed
thedjnK opened this issue May 27, 2017 · 31 comments
Assignees
Milestone

Comments

@thedjnK
Copy link

thedjnK commented May 27, 2017

What's the problem (or question)?

Attempting to use upx to compress a statically linked linux executable (against musl instead of glibc using alpine linux). The compression itself is fine but when running the application (arch linux, ubuntu) it segmentation faults instantly. Running the non-upx compressed executable is fine on all systems. I'm only able to get a trace of it on my desktop system as gdb on the VMs gives a 'Not in executable format: file format not recognised' error. All systems are 64-bit, the executable is 64-bit and the gdb version is 64-bit. I'm assuming this might be related to #93 I've also tried the devel branch and using upx on the VM where it segfaults but it still has the problem.

GDB log:

Reading symbols from ./UwTerminalX3...(no debugging symbols found)...done.
(gdb) run
Starting program: /tmp/UwTerminalX3 

Program received signal SIGSEGV, Segmentation fault.
0x0000555555684ddd in ?? ()
(gdb) info reg
rax            0x86     134
rbx            0x0      0
rcx            0x0      0
rdx            0x0      0
rsi            0x0      0
rdi            0x0      0
rbp            0x0      0x0
rsp            0x7fffffffe830   0x7fffffffe830
r8             0x0      0
r9             0x0      0
r10            0x0      0
r11            0x0      0
r12            0x0      0
r13            0x0      0
r14            0x0      0
r15            0x0      0
rip            0x555555684ddd   0x555555684ddd
eflags         0x10293  [ CF AF SF IF RF ]
cs             0x33     51
ss             0x2b     43
ds             0x0      0
es             0x0      0
fs             0x0      0
gs             0x0      0
(gdb) x/4i $pc
=> 0x555555684ddd:      stos   %eax,%es:(%rdi)
   0x555555684dde:      stos   %ax,%es:(%rdi)
   0x555555684de0:      (bad)  
   0x555555684de1:      (bad)  
(gdb) x/12i $pc-0x20 
   0x555555684dbd:      cmpsl  %es:(%rdi),%ds:(%rsi)
   0x555555684dbe:      add    (%rax),%bh
   0x555555684dc0:      stos   %al,%es:(%rdi)
   0x555555684dc1:      stos   %eax,%es:(%rdi)
   0x555555684dc2:      andl   $0x57031510,0x5c(%rax)
   0x555555684dc9:      ficoml (%rbx,%rbp,8)
   0x555555684dcc:      es mov $0xa640ede,%eax
   0x555555684dd2:      movabs 0x91e00ad02f60de91,%al
   0x555555684ddb:      sbb    $0x7a,%al
=> 0x555555684ddd:      stos   %eax,%es:(%rdi)
   0x555555684dde:      stos   %ax,%es:(%rdi)
   0x555555684de0:      (bad)  
(gdb) x/16xw $sp
0x7fffffffe830: 0x00000001      0x00000000      0xffffeb2a      0x00007fff
0x7fffffffe840: 0x00000000      0x00000000      0xffffeb3c      0x00007fff
0x7fffffffe850: 0xffffeb57      0x00007fff      0xffffeb6d      0x00007fff
0x7fffffffe860: 0xffffeb7f      0x00007fff      0xffffeb8e      0x00007fff
(gdb) info proc
process 4320
cmdline = '/tmp/UwTerminalX3'
cwd = '/tmp'
exe = '/tmp/UwTerminalX3'
(gdb) shell cat /proc/4320/maps
555555554000-55555689c000 r-xp 00000000 00:27 702178                     /tmp/UwTerminalX3
55555845a000-5555584f6000 rw-p 01348000 00:27 702178                     /tmp/UwTerminalX3
5555584f6000-55555850c000 rw-p 00000000 00:00 0                          [heap]
7ffff7ffb000-7ffff7ffd000 r--p 00000000 00:00 0                          [vvar]
7ffff7ffd000-7ffff7fff000 r-xp 00000000 00:00 0                          [vdso]
7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0                          [stack]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
(gdb) 

What should have happened?

Expected the program to run.

Do you have an idea for a solution?

Not a clue

How can we reproduce the issue?

  1. I'm using alpine linux 64-bit to compile https://github.com/LairdCP/UwTerminalX statically, the output file (before UPX compression) is available from https://www.dropbox.com/s/04qnasrb4rw4aqa/UwTerminalX_musl_upx.zip?dl=0
  2. Run the executable - it works
  3. UPX compress the executable: upx -9 UwTerminalX2
  4. Try to run the executable - it no longer runs and segfaults

Please tell us details about your environment.

  • UPX version used: 3.91, 3.94, devel-branch (all give the same result)
  • Host Operating System and version: Alpine linux 3.7 64-bit virtual-box VM (compiling), Arch linux 64-bit (UPX-ing and testing)
  • Host CPU architecture: Intel x86_64 Skylake
  • Target Operating System and version: 64-bit Linux
  • Target CPU architecture: x86_64
jreiser added a commit that referenced this issue May 28, 2017
…same

#105
	modified:   p_elf_enum.h
	modified:   p_lx_elf.cpp
	modified:   stub/src/amd64-linux.elf-main.c

	modified:   ../.github/travis_testsuite_1.sh
	modified:   stub/amd64-linux.elf-fold.h
	modified:   stub/tmp/amd64-linux.elf-fold.map
@jreiser
Copy link
Collaborator

jreiser commented May 28, 2017

Fixed for now by 6e541a4 on 'devel' branch. Revamp of stubs for -fPIE is due.

@jreiser
Copy link
Collaborator

jreiser commented May 28, 2017

The input has extraneous info in the target of RELA relocations. The final result is independent of the original contents of the target (all info is in the 24-byte RELA entry), so the original content might as well be 0. However, many many of the targets for UwTerminalX2 initially contain a copy of .r_addend, which costs at least 2 bytes of compressed output. There are 50546 RELA targets, so the compressed output is around 100K larger than if the targets began as 0.

@markus-oberhumer markus-oberhumer added this to the v3.95 milestone May 29, 2017
@thedjnK
Copy link
Author

thedjnK commented Jun 1, 2017

I've tested the devel branch and it's now working with 64-bit exectuables - thank you. However, 32-bit executables compiled on the same system (using the 32-bit distro instead) are segfaulting. GDB trace:

Program received signal SIGSEGV, Segmentation fault.
0xf5201f1e in ?? ()
(gdb) info reg
eax            0x5      5
ecx            0xffffc978       -13960
edx            0x57817034       1468100660
ebx            0xf7fe4854       -134330284
esp            0xffffc850       0xffffc850
ebp            0x0      0x0
esi            0x20     32
edi            0x0      0
eip            0xf5201f1e       0xf5201f1e
eflags         0x10206  [ PF IF RF ]
cs             0x23     35
ss             0x2b     43
ds             0x2b     43
es             0x2b     43
fs             0x0      0
gs             0x0      0
(gdb) x/4i $pc
=> 0xf5201f1e:  cmpl   $0x2,(%edx)
   0xf5201f21:  jne    0xf5201f2a
   0xf5201f23:  mov    %ebx,%eax
   0xf5201f25:  sub    0x8(%edx),%eax
(gdb) x/12i $pc-0x20 
   0xf5201efe:  add    %al,(%eax)
   0xf5201f00:  add    $0x8,%eax
   0xf5201f03:  jmp    0xf5201eeb
   0xf5201f05:  mov    0x1c(%esp),%eax
   0xf5201f09:  test   %eax,%eax
   0xf5201f0b:  jne    0xf5201f2e
   0xf5201f0d:  mov    0x14(%esp),%eax
   0xf5201f11:  mov    0x10(%esp),%esi
   0xf5201f15:  mov    0xc(%esp),%edx
   0xf5201f19:  test   %eax,%eax
   0xf5201f1b:  je     0xf5201f2e
   0xf5201f1d:  dec    %eax
(gdb) x/16xw $sp
0xffffc850:     0x00000000      0x00000000      0x00000000      0x57817034
0xffffc860:     0x00000020      0x00000006      0x00001000      0x00000000
0xffffc870:     0x00000000      0xf5201e70      0x00000000      0x000003e8
0xffffc880:     0x000003e8      0x000003e8      0x000003e8      0xffffdb0b
(gdb) info proc
process 5155
cmdline = '/tmp/a/UwTerminalX'
cwd = '/tmp/a'
exe = '/tmp/a/UwTerminalX'
(gdb)  shell cat /proc/5155/maps
56555000-56556000 r-xp 00000000 00:26 1590846                            /tmp/a/UwTerminalX
587ab000-587ac000 rw-p 00000000 00:26 1590846                            /tmp/a/UwTerminalX
f51a2000-f7fa9000 r-xp 00000000 00:00 0 
f7fa9000-f7faa000 ---p 00000000 00:00 0 
f7faa000-f7ffa000 rw-p 00000000 00:00 0 
f7ffa000-f7ffc000 r--p 00000000 00:00 0                                  [vvar]
f7ffc000-f7ffe000 r-xp 00000000 00:00 0                                  [vdso]
fffdd000-ffffe000 rw-p 00000000 00:00 0                                  [stack]
(gdb) 

@jreiser
Copy link
Collaborator

jreiser commented Jun 10, 2017

@thedjnK Please specify a URL for a compiled program that I can test. Thanks. (The similar case #106 now works.)

@thedjnK
Copy link
Author

thedjnK commented Jun 10, 2017

@jreiser Test program: https://www.dropbox.com/s/lc680o172pmf45x/UwTerminalX_32_musl_upx.tar.gz?dl=0 (not compressed with upx, I've just tried the two latest builds in the devel builds but the output is the same, executable works before compressing, after compressing segfaults)

@thedjnK
Copy link
Author

thedjnK commented Jun 14, 2017

OK got the same problem with a statically compiled musl ARM application (tested with UPX 3.94) on a raspberry pi.

(gdb) run
Starting program: /tmp/UwTerminalX_rpi2
Cannot access memory at address 0x0
Cannot access memory at address 0x0

Program received signal SIGILL, Illegal instruction.
0x54b2b698 in ?? ()
(gdb) bt
#0  0x54b2b698 in ?? ()
#1  0x00000000 in ?? ()
(gdb) info reg
r0             0x0      0
r1             0x0      0
r2             0x0      0
r3             0x0      0
r4             0x0      0
r5             0x0      0
r6             0x0      0
r7             0x0      0
r8             0x0      0
r9             0x0      0
r10            0x0      0
r11            0x0      0
r12            0x0      0
sp             0x7efff390       0x7efff390
lr             0x0      0
pc             0x54b2b698       0x54b2b698
cpsr           0x10     16
(gdb) x/4i $pc
=> 0x54b2b698:  mcrls   15, 2, r0, cr1, cr12, {6}
   0x54b2b69c:  mcrr2   12, 0, r0, r7, cr1
   0x54b2b6a0:  ldrbcs  r2, [r8, r0, lsl #6]!
   0x54b2b6a4:  mcrne   10, 2, r3, cr2, cr4, {7}
(gdb) x/12i $pc-0x20
   0x54b2b678:  svccs   0x004f6d0d
   0x54b2b67c:  movwls  r4, #65243      ; 0xfedb
   0x54b2b680:  svcvc   0x0013b74d
   0x54b2b684:  bmi     0x55b06fb8
   0x54b2b688:  subne   r4, lr, #1277952        ; 0x138000
   0x54b2b68c:  strbmi  r4, [lr], -lr, asr #14
   0x54b2b690:  cmpne   lr, lr, asr #10
   0x54b2b694:  submi   r4, lr, #939524097      ; 0x38000001
=> 0x54b2b698:  mcrls   15, 2, r0, cr1, cr12, {6}
   0x54b2b69c:  mcrr2   12, 0, r0, r7, cr1
   0x54b2b6a0:  ldrbcs  r2, [r8, r0, lsl #6]!
   0x54b2b6a4:  mcrne   10, 2, r3, cr2, cr4, {7}
(gdb) x/16xw $sp
0x7efff390:     0x00000001      0x7efff509      0x00000000      0x7efff51f
0x7efff3a0:     0x7efff559      0x7efff56b      0x7efff57b      0x7efff586
0x7efff3b0:     0x7efff5be      0x7efff5e4      0x7efff606      0x7efff619
0x7efff3c0:     0x7efff632      0x7efff63a      0x7efff664      0x7efffbfd
(gdb) info proc
process 949
cmdline = '/tmp/UwTerminalX_rpi2'
cwd = '/tmp'
exe = '/tmp/UwTerminalX_rpi2'
(gdb) shell cat /proc/949/maps
54aaa000-551a9000 r-xp 00000000 b3:06 30924      /tmp/UwTerminalX_rpi2
55be2000-55c38000 rw-p 00b28000 b3:06 30924      /tmp/UwTerminalX_rpi2
55c38000-55c47000 rw-p 00000000 00:00 0          [heap]
76ffd000-76ffe000 r-xp 00000000 00:00 0          [sigpage]
76ffe000-76fff000 r--p 00000000 00:00 0          [vvar]
76fff000-77000000 r-xp 00000000 00:00 0          [vdso]
7efdf000-7f000000 rw-p 00000000 00:00 0          [stack]
ffff0000-ffff1000 r-xp 00000000 00:00 0          [vectors]
(gdb)

Uncompressed test program: https://www.dropbox.com/s/e2nw9tzsqdajgl8/UwTerminalX_rpi.7z?dl=0

Had to compress it on x86_64 PC as the raspberry pi gave this error when trying to run upx:

./upx: line 1: syntax error: unexpected word (expecting ")")

@jreiser
Copy link
Collaborator

jreiser commented Jun 14, 2017

@thedjnK Thank you for the test programs. Commit 8f572e5 at tip of 'devel' branch works for me on UwTerminalX2(x86_64) UwTerminalX-32(i686) and UwTerminalX_rpi(arm).

@thedjnK
Copy link
Author

thedjnK commented Jun 15, 2017

@jreiser Nice, I've tested on 64-bit and ARM builds and it's great, however there's something very strange when using it on 32-bit executables (I'm using a 64-bit UPX build to compress all the builds): if I run the compressed executable on a 64-bit linux system it runs fine. If I run it on a 32-bit linux system it segmentation faults - however if I run it on the same system using gdb it runs fine without a segmentation fault, therefore I'm not actually able to investigate the problem. Performing an strace gives a SEGV_MAPERR but this is as much information as I can get (I've tried it on a debian 8 VM, an old 3.x-kernel arch linux VM and Fedora core 22 and they all act the same)

Link to the UPX compressed 32-bit executable: https://www.dropbox.com/s/h5fft1azj0ww4mc/Uw32a.7z?dl=0

@jreiser
Copy link
Collaborator

jreiser commented Jun 15, 2017

@thedjnK Please copy+paste the SEGV_MAPERR and preceding 10 or 15 lines from strace. They should give me another clue while I rustle up a real i686 system. (Running Uw32a in 32-bit mode on x86_64 does work for me, too.)

@jreiser
Copy link
Collaborator

jreiser commented Jun 15, 2017

@thedjnK Running Fedora-Live-Workstation-i686-23-10.iso from 1.5 years ago:

$ uname -a
Linux localhost 4.2.3-300.fc23.i686 #1 SMP Mon Oct 5 16:26:47 UTC 2015 i686 i686 i386 GNU/Linux

I see no problems in 10 attempts under strace. One of them begins:

2925  execve("./Uw32a", ["./Uw32a"], [/* 48 vars */]) = 0
2925  mmap(0x7ed57000, 20439829, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7ed57000
2925  readlink("/proc/self/exe", "/home/liveuser/Uw32a", 4055) = 20
2925  open("/proc/self/exe", O_RDONLY)  = 3
2925  mmap2(0x800d6000, 49927151, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x800d6000
2925  mprotect(0x800d6000, 49927148, PROT_READ|PROT_EXEC) = 0
2925  mmap2(0x83074000, 356455, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x83074000
2925  mprotect(0x83074000, 356452, PROT_READ|PROT_WRITE) = 0
2925  mmap2(0x830cc000, 60744, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x830cc000
2925  brk(0x830db000)                   = 0x83980000
2925  mmap2(NULL, 4096, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb773e000
2925  close(3)                          = 0
2925  munmap(0x7ed57000, 20439829)      = 0
   ### that munmap was the last syscall from the upx de-compression stub
2925  set_thread_area({entry_number:-1, base_addr:0x830dabdc, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0 (entry_number:6)
2925  set_tid_address(0x830dabf8)       = 2925
2925  brk(NULL)                         = 0x83980000
2925  brk(0x83981000)                   = 0x83981000
2925  brk(0x83986000)                   = 0x83986000
2925  geteuid32()                       = 1000
2925  getuid32()                        = 1000
2925  getpid()                          = 2925
2925  stat64("/proc/2925/exe", {st_mode=S_IFREG|0775, st_size=20440284, ...}) = 0
2925  lstat64("/proc/2925/exe", {st_mode=S_IFLNK|0777, st_size=0, ...}) = 0
2925  open("/proc/2925/exe", O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_CLOEXEC|O_PATH) = 3
2925  readlink("/proc/self/fd/3", "/home/liveuser/Uw32a", 4095) = 20
2925  fstat64(3, {st_mode=S_IFREG|0775, st_size=20440284, ...}) = 0
2925  stat64("/home/liveuser/Uw32a", {st_mode=S_IFREG|0775, st_size=20440284, ...}) = 0
2925  close(3)                          = 0
2925  stat64("/home/liveuser/qt.conf", 0xbfab85bc) = -1 ENOENT (No such file or directory)
2925  open("/usr/share/qt5/qtlogging.ini", O_RDONLY|O_LARGEFILE|O_CLOEXEC) = -1 ENOENT (No such file or directory)
2925  stat64("/home/liveuser/.config/QtProject/qtlogging.ini", 0xbfab870c) = -1 ENOENT (No such file or directory)
2925  stat64("/etc/xdg/QtProject/qtlogging.ini", {st_mode=S_IFREG|0644, st_size=22, ...}) = 0
2925  open("/etc/xdg/QtProject/qtlogging.ini", O_RDONLY|O_LARGEFILE|O_CLOEXEC) = 3
   [[snip]]

which is well past the upx de-compression stub, and into Qt initialization.

How big is your shell environment?

$ set | wc;  set

(Delete lines with sensitive info, but please tell me about how many bytes you deleted.)

@jreiser
Copy link
Collaborator

jreiser commented Jun 15, 2017

@thedjnK Similar lack of failure using:

debian-live-8.8.0-i386-mate-desktop.iso  (i686-pae)
Linux debian 3.16.0-4-686-pae #1 SMP Debian 3.16.43-2 (2017-04-30) i686 GNU/Linux

There is one clue in the strace, which begins:

19533 execve("./Uw32a", ["./Uw32a"], [/* 31 vars */]) = 0
19533 old_mmap(0x7ed7a000, 20439829, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7ed7a000
19533 readlink("/proc/self/exe", "/home/user/Uw32a", 4055) = 16
19533 open("/proc/self/exe", O_RDONLY)  = 3
19533 mmap2(0x800f9000, 49927151, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x800f9000
   [[snip]]

Note the 'old_mmap' vs 'mmap2'. Old_mmap uses register %ebx to point to a 6-word vector of arguments, almost always at top-of-stack. (new)mmap2 puts arguments into registers %ebx, %ecx, %edx, %esi, %edi, %ebp. Both use %eax=0xC0 as the syscall number.

@thedjnK
Copy link
Author

thedjnK commented Jun 15, 2017

Fedora set: 1648 5411 59264

Fedora set values: https://pastebin.com/2guZB8pF (nothing removed)

Fedora strace:

execve("./Uw32a", ["./Uw32a"], [/* 51 vars */]) = 0
old_mmap(0xb342b000, 20439829, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb342b000
readlink("/proc/self/exe", "/tmp/Uw32a", 4055) = 10
open("/proc/self/exe", O_RDONLY)        = 3
mmap2(0xb47aa000, 49927151, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb47aa000
mprotect(0xb47aa000, 49927148, PROT_READ|PROT_EXEC) = 0
mmap2(0xb7748000, 356455, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb7748000
mprotect(0xb7748000, 356452, PROT_READ|PROT_WRITE) = 0
mmap2(0xb77a0000, 60744, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb77a0000
brk(0xb77af000)                         = 0xb87b9000
mmap2(NULL, 4096, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb342a000
close(3)                                = 0
munmap(0xb342b000, 20439829)            = 0
set_thread_area({entry_number:-1, base_addr:0xb77aebdc, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0 (entry_number:6)
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x102} ---
+++ killed by SIGSEGV (core dumped) +++

Debian... Now this is odd, it didn't have strace so I installed strace and the executable now runs fine all the time. Removed strace and it still runs fine so I'm not sure what's happened.

Debian set: 1854 5799 62957

Debian set values: https://pastebin.com/HGpZRXYz (nothing removed)

Debian strace:

execve("./Uw32a", ["./Uw32a"], [/* 36 vars */]) = 0
old_mmap(0x7ecb8000, 20439829, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7ecb8000
readlink("/proc/self/exe", "/tmp/Uw32a", 4055) = 10
open("/proc/self/exe", O_RDONLY)        = 3
mmap2(0x80037000, 49927151, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x80037000
mprotect(0x80037000, 49927148, PROT_READ|PROT_EXEC) = 0
mmap2(0x82fd5000, 356455, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x82fd5000
mprotect(0x82fd5000, 356452, PROT_READ|PROT_WRITE) = 0
mmap2(0x8302d000, 60744, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x8302d000
brk(0x8303c000)                         = 0x84a6d000
mmap2(NULL, 4096, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb777d000
close(3)                                = 0
munmap(0x7ecb8000, 20439829)            = 0
set_thread_area({entry_number:-1, base_addr:0x8303bbdc, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0 (entry_number:6)
set_tid_address(0x8303bbf8)             = 1287
brk(0)                                  = 0x84a6d000
brk(0x84a6e000)                         = 0x84a6e000
brk(0x84a73000)                         = 0x84a73000
geteuid32()                             = 1000
getuid32()                              = 1000
getpid()                                = 1287
stat64("/proc/1287/exe", {st_mode=S_IFREG|0755, st_size=20440284, ...}) = 0
lstat64("/proc/1287/exe", {st_mode=S_IFLNK|0777, st_size=0, ...}) = 0
open("/proc/1287/exe", O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_CLOEXEC|O_PATH) = 3
readlink("/proc/self/fd/3", "/tmp/Uw32a", 4095) = 10
fstat64(3, {st_mode=S_IFREG|0755, st_size=20440284, ...}) = 0
stat64("/tmp/Uw32a", {st_mode=S_IFREG|0755, st_size=20440284, ...}) = 0
close(3)                                = 0
stat64("/tmp/qt.conf", 0xbfae484c)      = -1 ENOENT (No such file or directory)
open("/usr/share/qt5/qtlogging.ini", O_RDONLY|O_LARGEFILE|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat64("/home/laird/.config/QtProject/qtlogging.ini", 0xbfae499c) = -1 ENOENT (No such file or directory)
stat64("/etc/xdg/QtProject/qtlogging.ini", 0xbfae499c) = -1 ENOENT (No such file or directory)
stat64("/tmp/qt.conf", 0xbfae484c)      = -1 ENOENT (No such file or directory)
socket(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC, 0) = 3
connect(3, {sa_family=AF_LOCAL, sun_path=@"/tmp/.X11-unix/X0"}, 20) = 0
<snip>

Arch set: 61 77 1559

Arch set values: https://pastebin.com/r37ztpcm (nothing removed)

Arch strace:

execve("./Uw32a", ["./Uw32a"], 0xbff4c7c0 /* 26 vars */) = 0
mmap(0xb5023000, 20439829, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb5023000
readlink("/proc/self/exe", "/tmp/Uw32a", 4055) = 10
open("/proc/self/exe", O_RDONLY)        = 3
mmap2(0xb63a2000, 49927151, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb63a2000
mprotect(0xb63a2000, 49927148, PROT_READ|PROT_EXEC) = 0
mmap2(0xb9340000, 356455, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb9340000
mprotect(0xb9340000, 356452, PROT_READ|PROT_WRITE) = 0
mmap2(0xb9398000, 60744, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb9398000
brk(0xb93a7000)                         = 0xbb2a0000
mmap2(NULL, 4096, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb5022000
close(3)                                = 0
munmap(0xb5023000, 20439829)            = 0
set_thread_area({entry_number:-1, base_addr:0xb93a6bdc, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0 (entry_number:6)
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0xb63a1bb0} ---
+++ killed by SIGSEGV (core dumped) +++

@thedjnK
Copy link
Author

thedjnK commented Jun 16, 2017

Managed to reproduce the issue with a 64-bit ubuntu VM so it appears it isn't limited to 32-bit hosts.

Ubuntu set: 2803 8266 94138

Ubuntu set values: https://pastebin.com/UgrNWgh0 (nothing removed)

Ubuntu strace (non-working UPX version):

execve("./Uw32a", ["./Uw32a"], [/* 48 vars */]) = 0
[ Process PID=1912 runs in 32 bit mode. ]
old_mmap(0xf503f000, 20439829, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xfffffffff503f000
readlink("/proc/self/exe", "/tmp/Uw32a", 4055) = 10
open("/proc/self/exe", O_RDONLY)        = 3
mmap2(0xf63be000, 49927151, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xfffffffff63be000
mprotect(0xf63be000, 49927148, PROT_READ|PROT_EXEC) = 0
mmap2(0xf935c000, 356455, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xfffffffff935c000
mprotect(0xf935c000, 356452, PROT_READ|PROT_WRITE) = 0
mmap2(0xf93b4000, 60744, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xfffffffff93b4000
brk(0xf93c3000)                         = 0xfffffffffb188000
mmap2(NULL, 4096, PROT_READ, MAP_PRIVATE, 3, 0) = 0xfffffffff503e000
close(3)                                = 0
munmap(0xf503f000, 20439829)            = 0
set_thread_area(0xfff7e768)             = 0
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0xf63bd420} ---
+++ killed by SIGSEGV (core dumped) +++

Ubuntu strace (working non-UPX version):

execve("./Uw32n", ["./Uw32n"], [/* 48 vars */]) = 0
[ Process PID=1922 runs in 32 bit mode. ]
set_thread_area(0xffb8ed08)             = 0
set_tid_address(0xf782cbf8)             = 1922
brk(0)                                  = 0xfffffffff809d000
brk(0xf809e000)                         = 0xfffffffff809e000
brk(0xf80a3000)                         = 0xfffffffff80a3000
geteuid32()                             = 1000
getuid32()                              = 1000
getpid()                                = 1922
stat64("/proc/1922/exe", {st_mode=S_IFREG|0755, st_size=50283968, ...}) = 0
lstat64("/proc/1922/exe", {st_mode=S_IFLNK|0777, st_size=0, ...}) = 0
open("/proc/1922/exe", O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_CLOEXEC|0x200000) = 3
readlink("/proc/self/fd/3", "/tmp/Uw32n", 4095) = 10
fstat64(3, {st_mode=S_IFREG|0755, st_size=50283968, ...}) = 0
stat64("/tmp/Uw32n", {st_mode=S_IFREG|0755, st_size=50283968, ...}) = 0
close(3)                                = 0
stat64("/tmp/qt.conf", 0xffb8e73c)      = -1 ENOENT (No such file or directory)

This is ubuntu 14.04 LTS, uname: Linux laird-vm 3.13.0-32-generic #57-Ubuntu SMP Tue Jul 15 03:51:08 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux

@jreiser
Copy link
Collaborator

jreiser commented Jun 17, 2017

@thedjnK Commit b2115a4 on 'devel' branch cleans [most of] the stack (on i386 ONLY for now) when the de-compression stub finishes, and may help. The problem is that some user code assumes that "virgin" stack frames have been zeroed. For the case of the UPX de-compression stub, then a large number of shell environment variables (regardless of character length) can make the problem more visible.

Another item: Please try running the never-compressed Uw32 under valgrind. Memcheck complains of Uninitialized values. This almost certainly indicates bugs in the user code, which could be one source of "random" SIGSEGV errors. The commit above is an attempt to "cover up" some of the problem.

Example complaints from memcheck:

$ valgrind --trace-syscalls=yes --track-origins=yes ./Uw32a 2>vg.out
   [[snip]]
SYSCALL[25006,1](45) sys_brk ( 0x4001000 ) --> [pre-success] Success(0x4001000)
==25006== Conditional jump or move depends on uninitialised value(s)
==25006==    at 0xF17E32: ???
==25006==  Uninitialised value was created
==25006==    at 0xF169C6: ???
==25006==
   [[snip]]
==25006== Conditional jump or move depends on uninitialised value(s)
==25006==    at 0xF17D28: ???
==25006==  Uninitialised value was created by a stack allocation
==25006==    at 0x46ED70: ???
==25006==

For the Uw32 test case, then address 0xF169C6 is the common tail of all syscalls. I have entered https://bugs.kde.org/show_bug.cgi?id=381304 requesting that memcheck track the syscall number as well as the program counter. There is a possbility that some of the uninit values are created as a result of a misunderstanding about brk(), sbrk(), and malloc(). This is tricky; I'm still looking at it.

"created by a stack allocation" gives an address near the start of the subroutine. Use the un-stripped program to lookup which routine.

$ gdb Uw32.no-strip
(gdb) x/i 0x46ED70

@thedjnK
Copy link
Author

thedjnK commented Jun 17, 2017

@jreiser I recompiled without stripping: https://www.dropbox.com/s/s6f6agxsjo32zzt/Uw32f.tar.gz?dl=0

I'm not sure if the addresses have changed but if not then the output is:

(gdb) x/i 0x46ED70
    0x46ed70 <_ZN22QWindowSystemInterface17handleExposeEventINS_19SynchronousDeliveryEEEvP7QWindowRK7QRegion+272>:       sahf

Seems to be related to xcb. Running the unstripped executable in valgrind returns ~830,000 errors, I'm seeing a lot in malloc (this is tested on a 64-bit system whereby running the executable normally is fine), e.g.

SYSCALL[1959,1](243) sys_set_thread_area ( 0xfeebc778 ) --> [pre-success] Success(0x0)
SYSCALL[1959,1](258) sys_set_tid_address ( 0x310cbf8 )[sync] --> Success(0x7a7)
SYSCALL[1959,1](45) sys_brk ( 0x0 ) --> [pre-success] Success(0x4000000)
SYSCALL[1959,1](45) sys_brk ( 0x4001000 ) --> [pre-success] Success(0x4001000)
==1959== Conditional jump or move depends on uninitialised value(s)
==1959==    at 0xF18112: __malloc0 (malloc.c:375)
==1959==    by 0xF1696B: __cxa_atexit (atexit.c:44)
==1959==    by 0x1752C8: _GLOBAL__sub_I_qguiapplication.cpp (in /tmp/UwTerminalX)
==1959==    by 0xF164A7: libc_start_init (__libc_start_main.c:61)
==1959==    by 0xF164D0: (below main) (__libc_start_main.c:71)
==1959==  Uninitialised value was created
==1959==    at 0xF16CA6: ??? (syscall.s:36)
==1959==    by 0x2C: ???
==1959== 

...

SYSCALL[1959,1](45) sys_brk ( 0x4007000 ) --> [pre-success] Success(0x4007000)
SYSCALL[1959,1](145) sys_readv ( 4, 0xfeebbdd0, 2 ) --> [async] ...
SYSCALL[1959,1](145) ... [async] --> Success(0x36)
SYSCALL[1959,1](145) sys_readv ( 4, 0xfeebbdd0, 2 ) --> [async] ...
SYSCALL[1959,1](145) ... [async] --> Success(0x0)
SYSCALL[1959,1](6) sys_close ( 4 )[sync] --> Success(0x0)
SYSCALL[1959,1](102) sys_socketcall ( 6, 0xfeebc008 ) --> [async] ...
SYSCALL[1959,1](102) ... [async] --> Success(0x0)
SYSCALL[1959,1](45) sys_brk ( 0x400d000 ) --> [pre-success] Success(0x400d000)
==1959== Conditional jump or move depends on uninitialised value(s)
==1959==    at 0xF18112: __malloc0 (malloc.c:375)
==1959==    by 0x4BD7FC: xcb_connect_to_fd (in /tmp/UwTerminalX)
==1959==    by 0x4C123D: xcb_connect_to_display_with_auth_info (in /tmp/UwTerminalX)
==1959==    by 0x4C12F9: xcb_connect (in /tmp/UwTerminalX)
==1959==    by 0x45CAFE: QXcbConnection::QXcbConnection(QXcbNativeInterface*, bool, unsigned int, char const*) (in /tmp/UwTerminalX)
==1959==    by 0x445BB4: QXcbIntegration::QXcbIntegration(QStringList const&, int&, char**) (in /tmp/UwTerminalX)
==1959==    by 0x444AE0: QXcbIntegrationPlugin::create(QString const&, QStringList const&, int&, char**) (in /tmp/UwTerminalX)
==1959==    by 0x827E00: QPlatformIntegrationFactory::create(QString const&, QStringList const&, int&, char**, QString const&) (in /tmp/UwTerminalX)
==1959==    by 0x590018: QGuiApplicationPrivate::createPlatformIntegration() (in /tmp/UwTerminalX)
==1959==    by 0x590AEB: QGuiApplicationPrivate::createEventDispatcher() (in /tmp/UwTerminalX)
==1959==    by 0x1D8655: QApplicationPrivate::createEventDispatcher() (in /tmp/UwTerminalX)
==1959==    by 0xCA13D4: QCoreApplicationPrivate::init() (in /tmp/UwTerminalX)
==1959==  Uninitialised value was created
==1959==    at 0xF16CA6: ??? (syscall.s:36)
==1959==    by 0x2C: ???

...

==1959== Use of uninitialised value of size 4
==1959==    at 0xF2303C: ??? (memset.s:30)
==1959==    by 0x4C0554: get_lazyreply (in /tmp/UwTerminalX)
==1959==    by 0x4C0672: xcb_prefetch_extension_data (in /tmp/UwTerminalX)
==1959==    by 0x45CBB4: QXcbConnection::QXcbConnection(QXcbNativeInterface*, bool, unsigned int, char const*) (in /tmp/UwTerminalX)
==1959==    by 0x445BB4: QXcbIntegration::QXcbIntegration(QStringList const&, int&, char**) (in /tmp/UwTerminalX)
==1959==    by 0x444AE0: QXcbIntegrationPlugin::create(QString const&, QStringList const&, int&, char**) (in /tmp/UwTerminalX)
==1959==    by 0x827E00: QPlatformIntegrationFactory::create(QString const&, QStringList const&, int&, char**, QString const&) (in /tmp/UwTerminalX)
==1959==    by 0x590018: QGuiApplicationPrivate::createPlatformIntegration() (in /tmp/UwTerminalX)
==1959==    by 0x590AEB: QGuiApplicationPrivate::createEventDispatcher() (in /tmp/UwTerminalX)
==1959==    by 0x1D8655: QApplicationPrivate::createEventDispatcher() (in /tmp/UwTerminalX)
==1959==    by 0xCA13D4: QCoreApplicationPrivate::init() (in /tmp/UwTerminalX)
==1959==    by 0x5927E8: QGuiApplicationPrivate::init() (in /tmp/UwTerminalX)
==1959==  Uninitialised value was created by a stack allocation
==1959==    at 0x4CFF10: XauReadAuth (in /tmp/UwTerminalX)

I noticed 0x4CFF10 a few times so I'm assuming this is the location you were seeing:

(gdb) x/i 0x4CFF10
   0x4cff10 <_ZN23QPlatformSystemTrayIcon11qt_metacallEN11QMetaObject4CallEiPPv>:       push   %ebp

I'll try rebuilding without using the system try icon functionality and test it alongside the patched release soon. I noticed one in an SSL function regarding sorting engines but I assume the code on the failing systems doesn't get this far before segfaulting and therefore isn't related.

@thedjnK
Copy link
Author

thedjnK commented Jun 17, 2017

Just tried the new upx commit and removing the system tray code & SSL code but it's still segfaulting (just trying on 64-bit ubuntu)

@jreiser
Copy link
Collaborator

jreiser commented Jun 17, 2017

@thedjnK Please file a report against libmusl for poor integration with valgrind. libmusl is wasting the time of developers who use it.

==27239== Conditional jump or move depends on uninitialised value(s)
==27239==    at 0xF18112: __malloc0 (malloc.c:375)

void *__malloc0(size_t n)
{
        void *p = malloc(n);
        if (p && !IS_MMAPPED(MEM_TO_CHUNK(p))) {
                size_t *z;
                n = (n + sizeof *z - 1)/sizeof *z;
                for (z=p; n; n--, z++) if (*z) *z=0;   /* line 375 */
        }
        return p;
}

Conditionally clearing each word of a newly malloc()ed block causes the read-before-initialized complaint. Valgrind(memcheck) has low-overhead mechanisms for communicating about custom allocators. Also, modern memset() is no slouch. If a modest fraction of the block ever is written after __malloc0() exits, then it is arguable whether the conditional clear saves any time overall. Loading the data cache tends to dominate other delays.

I'm still looking at UwTerminal ...

@jreiser
Copy link
Collaborator

jreiser commented Jun 19, 2017

@thedjnK I have not been able to reproduce the problem running any of the 32-bit programs (compressed or not) on

Debian 9 (stretch) kernel 4.9.0-1-amd64 #1 SMP Debian 4.9.6-3 (2017-01-28) x86_64
Debian 8 (jessie) kernel 3.16.0-4-686-pae #1 SMP Debian 3.16.43-2 (2017-04-30) i686

nor on the i586 kernel which corresponds to the i686-pae kernel. I installed and ran on real hardware: a Core2Duo with sse, sse2, ssse3, and sse4_1 CPU feature flags, but not sse4_2 [grep flags /proc/cpuinfo].

valgrind(memcheck) is not as useful as I expected. libmusl not integrating with memcheck, and memcheck not understanding all the intricacies of socket() calls, dramatically lower the usefulness of memcheck on this problem. I'm disappointed.

So, I think it's time for a "reset" of sorts. You can reproduce the problem, so let's get usable info from that: namely, a core dump. Please search the web for "Debian enable core dump", implement those steps, generate a core dump, and send me a pointer to it (along with which executable you were running.)

Meanwhile, I will backup and try to reproduce your environment more faithfully. Please tell me the details of the virtualization that you use: kvm or xen, which version of the virtualization, which version of the Linux kernel running under the virtualization, which CPU flags are enabled (particularly sse, sse2, ssse3, sse4_1, sse4_2, avx).

@thedjnK
Copy link
Author

thedjnK commented Jun 19, 2017

I wasn't able to reproduce it on debian. This, however, is very odd. I downloaded a ubuntu 16.04 LTS ISO and tested on that - no problems. I also tried with an older 14.04 LTS ISO and that too ran it without issue (I'm now using a different host system for testing with a skylake CPU). I then copied the problematic 14.04 LTS image from the other host to this host and tried it in that and it has the segmentation fault. The original host is a 64-bit windows 7 laptop and this host is 64-bit arch linux, using virtualbox 5.x.

The original host has a Haswell i5-4300M CPU http://ark.intel.com/products/76347/Intel-Core-i5-4300M-Processor-3M-Cache-up-to-3_30-GHz and this PC has an i5-6600K CPU https://ark.intel.com/products/88191/Intel-Core-i5-6600K-Processor-6M-Cache-up-to-3_90-GHz

model name      : Intel(R) Core(TM) i5-6600K CPU @ 3.50GHz
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch intel_pt tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx rdseed adx smap clflushopt xsaveopt xsavec xgetbv1 xsaves dtherm arat pln pts hwp hwp_notify hwp_act_window hwp_epp

The flags from the problematic ubuntu VM:

flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx rdtscp lm constant_tsc rep_good nopl xtopology nonstop_tsc pni pclmulqdq ssse3 cx16 sse4_1 sse4_2 x2apic movbe popcnt aes xsave avx rdrand hypervisor lahf_lm abm 3dnowprefetch rdseed

Core dump from the ubuntu system (using the Uw32a file linked earlier, the system information for this VM is also in a previous post): https://www.dropbox.com/s/6njfoxbqke0revs/core.tar.gz?dl=0

I'll see if I can reduce the size of this VM image (currently at 8GB) and upload it

@thedjnK
Copy link
Author

thedjnK commented Jun 19, 2017

@jreiser OK I've compressed the image down and uploaded it to https://mega.nz/#!F3gk1CwT!Noc9y7y_tMYBp5UTkJgZ7-Cz3LDLTYR8H4lMSD4fQ-Q

If you create a new 64-bit ubuntu VM in virtualbox 5.x and select 'use an existing hard drive' and select the extracted file, then in settings set the RAM to 1GB and CPU count to 1 or 2 then run it and login (password is password). Click the Okay button, right click and go to Application > Terminal Emulators > Gnome Terminal, then you can run the executable from here using ./Uw32a and see the segmentation fault.

@jreiser
Copy link
Collaborator

jreiser commented Jun 19, 2017

@thedjnK Thank you. I have downloaded the core.tar.gz and the ubuntu VM image, and am investigating.

jreiser added a commit that referenced this issue Jun 19, 2017
#105
	modified:   stub/src/i386-linux.elf-entry.S

	modified:   stub/i386-linux.elf-entry.h
	modified:   stub/tmp/i386-linux.elf-entry.bin.dump
@jreiser
Copy link
Collaborator

jreiser commented Jun 19, 2017

@thedjnK Fixed on 'devel' branch by 9f20bbb . The VDSO (automatically added to the process image by the Linux kernel) might overlap our desired placement on -pie ET_DYN; so move below it.

Thank you for persevering. The VirtualBox really helped. Technique to avoid interference by gdb: Insert a deliberate infinite loop shortly before the code of interest in the UPX stub. Re-compress Uw32a, run in background (./Uw32a &). Attach gdb during infinite loop ("sudo gdb ./Uw32a PID" where the 'sudo' is necessary on Ubuntu in order to PTRACE a non-child process). Adjust: set $pc+=2 etc.

@thedjnK
Copy link
Author

thedjnK commented Jun 20, 2017

@jreiser Thank you for taking the time to look at this. I can confirm the fix works on the 64-bit ubuntu VM, however I've tried it on a 32-bit ubuntu 15 VM and the fedora core 22 32-bit VM and unfortunately it's segfaulting on both of them with the updated executable. I'll have a look into debugging on these distros when I get some time.

@ghost
Copy link

ghost commented Sep 25, 2017

Ping - just ran into this issue with a 64 bit binary.

@jreiser
Copy link
Collaborator

jreiser commented Sep 25, 2017

@voltagex Which architecture and Linux distribution and version ("uname -r")? If you can reproduce the problem with a small binary such as

int const x[10000] = {1,2,3};  /* const for .text; 10000 for compressible; non-static to force presence */
int main(int argc, char *argv[]) { return x[2]; }

then please gzip and upload it ("Attach files"). Otherwise please copy+paste the output of "readelf --segments a.out".

@ghost
Copy link

ghost commented Sep 30, 2017

Apologies for the delay.

voltagex@devbox:~/src/docker/upx-test$ ./tmp/a.out; echo $?
3
voltagex@devbox:~/src/docker/upx-test$ upx -9 ./tmp/a.out
                       Ultimate Packer for eXecutables
                          Copyright (C) 1996 - 2017
UPX 3.94        Markus Oberhumer, Laszlo Molnar & John Reiser   May 12th 2017

        File size         Ratio      Format      Name
   --------------------   ------   -----------   -----------
     72384 ->     16428   22.70%   linux/amd64   a.out

Packed 1 file.
voltagex@devbox:~/src/docker/upx-test$ ./tmp/a.out; echo $?
Segmentation fault
139
voltagex@devbox:~/src/docker/upx-test$

Host system is Debian sid on kernel 4.12.0-2-amd64, I'm running into the issue in a Docker container that's using Alpine and musl.

Dockerfile used to repro the issue

from alpine:latest

RUN apk add --update gcc libc-dev
RUN echo "int const x[10000] = {1,2,3};  /* const for .text; 10000 for compressible; non-static to force presence */" > test.c
RUN echo "int main(int argc, char *argv[]) { return x[2]; }" >> test.c
RUN gcc -static test.c

Note that I'm running upx and hitting the issue on the host Debian system.

@ghost
Copy link

ghost commented Sep 30, 2017

upx-test.gz

@jreiser
Copy link
Collaborator

jreiser commented Sep 30, 2017

@voltagex Exit code 139 = (128 + 11) and SIGSEGV is 11, so that matches.

I will look for a kernel 4.12.0-2 system. Meanwhile, please run under gdb:

$ gdb ./tmp/a.out
(gdb) run
   SIGSEGV
(gdb) info reg  ## contents of all registers
(gdb) x/5i $pc  ## current and next instructions
(gdb) x/12i $pc-0x20  ## likely previous instructions
(gdb) x/16xw $sp  ## top 16 words of stack
(gdb) info proc  ## process info
(gdb) shell cat /proc/PID/maps  ## where PID is the process ID from "info proc"

This information will help diagnose the problem. Thank you.

@ghost
Copy link

ghost commented Sep 30, 2017


Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7df328c in ?? ()
(gdb) info reg
rax            0x0      0
rbx            0x0      0
rcx            0x0      0
rdx            0x0      0
rsi            0x0      0
rdi            0x0      0
rbp            0x0      0x0
rsp            0x7fffffffeb10   0x7fffffffeb10
r8             0x0      0
r9             0x0      0
r10            0x0      0
r11            0x0      0
r12            0x0      0
r13            0x0      0
r14            0x0      0
r15            0x0      0
rip            0x7ffff7df328c   0x7ffff7df328c
eflags         0x10202  [ IF RF ]
cs             0x33     51
ss             0x2b     43
ds             0x0      0
es             0x0      0
fs             0x0      0
gs             0x0      0
(gdb) x/5i $pc
=> 0x7ffff7df328c:      add    (%rsi),%esi
   0x7ffff7df328e:      and    %ebx,%ebx
   0x7ffff7df3290:      insb   (%dx),%es:(%rdi)
   0x7ffff7df3291:      cmp    %ch,-0x2fdff8eb(%rsi)
   0x7ffff7df3297:      outsb  %ds:(%rsi),(%dx)
(gdb) x/5i $pc
=> 0x7ffff7df328c:      add    (%rsi),%esi
   0x7ffff7df328e:      and    %ebx,%ebx
   0x7ffff7df3290:      insb   (%dx),%es:(%rdi)
   0x7ffff7df3291:      cmp    %ch,-0x2fdff8eb(%rsi)
   0x7ffff7df3297:      outsb  %ds:(%rsi),(%dx)
(gdb) x/16xw $sp
0x7fffffffeb10: 0x00000001      0x00000000      0xffffed43      0x00007fff
0x7fffffffeb20: 0x00000000      0x00000000      0xffffed71      0x00007fff
0x7fffffffeb30: 0xffffed9d      0x00007fff      0xffffedac      0x00007fff
0x7fffffffeb40: 0xffffedbd      0x00007fff      0xffffede7      0x00007fff
(gdb) info proc
process 15476
cmdline = '/home/voltagex/src/docker/upx-test/temp/a.out'
cwd = '/home/voltagex/src/docker/upx-test/temp'
exe = '/home/voltagex/src/docker/upx-test/temp/a.out'
(gdb) shell cat /proc/15476/maps
7ffff7df3000-7ffff7df4000 r-xp 00000000 08:01 1704529                    /home/voltagex/src/docker/upx-test/temp/a.out
7ffff7ff8000-7ffff7ffb000 r--p 00000000 00:00 0                          [vvar]
7ffff7ffb000-7ffff7ffd000 r-xp 00000000 00:00 0                          [vdso]
7ffff7ffd000-7ffff7fff000 rw-p 00003000 08:01 1704529                    /home/voltagex/src/docker/upx-test/temp/a.out
7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0                          [stack]

@jreiser
Copy link
Collaborator

jreiser commented Oct 17, 2017

@thedjnK @voltagex Please try the devel branch. I have changed the strategy used by the runtime decompression stub, to remove assumptions about which address space is available. This should remove conflicts caused by placement of [vdso], [vvar], etc. Particularly because of the system-dependent nature of the problems shown here [the placement strategy varies from kernel to kernel], I believe that such conflicts were the cause.

@thedjnK
Copy link
Author

thedjnK commented Oct 20, 2017

@jreiser Just tested it with the previously failing 32-bit executable and it now works fine, I haven't tested the new build on 64-bit or ARM executables, thank you for the fix!

@jreiser jreiser closed this as completed Oct 20, 2017
jeffutter added a commit to jeffutter/eini that referenced this issue Mar 21, 2018
This was causing segfaults on alpine:

upx/upx#105

Should be fixed in the next upx release
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants