#include #include #include #include #include #include #include #include #include #include #include #include MODULE_LICENSE("GPL"); MODULE_AUTHOR("Olivier Blin "); struct opened_file { struct list_head s_list; char *name; }; unsigned long **sys_call_table; static struct dentry *dbg_dir; static struct dentry *dbg_file; struct opened_file bp; DECLARE_MUTEX(files_mutex); ssize_t (*read)(int f, const void *buf, size_t n); long (*open)(const char __user *filename, int flags, int mode); static void *profile_seq_start(struct seq_file *file, loff_t *pos) { struct list_head *p; loff_t l = *pos; down(&files_mutex); list_for_each(p, &bp.s_list) if (!l--) return list_entry(p, struct opened_file, s_list); return NULL; } static void *profile_seq_next(struct seq_file *file, void *v, loff_t *pos) { struct list_head *p = ((struct opened_file *)v)->s_list.next; (*pos)++; return p == &bp.s_list ? NULL : list_entry(p, struct opened_file, s_list); } static void profile_seq_stop(struct seq_file *file, void *v) { up(&files_mutex); } static int profile_seq_show(struct seq_file *file, void *v) { seq_printf(file, ((struct opened_file *)v)->name); seq_putc(file, '\n'); return 0; } static struct seq_operations profile_seq_ops = { .start = profile_seq_start, .next = profile_seq_next, .stop = profile_seq_stop, .show = profile_seq_show, }; static int profile_open(struct inode *inode, struct file *file) { return seq_open(file, &profile_seq_ops); } static struct file_operations profile_fops = { .owner = THIS_MODULE, .open = profile_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release }; /* Borrowed from * http://downloads.securityfocus.com/downloads/scprint.tar.gz * http://www.gnome.org/~lcolitti/gnome-startup/linux-iolog/readlog.c * http://kerneltrap.org/node/5793 */ unsigned long **find_sys_call_table(void) { unsigned long *p; for (p = (unsigned long *)((init_mm.end_code + 4) & 0xfffffffc); p < (unsigned long *)init_mm.end_data; p++) { if (p[__NR_close] == (unsigned long) sys_close){ return (unsigned long **) p; } } return NULL; } void addfilename(const char *filename) { struct opened_file *f; f = kmalloc(sizeof(struct opened_file), GFP_KERNEL); if (f == NULL) return; f->name = kmalloc(strlen(filename) + 1, GFP_KERNEL); if (f->name == NULL) return; strcpy(f->name, filename); INIT_LIST_HEAD(&f->s_list); printk(KERN_INFO "locking while adding: %s\n", filename); down(&files_mutex); list_add_tail(&f->s_list, &bp.s_list); up(&files_mutex); printk(KERN_INFO "unlocking after adding: %s\n", filename); } long loggingopen(const char __user *filename, int flags, int mode) { struct file *f = NULL; long fd; fd = open(filename, flags, mode); printk(KERN_INFO "opening fd %ld for %s\n", fd, filename); if(fd > 0 && current) { f = current->files->fd_array[fd]; if(f && f->f_dentry && f->f_vfsmnt) { char tmpname[PATH_MAX]; char *name = d_path(f->f_dentry, f->f_vfsmnt, tmpname, sizeof(tmpname) - 1); if (name) addfilename(name); } } return fd; } ssize_t loggingread(int fd, const void *buf, size_t n) { struct file *f = NULL; char *name = NULL; loff_t offset = 0; struct timeval tv; char tmpname[256]; do_gettimeofday(&tv); if(current) f = current->files->fd_array[fd]; printk(KERN_DEBUG "READ: f: %p\n", f); if(f) offset = f->f_pos; if (f) printk(KERN_DEBUG "READ: d_entry: %p, vfsmnt: %p\n", f->f_dentry, f->f_vfsmnt); if(f && f->f_dentry && f->f_vfsmnt) { printk(KERN_DEBUG "READ: d_path\n"); name = d_path(f->f_dentry, f->f_vfsmnt, tmpname, sizeof(tmpname) - 1); if (name) addfilename(name); } printk(KERN_DEBUG "READ: %lu.%lu (%s/%d) %Lu %s\n", tv.tv_sec, tv.tv_usec, current ? current->comm : "?", current ? current->pid : 0, offset, name ? name : "" ); return read(fd, buf, n); } static int __init readlog_init(void) { sys_call_table = find_sys_call_table(); /* compare with grep sys_call_table /boot/System.map */ printk(KERN_INFO "Found sys_call_table at %p\n", sys_call_table); open = (void *) (sys_call_table[__NR_open]); sys_call_table[__NR_open] = (void *) loggingopen; read = (void *) (sys_call_table[__NR_read]); /* sys_call_table[__NR_read] = (void *) loggingread; */ dbg_dir = debugfs_create_dir("dmc", NULL); if (IS_ERR(dbg_dir)) { printk(KERN_NOTICE ": debugfs is not available\n"); return -ENODEV; } if (dbg_dir == NULL) { printk(KERN_NOTICE ": unable to create usbmon directory\n"); return -ENODEV; } dbg_file = debugfs_create_file("bp", 0600, dbg_dir, NULL, &profile_fops); if (dbg_file == NULL) { debugfs_remove(dbg_dir); return -ENODEV; } INIT_LIST_HEAD(&bp.s_list); return 0; } static void __exit readlog_exit(void) { debugfs_remove(dbg_file); debugfs_remove(dbg_dir); sys_call_table[__NR_open] = (void *) open; sys_call_table[__NR_read] = (void *) read; printk(KERN_INFO "sys_call_table restored\n"); } module_init(readlog_init); module_exit(readlog_exit);