|
楼主 |
发表于 2003-5-26 06:11:45
|
显示全部楼层
procmon.c
[code:1]
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/devfs_fs_kernel.h>
#include <asm/ptrace.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
#include <asm/string.h>
#include <linux/timex.h>
MODULE_AUTHOR("Jacob Bower");
MODULE_DESCRIPTION("Procmon kernel module 0.3");
MODULE_LICENSE("GPL");
int (*system_execve) (struct pt_regs regs);
extern void *sys_call_table[];
typedef struct tagqueue_entry {
struct tagqueue_entry *next;
char *data;
} queue_entry_t;
spinlock_t queue_lock = SPIN_LOCK_UNLOCKED;
queue_entry_t *head;
queue_entry_t *tail;
#define MAX_QUEUE_LENGTH 65535
int queue_len;
int active = 0;
int read_offs;
char *current_log_entry;
DECLARE_WAIT_QUEUE_HEAD(procmon_wait);
void queue_init(void)
{
head = tail = NULL;
queue_len = 0;
}
void queue_clear(void)
{
spin_lock(&queue_lock);
while(tail) {
queue_entry_t *this_entry = tail;
tail = this_entry->next;
if(this_entry->data)
kfree(this_entry->data);
kfree(this_entry);
}
head = NULL;
queue_len = 0;
spin_unlock(&queue_lock);
}
char *queue_pop(void)
{
char *data;
queue_entry_t *old_entry;
spin_lock(&queue_lock);
if(queue_len == 0) {
spin_unlock(&queue_lock);
return NULL;
}
data = tail->data;
old_entry = tail;
if(tail == head)
head = NULL;
tail = tail->next;
kfree(old_entry);
queue_len--;
spin_unlock(&queue_lock);
return data;
}
int queue_push(char *data)
{
queue_entry_t *new_entry;
spin_lock(&queue_lock);
if((queue_len + 1) > MAX_QUEUE_LENGTH) {
printk("Procmon: proccess logging queue overflow (try increasing MAX_QUEUE_LENGTH)!\n");
spin_unlock(&queue_lock);
return 0;
}
queue_len++;
new_entry = kmalloc(sizeof(queue_entry_t), GFP_KERNEL);
if(!new_entry) {
printk("Procmon: failed to allocate memory for queue entry!\n");
spin_unlock(&queue_lock);
return 0;
}
new_entry->data = data;
new_entry->next = NULL;
if(!tail)
tail = new_entry;
if(head)
head->next = new_entry;
head = new_entry;
spin_unlock(&queue_lock);
return 1;
}
long get_timestamp(void)
{
struct timeval now;
int i;
do_gettimeofday(&now);
i = now.tv_sec;
return i;
}
void dolog(char *processname, char *args)
{
if(active) {
char *data;
data = kmalloc(strlen(processname) + strlen(args) + 30, GFP_KERNEL);
if(!data) {
printk("Warning: process name/args too long to log!!");
return ;
}
sprintf(data, "%li:%i:%i:%s%s",
(long)get_timestamp(),
(int)current->uid,
(int)current->pid,
processname, args);
if( !queue_push(data) )
kfree(data);
else
wake_up_interruptible(&procmon_wait);
}
}
char *buildargstr(char **args)
{
char **arg;
int argslen = 0;
char *argstr;
arg = ++args;
while(*arg)
argslen += 1 + strlen(*arg++);
argstr = kmalloc(argslen + 1, GFP_KERNEL);
if(!argstr) {
argstr = kmalloc(17, GFP_KERNEL);
strcpy(argstr, "<arg overflow!!>");
} else {
argstr[0] = '\0';
while(*args) {
strcat(argstr, " ");
strcat(argstr, *args++);
}
}
return argstr;
}
asmlinkage int proc_log_execve(struct pt_regs regs)
{
int error;
char * filename;
char * argstr;
MOD_INC_USE_COUNT;
argstr = buildargstr((char **) regs.ecx);
filename = getname((char *) regs.ebx);
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
error = do_execve(filename, (char **) regs.ecx, (char **) regs.edx, &regs);
if (error == 0) {
current->ptrace &= ~PT_DTRACE;
dolog(filename, argstr);
}
putname(filename);
kfree(argstr);
out:
MOD_DEC_USE_COUNT;
return error;
}
static ssize_t read_procmon(struct file *flip, char *dest,
size_t len, loff_t *off)
{
int bytes_read = 0;
while(len && !bytes_read) {
if(!current_log_entry) {
read_offs = 0;
current_log_entry = queue_pop();
}
while(current_log_entry && len--) {
if(read_offs < strlen(current_log_entry))
*dest++ = current_log_entry[read_offs++];
else {
kfree(current_log_entry);
current_log_entry = queue_pop();
*dest++ = '\n';
read_offs = 0;
}
bytes_read++;
}
if(flip->f_flags & O_NONBLOCK)
return -EAGAIN;
if(!bytes_read) {
interruptible_sleep_on(&procmon_wait);
if(signal_pending(current))
return -ERESTARTSYS;
}
}
*off += bytes_read;
return bytes_read;
}
static int release_procmon(struct inode *inode, struct file *flip)
{
active = 0;
if(current_log_entry)
kfree(current_log_entry);
queue_clear();
MOD_DEC_USE_COUNT;
return 0;
}
static int open_procmon(struct inode *inode, struct file *flip)
{
if(active)
return -EBUSY;
else {
current_log_entry = NULL;
queue_init();
active = 1;
MOD_INC_USE_COUNT;
return 0;
}
}
#define PROCMON_MAJOR 240
static struct file_operations procmon_fops = {
read: read_procmon,
open: open_procmon,
release: release_procmon,
};
int procmon_register(void)
{
if(devfs_register_chrdev(PROCMON_MAJOR, "procmon", &procmon_fops)) {
printk("Unable to get major %d for log dev(s)", PROCMON_MAJOR);
return 0;
}
return 1;
}
void procmon_deregister(void)
{
devfs_unregister_chrdev(PROCMON_MAJOR, "procmon");
}
int init_module(void)
{
if( procmon_register() ) {
system_execve = sys_call_table[__NR_execve];
sys_call_table[__NR_execve] = proc_log_execve;
return 0;
} else
return -1;
}
void cleanup_module(void)
{
if( sys_call_table[__NR_execve] != proc_log_execve ) {
printk("!!WARNING!! Another module has hooked the system excve function\n");
printk("original system function restored. System may be screwed.\n");
}
sys_call_table[__NR_execve] = system_execve;
if(current_log_entry)
kfree(current_log_entry);
queue_clear();
procmon_deregister();
}
[/code:1] |
|