3

I am working on a project in which i have hooked the system open call. When a user attempts to open a file i want sys_open to block the action if the current task (pid or tgid that "black listed" ) has potential to leak the file out of the host.

Any ways, the hooking itself worked fine on sys_read and sys_write (I have some printk inside the fake function as an indicator).

but, when i try the hooking on the sys_open function, nothing is printed out - means that the override not succeeded. I printed out the address of the sys call before and after the override so this might not be the issue.

I am confused about what can cause that uneven behavior when hooking different functions.

will be glad for some input here. thanks !

dmesg output examples:

when hooked write -

...

[ 2989.500485] in my write ...

[ 2989.500585] in my write ...

when hooked open, noting printed, but here some "debug" output -

[ 890.709696] address found 00000000103d42f6

[ 890.709697] Address before - 0000000006d29c3a

[ 890.709698] Address after - 00000000a5117c6a

[ 948.533339] BYE !!!

using lubuntu vm (kernel v 4.15.0.20).

here is the source code:

#include <linux/init.h> // Macros used to mark up functions e.g., __init __exit #include <linux/module.h> #include <linux/kernel.h> #include <linux/slab.h> #include <linux/types.h> #include <linux/syscalls.h> #include <linux/sched.h> #include <asm/uaccess.h> #include <asm/unistd.h> #include <asm/page.h> #include <linux/kallsyms.h> #include <linux/semaphore.h> #include <asm/cacheflush.h> #include <linux/set_memory.h> #include <linux/cred.h> #include <linux/user.h> MODULE_LICENSE("GPL"); MODULE_AUTHOR("ABC"); MODULE_VERSION("0.1"); asmlinkage long (*original_call)( char __user *filename, int flags, umode_t mode); // for read or write: (unsigned int fd, char __user *buf, size_t count); asmlinkage long my_sys_READ(unsigned int fd, char __user *buf, size_t count); asmlinkage long my_sys_WRITE(unsigned int fd, char __user *buf, size_t count); asmlinkage long my_sys_OPEN( char __user *filename, int flags, umode_t mode); unsigned long* find_sys_call_table(void); void set_page_rw( unsigned long addr); void set_page_ro( unsigned long addr); const struct cred *_cred = NULL ; struct user_struct *user =NULL ; unsigned long* sys_call_table = NULL; void set_page_rw(unsigned long addr) { unsigned int level; pte_t *pte = lookup_address(addr, &level); if (pte->pte &~ _PAGE_RW) pte->pte |= _PAGE_RW; } void set_page_ro( unsigned long addr) { unsigned int level; pte_t *pte = lookup_address(addr, &level); pte->pte = pte->pte &~_PAGE_RW; } /* asmlinkage long my_sys_READ(unsigned int fd, char __user *buf, size_t count) { //_cred = current_cred(); user = get_current_user(); if( (int)(*user).uid.val == uid ) { printk(KERN_ALERT"in my read ... hacked !"); return original_call(fd, buf, count); } printk(KERN_ALERT"in my read ... hacked !"); return original_call(fd, buf, count); } asmlinkage long my_sys_WRITE(unsigned int fd, char __user *buf, size_t count) { //_cred = current_cred(); user = get_current_user(); if( (int)(*user).uid.val == uid ) { printk(KERN_ALERT"in my write ... hacked !"); return original_call(fd, buf, count); } printk(KERN_ALERT"in my write ... hacked !"); return original_call(fd, buf, count); } */ asmlinkage long my_sys_OPEN( char __user *filename, int flags, umode_t mode) { printk(KERN_ALERT"in my open ... hacked !"); return original_call(filename, flags, mode); } unsigned long* find_sys_call_table(void) { return (unsigned long *)kallsyms_lookup_name("sys_call_table"); } int init_module() { printk(KERN_ALERT "I'm dangerous. I hope you did a "); printk(KERN_ALERT "sync before you insmod'ed me.\n"); sys_call_table = find_sys_call_table(); printk(KERN_INFO"address found %p \n",sys_call_table); original_call = (void *)sys_call_table[__NR_open]; set_page_rw((unsigned long)sys_call_table); printk(KERN_INFO" Address before - %p", (void *)sys_call_table[__NR_open]); sys_call_table[__NR_open] = (unsigned long)my_sys_OPEN; printk(KERN_INFO" Address after - %p", (void *)sys_call_table[__NR_open]); return 0; } /* * Cleanup − unregister the appropriate file from /proc */ void cleanup_module() { /* * Return the system call back to normal */ if (sys_call_table[__NR_open] != (unsigned long)my_sys_OPEN) { printk(KERN_ALERT "Somebody else also played with the "); printk(KERN_ALERT "open system call\n"); } printk(KERN_ALERT "BYE !!!\n"); sys_call_table[__NR_open] = (unsigned long)original_call; } 
5
  • Which Ubuntu version do you use? What's your glibc version? Commented Sep 30, 2018 at 18:42
  • Hm, I cannot see a reason why this shouldn't work. How do you exactly test it? Commented Sep 30, 2018 at 20:55
  • The proper way to do this is not to behave like a virus, but to write a LSM. Commented Oct 1, 2018 at 7:12
  • I am using ubuntu lite 18.04 (kernel v 4.15.0.20) ,glibc version 2.27. To test that the hooking part alone works fine i actually print inside my sys_open warper function to dmesg. ** the strange ** part is that when i hooked other sys_calls, it has printed out whenever the sys_call occurred - which is a lot of curse... Commented Oct 1, 2018 at 13:00
  • Can you run strace on your use space program that you use for testing to see which system call it calls ?(e.g. it might call openat() instead of open()) Commented Oct 1, 2018 at 13:16

1 Answer 1

4

Your Ubuntu version is based on glibc 2.27.

glibc version 2.26 switched to implementing open with openat:

commit b41152d716ee9c5ba34495a54e64ea2b732139b5 Author: Adhemerval Zanella <[email protected]> Date: Fri Nov 11 15:00:03 2016 -0200 Consolidate Linux open implementation This patch consolidates the open Linux syscall implementation on sysdeps/unix/sysv/linux/open{64}.c. The changes are: 1. Remove open{64} from auto-generation syscalls.list. 2. Add a new open{64}.c implementation. For architectures that define __OFF_T_MATCHES_OFF64_T the default open64 will create alias to required open symbols. 3. Use __NR_openat as default syscall for open{64}. 

You will have to hook openat in addition to open as a result.

Note that the Linux kernel provides a proper interface for this, in the form of the fanotify interface. If you use that, you will not have to worry about such details.

Sign up to request clarification or add additional context in comments.

2 Comments

many thanks, i would vote for you if i could. But still- I would like to know , for next time, how did you find the solution? I mean do you work in that area of content so that you are more or less updated?or what are the other tools that available to me for next time ? in general of curse :)
strace and, for complicated cases, Systemtap are are useful tools for system call tracing. For hooking file I/O independent of file systems, fanotify is the recommended interface.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.