#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 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 , OpenVZ, SWsoft Inc. * (C) 2007 Sukadev Bhattiprolu , 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);