linux kernel module hooking certain system calls cannot see string parameters in user space

0

I am doing an exercise for a class to hook some system calls on a running kernel using a linux kernel module and using my new_sys_call() in place of the old one. I am developing on CentOS 7 and using a stock kernel-3.10.0-862.3.2. I was able to successfully hook execve and I can access parameter values but I cannot seem to access the rename syscall parameter values. I realize this is probably not a practical real world approach but I am trying to learn more about kernel development and how system calls work.

Here's an example of the hooking method definitions:

/*
   Original Syscall Prototype
*/
asmlinkage long (*orig_sys_chdir_fn)(const char __user *filename);

/*
new syscall
*/
asmlinkage long new_sys_chdir(const char __user *filename) {

   // do stuff
   return orig_sys_chdir_fn(filename);
}

We obtain the stub chdir address with this code:

orig_stub_chdir_addr = ((unsigned long *)(sys_call_table_addr))[__NR_chdir];



  Thread 357 hit Breakpoint 3, new_sys_rename (oldname=0xffffff9c <error: Cannot access memory at address 0xffffff9c>,
    newname=0xffffff9c <error: Cannot access memory at address 0xffffff9c>) at /home/ulys/syshooks/kmod/sysrename.c:19
19      asmlinkage long new_sys_rename(const char __user *oldname,  const char __user *newname) {
(gdb) info registers
rax            0xffffffff8122dbd0       -2128421936
rbx            0x0      0
rcx            0x7ffd0faf9480   140724866618496
rdx            0xffffff9c       4294967196
rsi            0xffffff9c       4294967196
rdi            0xffffff9c       4294967196
rbp            0xffff88004183bf48       0xffff88004183bf48
rsp            0xffff88004183bf40       0xffff88004183bf40
r8             0x0      0
r9             0x1      1
r10            0x7ffd0faf7320   140724866609952
r11            0x202    514
r12            0x0      0
r13            0x0      0
r14            0x0      0
r15            0x0      0
rip            0xffffffffc0540b20       0xffffffffc0540b20 <new_sys_rename>
eflags         0x10246  [ PF ZF IF RF ]
cs             0x10     16
ss             0x18     24
ds             0x0      0
es             0x0      0
fs             0x0      0
gs             0xb      11
(gdb) info stack
#0  new_sys_rename (oldname=0xffffff9c <error: Cannot access memory at address 0xffffff9c>,
    newname=0xffffff9c <error: Cannot access memory at address 0xffffff9c>) at /home/ulys/syshooks/kmod/sysrename.c:19
#1  0xffffffff8122dbee in gather_surplus_pages (delta=-2123237509, h=0x0 <irq_stack_union>) at mm/hugetlb.c:1764
#2  hugetlb_acct_memory (h=0x0 <irq_stack_union>, delta=-2123237521) at mm/hugetlb.c:3149
#3  0xffffffff8171f82f in inet_netconf_fill_devconf (skb=0xffffffff8171f77b <inet_netconf_fill_devconf+123>,
    ifindex=<optimized out>, devconf=<optimized out>, portid=<optimized out>, seq=<optimized out>, flags=<optimized out>,
    type=<error reading variable: Cannot access memory at address 0x10>, event=80) at net/ipv4/devinet.c:1786
Backtrace stopped: previous frame inner to this frame (corrupt stack?)
(gdb) x/s 0x7ffd0faf9480
0x7ffd0faf9480: "/tmp/test2"

You can see the bogus addresses at 0xffffff9c which cannot be read by copy_from_user or used by anything in the new_sys_rename function. You can see that the newname is in the register rcx but I can't locate oldname. I have noticed this on several different filename based syscalls such as chmod and chdir as well.

On chdir, I receive similar results except I can't find filename in any register.

Thread 304 hit Breakpoint 1, new_sys_chdir (
    filename=0xffffff9c <error: Cannot access memory at address 0xffffff9c>)
    at /home/ulys/syshooks/kmod/syschdir.c:17
