Control: tags -1 + upstream patch
Dear Maintainer,
I tried to have a look into this issue and guess I found something.
It looks like the application is exhausting its stack by
allocation an integer array with maxpid elements.
At least in my test VM this leads to 16 MB array size,
while stack has just a size of 8 MB.
Attached patch allocates two such arrays from the heap.
With this "unhide brute" could finish without crash.
Another workaround would be to increase stacksize
by "ulimit -s 40960" before running unhide.
Kind regards,
Bernhard
dmesg by submitter:
Nov 30 01:39:48 heisenberg kernel: unhide[208429]: segfault at 7ffd06cfec58 ip
000055c15aa077d3 sp 00007ffd06cfec60 error 6 in unhide-linux[55c15aa07000+6000]
Nov 30 01:39:48 heisenberg kernel: Code: 00 48 89 45 c8 31 c0 48 63 05 5d 98 00
00 48 8d 04 85 0f 00 00 00 48 83 e0 f0 48 29 c4 48 89 65 98 48 29 c4 31 c0 48
89 65 90 <e8> d8 3e 00 00 31 c0 66 0f 1f 44 00 00 48 8b 4d 98 48 8b 55 90 c7
/*
* Page fault error code bits:
*
* bit 0 == 0: no page found 1: protection fault
* bit 1 == 0: read access 1: write access
* bit 2 == 0: kernel-mode access 1: user-mode access
* bit 3 == 1: use of reserved bit detected
* bit 4 == 1: fault was an instruction fetch
* bit 5 == 1: protection keys block access
*/
enum x86_pf_error_code {
PF_PROT = 1 << 0,
PF_WRITE = 1 << 1,
PF_USER = 1 << 2,
PF_RSVD = 1 << 3,
PF_INSTR = 1 << 4,
PF_PK = 1 << 5,
};
arch/x86/mm/fault.c:
printk("%s%s[%d]: segfault at %lx ip %px sp %px error %lx",
"error 6" == 0x6 == 0b110
bit 0 == 0: no page found
bit 1 == 1: write access
bit 2 == 1: user-mode access
bit 3 == 0:
bit 4 == 0:
bit 5 == 0:
# Bullseye/testing amd64 qemu VM 2019-12-03
apt update
apt dist-upgrade
apt install systemd-coredump mc devscripts dpkg-dev gdb unhide unhide-dbgsym
mkdir /home/benutzer/source/unhide/orig -p
cd /home/benutzer/source/unhide/orig
apt source unhide
cd
gdb -q --args unhide
set width 0
set pagination off
directory /home/benutzer/source/unhide/orig/unhide-20130526
b main
run
dele 1
info target
find /b 0x00005555555563e0, 0x000055555555b001, 0x00, 0x48, 0x89, 0x45, 0xc8,
0x31, 0xc0, 0x48, 0x63, 0x05, 0x5d, 0x98, 0x00, 0x00, 0x48, 0x8d, 0x04, 0x85,
0x0f, 0x00, 0x00, 0x00, 0x48, 0x83, 0xe0, 0xf0, 0x48, 0x29, 0xc4, 0x48, 0x89,
0x65, 0x98, 0x48, 0x29, 0xc4, 0x31, 0xc0, 0x48, 0x89, 0x65, 0x90, 0xe8, 0xd8,
0x3e, 0x00, 0x00, 0x31, 0xc0, 0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00, 0x48, 0x8b,
0x4d, 0x98, 0x48, 0x8b, 0x55, 0x90, 0xc7
root@debian:~# gdb -q --args unhide
Reading symbols from unhide...
Reading symbols from
/usr/lib/debug/.build-id/41/d7d39535f738606ad3acf0611a8397925762b3.debug...
(gdb) set width 0
(gdb) set pagination off
(gdb) directory /home/benutzer/source/unhide/orig/unhide-20130526
Source directories searched:
/home/benutzer/source/unhide/orig/unhide-20130526:$cdir:$cwd
(gdb) b main
Breakpoint 1 at 0x23e0: file /usr/include/x86_64-linux-gnu/bits/stdio2.h, line
107.
(gdb) run
Starting program: /usr/sbin/unhide
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, main (argc=1, argv=0x7fffffffed18) at
/usr/include/x86_64-linux-gnu/bits/stdio2.h:107
warning: Source file is more recent than executable.
107 return __printf_chk (__USE_FORTIFY_LEVEL - 1, __fmt, __va_arg_pack
());
(gdb) dele 1
(gdb) info target
Symbols from "/usr/sbin/unhide-linux".
Native process:
Using the running image of child Thread 0x7ffff7de5740 (LWP 13520).
While running this, GDB does not access memory from...
Local exec file:
`/usr/sbin/unhide-linux', file type elf64-x86-64.
Entry point: 0x555555556660
...
0x00005555555563e0 - 0x000055555555b001 is .text
...
(gdb) find /b 0x00005555555563e0, 0x000055555555b001, 0x00, 0x48, 0x89, 0x45,
0xc8, 0x31, 0xc0, 0x48, 0x63, 0x05, 0x5d, 0x98, 0x00, 0x00, 0x48, 0x8d, 0x04,
0x85, 0x0f, 0x00, 0x00, 0x00, 0x48, 0x83, 0xe0, 0xf0, 0x48, 0x29, 0xc4, 0x48,
0x89, 0x65, 0x98, 0x48, 0x29, 0xc4, 0x31, 0xc0, 0x48, 0x89, 0x65, 0x90, 0xe8,
0xd8, 0x3e, 0x00, 0x00, 0x31, 0xc0, 0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00, 0x48,
0x8b, 0x4d, 0x98, 0x48, 0x8b, 0x55, 0x90, 0xc7
0x5555555567a9 <brute+41>
1 pattern found.
(gdb) b *(0x5555555567a9 + 42)
Breakpoint 3 at 0x5555555567d3: file unhide-linux-bruteforce.c, line 73.
(gdb) x/10xb 0x5555555567d3
0x5555555567d3 <brute+83>: 0xe8 0xd8 0x3e 0x00 0x00 0x31
0xc0 0x66
0x5555555567db <brute+91>: 0x0f 0x1f
(gdb) info b
Num Type Disp Enb Address What
3 breakpoint keep y 0x00005555555567d3 in brute at
unhide-linux-bruteforce.c:73
(gdb) list unhide-linux-bruteforce.c:73
68 int allpids2[maxpid] ;
69 int x;
70 int y;
71 int z;
72
73 msgln(unlog, 0, "[*]Starting scanning using brute force against PIDS
with fork()\n") ;
74
75 // PID under 301 are reserved for kernel
76 for(x=0; x < 301; x++)
77 {
(gdb) disassemble brute
Dump of assembler code for function brute:
0x0000555555556780 <+0>: push %rbp
0x0000555555556781 <+1>: lea 0x5880(%rip),%rdx # 0x55555555c008
0x0000555555556788 <+8>: xor %esi,%esi
0x000055555555678a <+10>: mov %rsp,%rbp
0x000055555555678d <+13>: push %r15
0x000055555555678f <+15>: push %r14
0x0000555555556791 <+17>: push %r13
0x0000555555556793 <+19>: push %r12
0x0000555555556795 <+21>: push %rbx
0x0000555555556796 <+22>: sub $0x68,%rsp
0x000055555555679a <+26>: mov 0x3a38f(%rip),%rdi #
0x555555590b30 <unlog>
0x00005555555567a1 <+33>: mov %fs:0x28,%rax
0x00005555555567aa <+42>: mov %rax,-0x38(%rbp)
0x00005555555567ae <+46>: xor %eax,%eax
0x00005555555567b0 <+48>: movslq 0x985d(%rip),%rax #
0x555555560014 <maxpid>
0x00005555555567b7 <+55>: lea 0xf(,%rax,4),%rax
0x00005555555567bf <+63>: and $0xfffffffffffffff0,%rax
0x00005555555567c3 <+67>: sub %rax,%rsp
0x00005555555567c6 <+70>: mov %rsp,-0x68(%rbp)
0x00005555555567ca <+74>: sub %rax,%rsp
0x00005555555567cd <+77>: xor %eax,%eax
0x00005555555567cf <+79>: mov %rsp,-0x70(%rbp)
0x00005555555567d3 <+83>: callq 0x55555555a6b0 <msgln>
<<<<<<<<<<<<<<<
0x00005555555567d8 <+88>: xor %eax,%eax
0x00005555555567da <+90>: nopw 0x0(%rax,%rax,1)
0x00005555555567e0 <+96>: mov -0x68(%rbp),%rcx
0x00005555555567e4 <+100>: mov -0x70(%rbp),%rdx
...
##########
gdb -q --args unhide brute
set width 0
set pagination off
set backtrace past-main
directory /home/benutzer/source/unhide/orig/unhide-20130526
b *(brute +83)
run
root@debian:~# gdb -q --args unhide brute
Reading symbols from unhide...
Reading symbols from
/usr/lib/debug/.build-id/41/d7d39535f738606ad3acf0611a8397925762b3.debug...
(gdb) set width 0
(gdb) set pagination off
(gdb) directory /home/benutzer/source/unhide/orig/unhide-20130526
Source directories searched:
/home/benutzer/source/unhide/orig/unhide-20130526:$cdir:$cwd
(gdb) b brute
Breakpoint 1 at 0x2780: file unhide-linux-bruteforce.c, line 65.
(gdb) run
Starting program: /usr/sbin/unhide brute
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Unhide 20130526
Copyright © 2013 Yago Jesus & Patrick Gouin
License GPLv3+ : GNU GPL version 3 or later
http://www.unhide-forensics.info
NOTE : This version of unhide is for systems using Linux >= 2.6
Used options:
Breakpoint 1, brute () at unhide-linux-bruteforce.c:65
65 {
(gdb) b *(brute +83)
Breakpoint 2 at 0x5555555567d3: file unhide-linux-bruteforce.c, line 73.
(gdb) dele 1
(gdb) cont
Continuing.
Breakpoint 2, brute () at unhide-linux-bruteforce.c:73
73 msgln(unlog, 0, "[*]Starting scanning using brute force against PIDS
with fork()\n") ;
(gdb) stepi
Program received signal SIGSEGV, Segmentation fault.
brute () at unhide-linux-bruteforce.c:73
73 msgln(unlog, 0, "[*]Starting scanning using brute force against PIDS
with fork()\n") ;
(gdb) bt
#0 brute () at unhide-linux-bruteforce.c:73
#1 0x00005555555565c9 in main (argc=argc@entry=2,
argv=argv@entry=0x7fffffffecf8) at unhide-linux.c:787
#2 0x00007ffff7e0ebbb in __libc_start_main (main=0x5555555563e0 <main>,
argc=2, argv=0x7fffffffecf8, init=<optimized out>, fini=<optimized out>,
rtld_fini=<optimized out>, stack_end=0x7fffffffece8) at ../csu/libc-start.c:308
#3 0x000055555555668a in _start ()
(gdb) display/i $pc
1: x/i $pc
=> 0x5555555567d3 <brute+83>: callq 0x55555555a6b0 <msgln>
(gdb) info frame 0
Stack frame at 0x7fffffffebf0:
rip = 0x5555555567d3 in brute (unhide-linux-bruteforce.c:73); saved rip =
0x5555555565c9
called by frame at 0x7fffffffec20
source language c.
Arglist at 0x7ffffdffeb50, args:
Locals at 0x7ffffdffeb50, Previous frame's sp is 0x7fffffffebf0
Saved registers:
rbx at 0x7fffffffebb8, rbp at 0x7fffffffebe0, r12 at 0x7fffffffebc0, r13 at
0x7fffffffebc8, r14 at 0x7fffffffebd0, r15 at 0x7fffffffebd8, rip at
0x7fffffffebe8
(gdb) info frame 1
Stack frame at 0x7fffffffec20:
rip = 0x5555555565c9 in main (unhide-linux.c:787); saved rip = 0x7ffff7e0ebbb
called by frame at 0x7fffffffece0, caller of frame at 0x7fffffffebf0
source language c.
Arglist at 0x7fffffffebe8, args: argc=argc@entry=2,
argv=argv@entry=0x7fffffffecf8
Locals at 0x7fffffffebe8, Previous frame's sp is 0x7fffffffec20
Saved registers:
rbx at 0x7fffffffebf8, rbp at 0x7fffffffec00, r12 at 0x7fffffffec08, r13 at
0x7fffffffec10, rip at 0x7fffffffec18
(gdb) info frame 2
Stack frame at 0x7fffffffece0:
rip = 0x7ffff7e0ebbb in __libc_start_main (../csu/libc-start.c:308); saved rip
= 0x55555555668a
called by frame at 0x0, caller of frame at 0x7fffffffec20
source language c.
Arglist at 0x7fffffffec18, args: main=0x5555555563e0 <main>, argc=2,
argv=0x7fffffffecf8, init=<optimized out>, fini=<optimized out>,
rtld_fini=<optimized out>, stack_end=0x7fffffffece8
Locals at 0x7fffffffec18, Previous frame's sp is 0x7fffffffece0
Saved registers:
rbx at 0x7fffffffecb0, rbp at 0x7fffffffecb8, r12 at 0x7fffffffecc0, r13 at
0x7fffffffecc8, r14 at 0x7fffffffecd0, rip at 0x7fffffffecd8
(gdb) info frame 3
Stack frame at 0x0:
rip = 0x55555555668a in _start; saved rip = <not saved>
Outermost frame: outermost
caller of frame at 0x7fffffffece0
Arglist at 0x7fffffffecd8, args:
Locals at 0x7fffffffecd8, Previous frame's sp is 0x7fffffffece8
https://stackoverflow.com/questions/37321252/check-used-stack-size-using-core-file/37327019
(gdb) print (char *)_environ - (char *)$sp
$1 = 33554880
(gdb) print/x (char *)_environ - (char *)$sp
$2 = 0x20001c0
(gdb) print/x maxpid
$4 = 0x400000
(gdb) print/x sizeof(allpids2[0])
$5 = 0x4
(gdb) print/x sizeof(allpids2[0]) * maxpid
$6 = 0x1000000
(gdb) print sizeof(allpids2[0]) * maxpid
$7 = 16777216
(gdb) print (sizeof(allpids2[0]) * maxpid)/1024
$8 = 16384
(gdb) print (sizeof(allpids2[0]) * maxpid)/1024/1024
$9 = 16
root@debian:~# ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 11863
max locked memory (kbytes, -l) 65536
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192 <<<<<<<<<<< Just 8 MB
stack size, but array allpids2 has 16 MB of size
cpu time (seconds, -t) unlimited
max user processes (-u) 11863
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
Description: Allocate pid arrays from the stack
Author: Bernhard Ãbelacker <[email protected]>
Bug-Debian: https://bugs.debian.org/945864
Forwarded: no
Last-Update: 2019-12-03
--- unhide-20130526.orig/unhide-linux-bruteforce.c
+++ unhide-20130526/unhide-linux-bruteforce.c
@@ -64,14 +64,20 @@ void *funcionThread (void *parametro)
void brute(void)
{
int i=0;
- int allpids[maxpid] ;
- int allpids2[maxpid] ;
+ int* allpids;
+ int* allpids2;
int x;
int y;
int z;
msgln(unlog, 0, "[*]Starting scanning using brute force against PIDS with fork()\n") ;
+ allpids = malloc(sizeof(int)*maxpid) ;
+ allpids2 = malloc(sizeof(int)*maxpid) ;
+ if (!allpids || !allpids2) {
+ die(unlog, "Error: Cannot allocate pid arrays ! Exiting.");
+ }
+
// PID under 301 are reserved for kernel
for(x=0; x < 301; x++)
{
@@ -214,4 +220,7 @@ void brute(void)
}
}
}
+
+ free(allpids);
+ free(allpids2);
}