#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 #include #include #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 "); MODULE_DESCRIPTION("Hack to enable mount namespace switching via setns. Based on a patch by Eric Biederman."); MODULE_LICENSE("GPL"); MODULE_VERSION(VERSION_STR); 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; /* Find the root */ root.mnt = mnt_ns->root; root.dentry = mnt_ns->root->mnt.mnt_root; path_get(&root); while(d_mountpoint(root.dentry) && follow_down(&root)) ; /* Update the pwd and 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 file *(*proc_ns_fget2)(int fd); 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_entry(int fd, int nstype) { if (nstype==666) { const struct proc_ns_operations *ops; struct task_struct *tsk = current; struct nsproxy *new_nsproxy; struct proc_inode *ei; struct file *file; int err; if (!capable(CAP_SYS_ADMIN)) return -EPERM; file = (*proc_ns_fget2)(fd); if (IS_ERR(file)) return PTR_ERR(file); err = -EINVAL; ei = PROC_I(file->f_dentry->d_inode); 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, ei->ns); if (err) { (*free_nsproxy2)(new_nsproxy); goto out; } (*switch_task_namespaces2)(tsk, new_nsproxy); out: fput(file); } jprobe_return(); return 0; } static struct jprobe setns_jprobe = { .entry = (kprobe_opcode_t *) setns_entry }; static void __exit mntsu_exit(void) { unregister_jprobe(&setns_jprobe); printk("Procprotect: Stopped mntsu.\n"); } static int __init mntsu_init(void) { int ret=0; printk("Mntsu: starting mntsu version %s.\n", VERSION_STR); proc_ns_fget2 = kallsyms_lookup_name("proc_ns_fget"); printk(KERN_CRIT "proc_ns_fget = %x",proc_ns_fget2); 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); setns_jprobe.kp.addr = (kprobe_opcode_t *) kallsyms_lookup_name("sys_setns"); if (!setns_jprobe.kp.addr) { printk("Couldn't find %s to plant jprobe\n", "do_execve"); return -1; } if ((ret = register_jprobe(&setns_jprobe)) <0) { printk("register_jprobe failed, returned %d\n", ret); return -1; } return ret; } module_init(mntsu_init); module_exit(mntsu_exit);