17      asmlinkage long new_sys_chdir(const char __user *filename) {
(gdb) info registers
rax            0x0      0
rbx            0x0      0
rcx            0xffff880055d47f18       -131939955343592
rdx            0x3      3
rsi            0x3      3
rdi            0xffffff9c       4294967196
rbp            0xffff880055d47f48       0xffff880055d47f48
rsp            0xffff880055d47f10       0xffff880055d47f10
r8             0xc919d0 13179344
r9             0xcba2d0 13345488
r10            0x7f7147cfd030   140124512833584
r11            0x246    582
r12            0x3      3
r13            0xc8f320 13169440
r14            0x0      0
r15            0x0      0
rip            0xffffffffc0561000       0xffffffffc0561000 <new_sys_chdir>
eflags         0x10246  [ PF ZF IF RF ]
cs             0x10     16
ss             0x18     24
ds             0x0      0
es             0x0      0
fs             0x0      0
gs             0xb      11
(gdb) x/s 0xffff880055d47f18
0xffff880055d47f18:     "o\367q\201\377\377\377\377{\367q\201\377\377\377\377\225\"", <incomplete sequence \356>
(gdb) x/s 0xc919d0
0xc919d0:       " "
(gdb) x/s 0xc919d0
0xc919d0:       " "
(gdb) x/s 0x7f7147cfd030
0x7f7147cfd030: "f\017s\372\005f\017t\321f\017\370\320fD\017\327\312\323\352A\323\351D)\312\017\205\v\004"
(gdb) info stack
#0  new_sys_chdir (filename=0xffffff9c <error: Cannot access memory at address 0xffffff9c>)
    at /home/ulys/syshooks/kmod/syschdir.c:17
#1  0xffffffff81218b3e in move_page_tables (vma=<optimized out>, old_addr=3, new_vma=<optimized out>,
    new_addr=18446744071586314095, len=<optimized out>, need_rmap_locks=<optimized out>) at mm/mremap.c:187
#2  0xffffffff8171f82f in inet_netconf_fill_devconf (skb=0xffffffff8171f77b <inet_netconf_fill_devconf+123>,
    ifindex=<optimized out>, devconf=<optimized out>, portid=<optimized out>, seq=<optimized out>, flags=<optimized out>,
    type=<error reading variable: Cannot access memory at address 0x10>, event=80) at net/ipv4/devinet.c:1786
Backtrace stopped: previous frame inner to this frame (corrupt stack?)

It appears to work just fine on execve. Here you can see similar output but I have no problems accessing any of execve's filename or argv strings.

Thread 335 hit Breakpoint 2, new_sys_execve (filename=0x55c85e0d7af0 "/usr/libexec/postfix/pickup", argv=0x55c85e0d3d00,
    envp=0x55c85e0d3d00) at /home/ulys/syshooks/kmod/sysexecve.c:21
21              const char __user * const __user * envp) {
(gdb) info registers
rax            0xffffffff8171fd80       -2123235968
rbx            0x0      0
rcx            0xffffffff       4294967295
rdx            0x55c85e0d3d00   94319059746048
rsi            0x55c85e0d3d00   94319059746048
rdi            0x55c85e0d7af0   94319059761904
rbp            0x0      0x0 <irq_stack_union>
rsp            0xffff88005323ff50       0xffff88005323ff50
r8             0x30     48
r9             0x0      0
r10            0xffffffff       4294967295
r11            0x206    518
r12            0x0      0
r13            0x0      0
r14            0x0      0
r15            0x0      0
rip            0xffffffffc053f880       0xffffffffc053f880 <new_sys_execve>
eflags         0x10282  [ SF IF RF ]
cs             0x10     16
ss             0x18     24
ds             0x0      0
es             0x0      0
fs             0x0      0
gs             0xb      11
(gdb) info stack
#0  new_sys_execve (filename=0x55c85e0d7af0 "/usr/libexec/postfix/pickup", argv=0x55c85e0d3d00, envp=0x55c85e0d3d00)
    at /home/ulys/syshooks/kmod/sysexecve.c:21
#1  0xffffffff8171fdc8 in rtm_to_ifaddr (pprefered_lft=<synthetic pointer>, pvalid_lft=<synthetic pointer>,
    nlh=0x0 <irq_stack_union>, net=0x0 <irq_stack_union>) at net/ipv4/devinet.c:801
#2  inet_rtm_newaddr (skb=0x0 <irq_stack_union>, nlh=0x0 <irq_stack_union>) at net/ipv4/devinet.c:854
Backtrace stopped: Cannot access memory at address 0x8

So why are some of these variables protected from kernel space? Where can they be found and is there another kernel function that can be called to get the values?

c
linux
kernel
hook
system-calls

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0