Pid and mnt namespace support in lxcsu
Sapan Bhatia [Wed, 5 Sep 2012 11:00:45 +0000 (07:00 -0400)]
mntsu.c [new file with mode: 0644]
pidsu.c [new file with mode: 0644]

diff --git a/mntsu.c b/mntsu.c
new file mode 100644 (file)
index 0000000..34cfb56
--- /dev/null
+++ b/mntsu.c
@@ -0,0 +1,201 @@
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs_struct.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/reboot.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+#include <asm/uaccess.h>
+#include <linux/sysrq.h>
+#include <linux/timer.h>
+#include <linux/time.h>
+#include <linux/lglock.h>
+#include <linux/init.h>
+#include <linux/idr.h>
+#include <linux/namei.h>
+#include <linux/bitops.h>
+#include <linux/mnt_namespace.h>
+#include <linux/path.h>
+#include <linux/dcache.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/sched.h>
+#include <linux/seq_file.h>
+#include <linux/file.h>
+#include <linux/kprobes.h>
+#include <linux/kallsyms.h>
+#include <linux/nsproxy.h>
+#include "mount.h"
+
+#define VERSION_STR "0.0.1"
+
+#ifndef CONFIG_X86_64
+#error "This code does not support your architecture"
+#endif
+
+MODULE_AUTHOR("Sapan Bhatia <sapanb@cs.princeton.edu>");
+MODULE_DESCRIPTION("Hack to enable mount namespace switching via setns. Based on a patch by Eric Biederman.");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(VERSION_STR);
+
+struct proc_dir_entry *proc_entry;
+
+static void *mntns_get(struct task_struct *task)
+{
+       struct mnt_namespace *ns;
+       rcu_read_lock();
+       ns = task->nsproxy->mnt_ns;
+       atomic_inc(&ns->count);
+       rcu_read_unlock();
+       return ns;
+}
+
+void (*put_mnt_ns2)(struct mnt_namespace *ns);
+
+static void mntns_put(void *ns)
+{
+       (*put_mnt_ns2)(ns);
+}
+
+static int mntns_install(struct nsproxy *nsproxy, void *ns)
+{
+       struct fs_struct *fs = current->fs;
+       struct mnt_namespace *mnt_ns = ns;
+       struct path root;
+
+       if (fs->users != 1)
+               return -EINVAL;
+
+       atomic_inc(&mnt_ns->count);
+       (*put_mnt_ns2)(nsproxy->mnt_ns);
+       nsproxy->mnt_ns = mnt_ns;
+
+       root.mnt    = &mnt_ns->root->mnt;
+       root.dentry = mnt_ns->root->mnt.mnt_root;
+       path_get(&root);
+       while(d_mountpoint(root.dentry) && follow_down(&root))
+               ;
+
+       path_get(&root);
+       path_get(&root);
+       path_put(&fs->root);
+       path_put(&fs->pwd);
+       fs->root = root;
+       fs->pwd  = root;
+       path_put(&root);
+
+       return 0;
+}
+
+const struct proc_ns_operations mntns_operations = {
+       .name           = "mnt_ns",
+       .get            = mntns_get,
+       .put            = mntns_put,
+       .install        = mntns_install,
+};
+
+void (*free_nsproxy2)(struct nsproxy *ns);
+
+struct nsproxy * (*create_new_namespaces)(unsigned long flags,
+                       struct task_struct *tsk, struct fs_struct *new_fs);
+
+void (*switch_task_namespaces2)(struct task_struct *p, struct nsproxy *new);
+
+static int setns(struct task_struct *reftask) {
+        const struct proc_ns_operations *ops;
+        struct task_struct *tsk = current;
+        struct nsproxy *new_nsproxy;
+        int err;
+
+        if (!capable(CAP_SYS_ADMIN))
+            return -EPERM;
+
+        err = -EINVAL;
+        ops = &mntns_operations;
+
+        new_nsproxy = (*create_new_namespaces)(0, tsk, tsk->fs);
+        if (IS_ERR(new_nsproxy)) {
+            err = PTR_ERR(new_nsproxy);
+            goto out;
+        }
+
+        err = ops->install(new_nsproxy, reftask->nsproxy->mnt_ns);
+        if (err) {
+            (*free_nsproxy2)(new_nsproxy);
+            goto out;
+        }
+        (*switch_task_namespaces2)(tsk, new_nsproxy);
+        return 0;
+out:
+        return err;
+
+}
+
+static void __exit lxcsu_exit(void)
+{
+       remove_proc_entry("lxcsu",NULL);
+       printk("Procprotect: Stopped lxcsu.\n");
+}
+
+int lxcsu_write(struct file *file, const char *buffer, unsigned long count, void *data) {
+       char pidname[PATH_MAX];
+    int pid;
+    struct pid *p;
+    char **s;
+    struct task_struct *task;
+
+       if (current->nsproxy->mnt_ns!=init_task.nsproxy->mnt_ns)
+               return -EPERM;
+
+       if (copy_from_user(pidname, buffer, count)) {
+               return -EFAULT;
+       }
+       if (count && (pidname[count-1]==10 || pidname[count-1]==13)) {
+               pidname[count-1]='\0';
+       }
+       else
+               pidname[count]='\0';
+
+    pid = simple_strtol(pidname,s,10);
+    p = find_vpid(pid);
+    task = get_pid_task(p,PIDTYPE_PID);
+    if (task) {
+        setns(task);
+    }
+    else {
+        printk(KERN_CRIT "Task %d not found",pid);
+    }
+
+       return count;
+}
+
+
+static int __init lxcsu_init(void)
+{
+               int ret=0;
+        printk("Mntsu: starting lxcsu version %s.\n",
+              VERSION_STR);
+
+        
+        free_nsproxy2 = kallsyms_lookup_name("free_nsproxy");
+        printk(KERN_CRIT "free_nsproxy = %x",free_nsproxy2);
+
+        switch_task_namespaces2 = kallsyms_lookup_name("switch_task_namespaces");
+        printk(KERN_CRIT "switch_task_namespaces = %x",switch_task_namespaces2);
+
+        create_new_namespaces = kallsyms_lookup_name("create_new_namespaces");
+        printk(KERN_CRIT "create_new_namespaces = %x",create_new_namespaces);
+
+        put_mnt_ns2 = kallsyms_lookup_name("put_mnt_ns");
+        printk(KERN_CRIT "Put mnt ns = %x",put_mnt_ns2);
+
+        proc_entry = create_proc_entry("lxcsu", 0644, NULL);
+           proc_entry->write_proc = lxcsu_write;
+        return ret;
+}
+
+module_init(lxcsu_init);
+module_exit(lxcsu_exit);
diff --git a/pidsu.c b/pidsu.c
new file mode 100644 (file)
index 0000000..fa09133
--- /dev/null
+++ b/pidsu.c
@@ -0,0 +1,205 @@
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs_struct.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/reboot.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+#include <asm/uaccess.h>
+#include <linux/sysrq.h>
+#include <linux/timer.h>
+#include <linux/time.h>
+#include <linux/lglock.h>
+#include <linux/init.h>
+#include <linux/idr.h>
+#include <linux/namei.h>
+#include <linux/bitops.h>
+#include <linux/pid_namespace.h>
+#include <linux/path.h>
+#include <linux/dcache.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/sched.h>
+#include <linux/seq_file.h>
+#include <linux/file.h>
+#include <linux/kprobes.h>
+#include <linux/kallsyms.h>
+#include <linux/nsproxy.h>
+#include "mount.h"
+
+#define VERSION_STR "0.0.1"
+
+#ifndef CONFIG_X86_64
+#error "This code does not support your architecture"
+#endif
+
+MODULE_AUTHOR("Sapan Bhatia <sapanb@cs.princeton.edu>");
+MODULE_DESCRIPTION("Hack to enable pid namespace switching via setns. Based on a patch by Eric Biederman.");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(VERSION_STR);
+
+struct proc_dir_entry *proc_entry;
+
+/*
+ * Pid namespaces
+ *
+ * Authors:
+ *    (C) 2007 Pavel Emelyanov <xemul@openvz.org>, OpenVZ, SWsoft Inc.
+ *    (C) 2007 Sukadev Bhattiprolu <sukadev@us.ibm.com>, IBM
+ *     Many thanks to Oleg Nesterov for comments and help
+ *
+ */
+
+#define BITS_PER_PAGE       (PAGE_SIZE*8)
+
+void (*free_nsproxy2)(struct nsproxy *ns);
+struct nsproxy * (*create_new_namespaces)(unsigned long flags,
+                       struct task_struct *tsk, struct fs_struct *new_fs);
+
+void (*switch_task_namespaces2)(struct task_struct *p, struct nsproxy *new);
+void (*free_pid_ns2)(struct kref *kref);
+
+
+struct pid_cache {
+    int nr_ids;
+    char name[16];
+    struct kmem_cache *cachep;
+    struct list_head list;
+};
+
+static LIST_HEAD(pid_caches_lh);
+static DEFINE_MUTEX(pid_caches_mutex);
+
+static void *pidns_get(struct task_struct *task)
+{
+    struct pid_namespace *ns;
+
+    rcu_read_lock();
+    ns = get_pid_ns(task_active_pid_ns(task));
+    rcu_read_unlock();
+
+    return ns;
+}
+
+static void pidns_put(void *ns)
+{
+    struct pid_namespace *pidns = ns;
+    if (pidns != &init_pid_ns)
+        kref_put(&pidns->kref, free_pid_ns2);
+}
+
+static int pidns_install(struct nsproxy *nsproxy, void *ns)
+{
+    printk(KERN_CRIT "Entering pid ns");
+    pidns_put(nsproxy->pid_ns);
+    nsproxy->pid_ns = get_pid_ns(ns);
+    return 0;
+}
+
+const struct proc_ns_operations pidns_operations = {
+    .name       = "pid",
+    .type       = CLONE_NEWPID,
+    .get        = pidns_get,
+    .put        = pidns_put,
+    .install    = pidns_install,
+};
+
+static int setns(struct task_struct *reftask) {
+        const struct proc_ns_operations *ops;
+        struct task_struct *tsk = current;
+        struct nsproxy *new_nsproxy;
+        int err;
+
+        if (!capable(CAP_SYS_ADMIN))
+            return -EPERM;
+
+        err = -EINVAL;
+        ops = &pidns_operations;
+
+        new_nsproxy = (*create_new_namespaces)(0, tsk, tsk->fs);
+        if (IS_ERR(new_nsproxy)) {
+            err = PTR_ERR(new_nsproxy);
+            goto out;
+        }
+
+        err = ops->install(new_nsproxy, reftask->nsproxy->pid_ns);
+        if (err) {
+            (*free_nsproxy2)(new_nsproxy);
+            goto out;
+        }
+        (*switch_task_namespaces2)(tsk, new_nsproxy);
+        return 0;
+out:
+        return err;
+
+}
+
+static void __exit pidsu_exit(void)
+{
+       remove_proc_entry("pidsu",NULL);
+       printk("Procprotect: Stopped pidsu.\n");
+}
+
+int pidsu_write(struct file *file, const char *buffer, unsigned long count, void *data) {
+       char pidname[80];
+    int pid;
+    struct pid *p;
+    char **s;
+    struct task_struct *task;
+
+       if (current->nsproxy->pid_ns!=init_task.nsproxy->pid_ns)
+               return -EPERM;
+
+       if (copy_from_user(pidname, buffer, count)) {
+               return -EFAULT;
+       }
+       if (count && (pidname[count-1]==10 || pidname[count-1]==13)) {
+               pidname[count-1]='\0';
+       }
+       else
+               pidname[count]='\0';
+
+    pid = simple_strtol(pidname,s,10);
+    p = find_vpid(pid);
+    task = get_pid_task(p,PIDTYPE_PID);
+    if (task) {
+        setns(task);
+    }
+    else {
+        printk(KERN_CRIT "Task %d not found",pid);
+    }
+
+       return count;
+}
+
+static int __init pidsu_init(void)
+{
+               int ret=0;
+        printk("Mntsu: starting pidsu version %s.\n",
+              VERSION_STR);
+
+        free_pid_ns2 = kallsyms_lookup_name("free_pid_ns");
+        printk(KERN_CRIT "free_pid_ns = %x",free_pid_ns2);
+
+        free_nsproxy2 = kallsyms_lookup_name("free_nsproxy");
+        printk(KERN_CRIT "free_nsproxy = %x",(unsigned int) free_nsproxy2);
+
+        switch_task_namespaces2 = kallsyms_lookup_name("switch_task_namespaces");
+        printk(KERN_CRIT "switch_task_namespaces = %x",(unsigned int) switch_task_namespaces2);
+
+        create_new_namespaces = kallsyms_lookup_name("create_new_namespaces");
+        printk(KERN_CRIT "create_new_namespaces = %x",(unsigned int) create_new_namespaces);
+
+        /*put_pid_ns2 = kallsyms_lookup_name("put_pid_ns");
+        printk(KERN_CRIT "Put pid ns = %x",put_pid_ns2);*/
+
+        proc_entry = create_proc_entry("pidsu", 0644, NULL);
+           proc_entry->write_proc = pidsu_write;
+        return ret;
+}
+
+module_init(pidsu_init);
+module_exit(pidsu_exit);