#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); 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);