Reputation: 31
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 !
...
[ 2989.500485] in my write ...
[ 2989.500585] in my write ...
[ 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;
}
Upvotes: 3
Views: 585
Reputation: 33694
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.
Upvotes: 4