/*

  Safer execve() implementation - shellcode execution is permitted
  for Linux 2.4.xx

  (c) Marcin Ulikowski <elceef@itsec.pl>

  # cc -O2 -c -Wall -I/lib/modules/`uname -r`/build/include/ safexec.c
  # insmod safexec
  
  Example /var/log/messages entry:
  May 13 00:13:37 osiris safexec: shellcode execution attempt (pid:1533,
  uid/euid:0/0, ebx:0xbffff4a8, ecx:0xbffff4a0, edx:0x0). Task terminated.

  Distributed without any warranty under GPL version 2 terms
  and conditions

*/


#define __KERNEL__
#define MODULE

#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/string.h>
#include <asm/unistd.h>
#include <linux/version.h>
#include <asm/string.h>
#include <asm/segment.h>
#include <asm/uaccess.h>

#define VERSION "20051029"

extern void *sys_call_table[];

static int (*o_execve)(struct pt_regs regs);

static int safe_execve(struct pt_regs regs) {
  int *addr = (int *)regs.edx;
  char *filename;
  int envp = 0x0;
  int ret = 0;

#ifdef DEBUG
  /* this is for me, useless for You ;-) */
  printk("safexec: eip:0x%08lx, ebx:0x%08lx, ecx:0x%08lx, edx:0x%08lx\n",
         regs.eip, regs.ebx, regs.ecx, regs.edx);
#endif

  /* getting data from virtual address 0x0 would cause kernel panic */
  if (access_ok(VERIFY_READ, addr, 4))
    get_user(envp, addr);

  filename = getname((char *)regs.ebx);

  if (!strncmp("//bin/sh", filename, 8) ||
      !strncmp("/bin//sh", filename, 8) ||
      (!strncmp("/bin/sh", filename, 7) && (!regs.edx || !envp)) || 
      (((regs.ebx & 0xFFFF0000) == 0xBFFF0000) &&
       ((regs.ecx & 0xFFFF0000) == 0xBFFF0000) &&
       (!regs.edx || !envp))) {

    printk("safexec: shellcode execution attempt (pid:%d, uid/euid:%d/%d, "
           "ebx:0x%lx, ecx:0x%lx, edx:0x%lx). Task terminated.\n",
           current->pid, current->uid, current->euid, regs.ebx, regs.ecx,
           regs.edx);

    ret = -EACCES;

  }

  putname(filename);
/*
  if ((regs.ebx & 0xF0000000) == 0x40000000) {

    printk("safexec: return-into-libc attack attempt (pid:%d, uid/euid:%d/%d, "
           "ebx:0x%lx, ecx:0x%lx, edx:0x%lx). Task terminated.\n",
           current->pid, current->uid, current->euid, regs.ebx, regs.ecx,
           regs.edx);

    ret = -EACCES;

  }
*/
  if (!ret)
     ret = do_execve(filename, (char **)regs.ecx, (char **)regs.edx, &regs);

  return ret;
}

int init_module(void) {
  printk("safexec version "VERSION": init... ");
  o_execve = sys_call_table[__NR_execve];
  sys_call_table[__NR_execve] = safe_execve;
  printk("done.\n");

  return 0;
}

void cleanup_module(void) {
  sys_call_table[__NR_execve] = o_execve;
  printk("safexec: unloaded.\n");
}

MODULE_LICENSE("GPL");

