summaryrefslogtreecommitdiffstats
path: root/trunk/kmod/readlog.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/kmod/readlog.c')
-rw-r--r--trunk/kmod/readlog.c230
1 files changed, 230 insertions, 0 deletions
diff --git a/trunk/kmod/readlog.c b/trunk/kmod/readlog.c
new file mode 100644
index 0000000..8a1c5ad
--- /dev/null
+++ b/trunk/kmod/readlog.c
@@ -0,0 +1,230 @@
+#include <linux/init.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/syscalls.h>
+#include <linux/time.h>
+
+#include <asm/unistd.h>
+
+#include <asm/current.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Olivier Blin <blino@mandriva.com>");
+
+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 : "<no dentry>"
+ );
+
+ 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);