syscall.c

Note: This program involves modification of the Kernel syscall_table, which is no longer exported in Kernel 2.6.17. This may require recompiling the kernel with syscall_table exported.

/*
 * syscall.c
 *
 * System call "stealing" sample.
 */
 
/*
 * Copyright (C) 2001 by Peter Jay Salzman
 */
 
/*
 * The necessary header files
 */
 
/*
 * Standard in kernel modules
 */
#include <linux/kernel.h>       /* We're doing kernel work */
#include <linux/module.h>       /* Specifically, a module, */
#include <linux/moduleparam.h>  /* which will have params */
#include <linux/unistd.h>       /* The list of system calls */
 
/*
 * For the current (process) structure, we need
 * this to know who the current user is.
 */
#include <linux/sched.h>
#include <asm/uaccess.h>
 
/*
 * The system call table (a table of functions). We
 * just define this as external, and the kernel will
 * fill it up for us when we are insmod'ed
 *
 * sys_call_table is no longer exported in 2.6.x kernels.
 * If you really want to try this DANGEROUS module you will
 * have to apply the supplied patch against your current kernel
 * and recompile it.
 */
void **sys_call_table;
 
/*
 * UID we want to spy on - will be filled from the
 * command line
 */
static int uid;
module_param(uid, int, 0644);
/*
 * A pointer to the original system call. The reason
 * we keep this, rather than call the original function
 * (sys_open), is because somebody else might have
 * replaced the system call before us. Note that this
 * is not 100% safe, because if another module
 * replaced sys_open before us, then when we're inserted
 * we'll call the function in that module - and it
 * might be removed before we are.
 *
 * Another reason for this is that we can't get sys_open.
 * It's a static variable, so it is not exported.
 */
 
asmlinkage int (*original_call) (const char *, int, int);
/*
 * The function we'll replace sys_open (the function
 * called when you call the open system call) with. To
 * find the exact prototype, with the number and type
 * of arguments, we find the original function first
 * (it's at fs/open.c).
 *
 * In theory, this means that we're tied to the
 * current version of the kernel. In practice, the
 * system calls almost never change (it would wreck havoc
 * and require programs to be recompiled, since the system
 * calls are the interface between the kernel and the
 * processes).
 */
 
asmlinkage int our_sys_open(const char *filename, int flags, int mode)
{
  int i = 0;
  char ch;
  /*
   * Check if this is the user we're spying on
   */
  if (uid == current->uid) {
    /*
     * Report the file, if relevant
     */
    printk("Opened file by %d: ", uid);
    do {
      get_user(ch, filename + i);
      i++;
      printk("%c", ch);
    } while (ch != 0);
    printk("\n");
  }
  /*
   * Call the original sys_open - otherwise, we lose
   * the ability to open files
   */
  return original_call(filename, flags, mode);
}
 
/*
 * Initialize the module - replace the system call
 */
int init_module()
{
  /*
   * Warning - too late for it now, but maybe for
   * next time...
   */
  printk(KERN_ALERT "I'm dangerous. I hope you did a ");
  printk(KERN_ALERT "sync before you insmod'ed me.\n");
  printk(KERN_ALERT "My counterpart, cleanup_module(), is even");
  printk(KERN_ALERT "more dangerous. If\n");
  printk(KERN_ALERT "you value your file system, it will ");
  printk(KERN_ALERT "be \"sync; rmmod\" \n");
  printk(KERN_ALERT "when you remove this module.\n");
  /*
   * Keep a pointer to the original function in
   * original_call, and then replace the system call
   * in the system call table with our_sys_open
   */
 
  /* 
   * This address 0xc03878a0 is from System.map under /boot.
   * However, this example and the hack didn't work on Kernel 2.6.17.
   * Maybe a way to get it to work is to recompile the kernel
   * with sys_call_table exported.
   */
 
  sys_call_table = (void**) simple_strtoul("0xc03878a0",NULL,16);
 
  original_call = sys_call_table[__NR_open];
  sys_call_table[__NR_open] = our_sys_open;
  /*
   * To get the address of the function for system
   * call foo, go to sys_call_table[__NR_foo].
   */
  printk(KERN_INFO "Spying on UID:%d\n", uid);
  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] != our_sys_open) {
    printk(KERN_ALERT "Somebody else also played with the ");
    printk(KERN_ALERT "open system call\n");
    printk(KERN_ALERT "The system may be left in ");
    printk(KERN_ALERT "an unstable state.\n");
  }
  sys_call_table[__NR_open] = original_call;
}
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License