From: Sapan Bhatia Date: Tue, 24 Apr 2012 06:50:09 +0000 (-0400) Subject: Procprotect kernel module for protecting /proc in LXC containers X-Git-Tag: procprotect-0.1-1~3 X-Git-Url: http://git.onelab.eu/?p=procprotect.git;a=commitdiff_plain;h=eb602e2ed7a3b723feb4be26f19b333d1ac88462 Procprotect kernel module for protecting /proc in LXC containers --- diff --git a/procprotect.c b/procprotect.c new file mode 100644 index 0000000..d49a41b --- /dev/null +++ b/procprotect.c @@ -0,0 +1,228 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define VERSION_STR "0.0.1" + +#ifndef CONFIG_X86_64 +#error "This code does not support your architecture" +#endif + +static char *aclpath __devinitdata = "procprotect"; +static struct qstr aclqpath; + +module_param(aclpath, charp, 0); +MODULE_PARM_DESC(aclpath, "Root of directory that stores acl tags for /proc files."); + +MODULE_AUTHOR("Sapan Bhatia "); +MODULE_DESCRIPTION("Lightweight ACLs for /proc."); +MODULE_LICENSE("GPL"); +MODULE_VERSION(VERSION_STR); + +struct procprotect_ctx { + struct inode **inode; +}; + +struct acl_entry { + unsigned int ino; + struct hlist_node hlist; +}; + +#define HASH_SIZE (1<<16) + +struct hlist_head procprotect_hash[HASH_SIZE]; + +struct proc_dir_entry *proc_entry; + +/* + Entry point of intercepted call. We need to do two things here: + - Decide if we need the heavier return hook to be called + - Save the first argument, which is in a register, for consideration in the return hook +*/ +static int do_lookup_entry(struct kretprobe_instance *ri, struct pt_regs *regs) { + int ret = -1; + struct procprotect_ctx *ctx; + struct nameidata *nd = (struct nameidata *) regs->di; + struct qstr *q = (struct qstr *) regs->si; + struct dentry *parent = nd->path.dentry; + struct inode *pinode = parent->d_inode; + + if (pinode->i_sb->s_magic == PROC_SUPER_MAGIC) { + ctx = (struct procprotect_ctx *) ri->data; + ctx->inode = (struct inode **) regs->cx; + ret = 0; + } + + return ret; +} + +static int run_acl(unsigned long ino) { + struct hlist_node *n; + struct acl_entry *entry; + hlist_for_each_entry_rcu(entry, + n, &procprotect_hash[ino & (HASH_SIZE-1)], + hlist) { + if (entry->ino==ino) { + return 0; + } + } + return 1; +} + +/* The entry hook ensures that the return hook is only called for +accesses to /proc */ + +static int do_lookup_ret(struct kretprobe_instance *ri, struct pt_regs *regs) +{ + struct procprotect_ctx *ctx = (struct procprotect_ctx *) ri->data; + int ret = regs->ax; + + if (ret==0) { + /* The kernel is going to honor the request. Here's where we step in */ + struct inode *inode = *(ctx->inode); + //printk(KERN_CRIT "Checking inode %x number %u",inode,inode->i_ino); + if (!run_acl(inode->i_ino)) { + if (current->nsproxy->mnt_ns!=init_task.nsproxy->mnt_ns) + regs->ax = -EPERM; + } + } + + return 0; +} + +static struct kretprobe proc_probe = { + .entry_handler = (kprobe_opcode_t *) do_lookup_entry, + .handler = (kprobe_opcode_t *) do_lookup_ret, + .maxactive = 20, + .data_size = sizeof(struct procprotect_ctx) +}; + +static void add_entry(char *pathname) { + struct path path; + if (kern_path(pathname, 0, &path)) { + printk(KERN_CRIT "Path lookup failed for %s",pathname); + } + else { + unsigned int ino = path.dentry->d_inode->i_ino; + struct acl_entry *entry; + entry = kmalloc(GFP_KERNEL, sizeof(struct acl_entry)); + entry->ino = ino; + + if (!entry) { + printk(KERN_CRIT "Could not allocate memory for %s",pathname); + } + else { + if (run_acl(ino)) { + hlist_add_head_rcu(&entry->hlist,&procprotect_hash[ino&(HASH_SIZE-1)]); + printk(KERN_CRIT "Added inode %u",ino); + } + else { + printk(KERN_CRIT "Did not add inode %u, already in list", ino); + } + } + } +} + + +static void __exit procprotect_exit(void) +{ + unregister_kretprobe(&proc_probe); + struct hlist_node *n; + struct acl_entry *entry; + int i; + + for (i=0;insproxy->mnt_ns!=init_task.nsproxy->mnt_ns) + return -EPERM; + + if (copy_from_user(pathname, buffer, count)) { + return -EFAULT; + } + if (count && (pathname[count-1]==10 || pathname[count-1]==13)) { + pathname[count-1]='\0'; + } + else + pathname[count]='\0'; + add_entry(pathname); + printk(KERN_CRIT "Length of buffer=%d",strlen(pathname)); + return count; +} + +static int __init procprotect_init(void) +{ + printk("Procprotect: starting procprotect version %s with ACLs at path %s.\n", + VERSION_STR, aclpath); + int ret; + int i; + + for(i=0;iwrite_proc = procfile_write; + return ret; +} + + + +module_init(procprotect_init); +module_exit(procprotect_exit);