Removed debug message
[lxc-kernelspace-obsolete.git] / pidsu.c
1 #include <linux/module.h>
2 #include <linux/moduleparam.h>
3 #include <linux/types.h>
4 #include <linux/kernel.h>
5 #include <linux/fs_struct.h>
6 #include <linux/fs.h>
7 #include <linux/mm.h>
8 #include <linux/reboot.h>
9 #include <linux/delay.h>
10 #include <linux/proc_fs.h>
11 #include <asm/uaccess.h>
12 #include <linux/sysrq.h>
13 #include <linux/timer.h>
14 #include <linux/time.h>
15 #include <linux/lglock.h>
16 #include <linux/init.h>
17 #include <linux/idr.h>
18 #include <linux/namei.h>
19 #include <linux/bitops.h>
20 #include <linux/pid_namespace.h>
21 #include <linux/path.h>
22 #include <linux/dcache.h>
23 #include <linux/spinlock.h>
24 #include <linux/completion.h>
25 #include <linux/sched.h>
26 #include <linux/seq_file.h>
27 #include <linux/file.h>
28 #include <linux/kprobes.h>
29 #include <linux/kallsyms.h>
30 #include <linux/nsproxy.h>
31 #include "mount.h"
32
33 #define VERSION_STR "0.0.1"
34
35 #ifndef CONFIG_X86_64
36 #error "This code does not support your architecture"
37 #endif
38
39 MODULE_AUTHOR("Sapan Bhatia <sapanb@cs.princeton.edu>");
40 MODULE_DESCRIPTION("Hack to enable pid namespace switching via setns. Based on a patch by Eric Biederman.");
41 MODULE_LICENSE("GPL");
42 MODULE_VERSION(VERSION_STR);
43
44 struct proc_dir_entry *proc_entry;
45
46 /*
47  * Pid namespaces
48  *
49  * Authors:
50  *    (C) 2007 Pavel Emelyanov <xemul@openvz.org>, OpenVZ, SWsoft Inc.
51  *    (C) 2007 Sukadev Bhattiprolu <sukadev@us.ibm.com>, IBM
52  *     Many thanks to Oleg Nesterov for comments and help
53  *
54  */
55
56 #define BITS_PER_PAGE       (PAGE_SIZE*8)
57
58 void (*free_nsproxy2)(struct nsproxy *ns);
59 struct nsproxy * (*create_new_namespaces)(unsigned long flags,
60                         struct task_struct *tsk, struct fs_struct *new_fs);
61
62 void (*switch_task_namespaces2)(struct task_struct *p, struct nsproxy *new);
63 void (*free_pid_ns2)(struct kref *kref);
64
65
66 struct pid_cache {
67     int nr_ids;
68     char name[16];
69     struct kmem_cache *cachep;
70     struct list_head list;
71 };
72
73 static LIST_HEAD(pid_caches_lh);
74 static DEFINE_MUTEX(pid_caches_mutex);
75
76 static void *pidns_get(struct task_struct *task)
77 {
78     struct pid_namespace *ns;
79
80     rcu_read_lock();
81     ns = get_pid_ns(task_active_pid_ns(task));
82     rcu_read_unlock();
83
84     return ns;
85 }
86
87 static void pidns_put(void *ns)
88 {
89     struct pid_namespace *pidns = ns;
90     if (pidns != &init_pid_ns)
91         kref_put(&pidns->kref, free_pid_ns2);
92 }
93
94 static int pidns_install(struct nsproxy *nsproxy, void *ns)
95 {
96     //printk(KERN_CRIT "Entering pid ns");
97     pidns_put(nsproxy->pid_ns);
98     nsproxy->pid_ns = get_pid_ns(ns);
99     return 0;
100 }
101
102 const struct proc_ns_operations pidns_operations = {
103     .name       = "pid",
104     .type       = CLONE_NEWPID,
105     .get        = pidns_get,
106     .put        = pidns_put,
107     .install    = pidns_install,
108 };
109
110 static int setns(struct task_struct *reftask) {
111         const struct proc_ns_operations *ops;
112         struct task_struct *tsk = current;
113         struct nsproxy *new_nsproxy;
114         int err;
115
116         if (!capable(CAP_SYS_ADMIN))
117             return -EPERM;
118
119         err = -EINVAL;
120         ops = &pidns_operations;
121
122         new_nsproxy = (*create_new_namespaces)(0, tsk, tsk->fs);
123         if (IS_ERR(new_nsproxy)) {
124             err = PTR_ERR(new_nsproxy);
125             goto out;
126         }
127
128         err = ops->install(new_nsproxy, reftask->nsproxy->pid_ns);
129         if (err) {
130             (*free_nsproxy2)(new_nsproxy);
131             goto out;
132         }
133         (*switch_task_namespaces2)(tsk, new_nsproxy);
134         return 0;
135 out:
136         return err;
137
138 }
139
140 static void __exit pidsu_exit(void)
141 {
142         remove_proc_entry("pidsu",NULL);
143         printk("Procprotect: Stopped pidsu.\n");
144 }
145
146 int pidsu_write(struct file *file, const char *buffer, unsigned long count, void *data) {
147         char pidname[80];
148     int pid;
149     struct pid *p;
150     char **s;
151     struct task_struct *task;
152
153         if (current->nsproxy->pid_ns!=init_task.nsproxy->pid_ns)
154                 return -EPERM;
155
156         if (copy_from_user(pidname, buffer, count)) {
157                 return -EFAULT;
158         }
159         if (count && (pidname[count-1]==10 || pidname[count-1]==13)) {
160                 pidname[count-1]='\0';
161         }
162         else
163                 pidname[count]='\0';
164
165     pid = simple_strtol(pidname,s,10);
166     p = find_vpid(pid);
167     task = get_pid_task(p,PIDTYPE_PID);
168     if (task) {
169         setns(task);
170     }
171     else {
172         printk(KERN_CRIT "Task %d not found",pid);
173     }
174
175         return count;
176 }
177
178 static int __init pidsu_init(void)
179 {
180                 int ret=0;
181         printk("Mntsu: starting pidsu version %s.\n",
182                VERSION_STR);
183
184         free_pid_ns2 = kallsyms_lookup_name("free_pid_ns");
185         printk(KERN_CRIT "free_pid_ns = %x",free_pid_ns2);
186
187         free_nsproxy2 = kallsyms_lookup_name("free_nsproxy");
188         printk(KERN_CRIT "free_nsproxy = %x",(unsigned int) free_nsproxy2);
189
190         switch_task_namespaces2 = kallsyms_lookup_name("switch_task_namespaces");
191         printk(KERN_CRIT "switch_task_namespaces = %x",(unsigned int) switch_task_namespaces2);
192
193         create_new_namespaces = kallsyms_lookup_name("create_new_namespaces");
194         printk(KERN_CRIT "create_new_namespaces = %x",(unsigned int) create_new_namespaces);
195
196         /*put_pid_ns2 = kallsyms_lookup_name("put_pid_ns");
197         printk(KERN_CRIT "Put pid ns = %x",put_pid_ns2);*/
198
199         proc_entry = create_proc_entry("pidsu", 0644, NULL);
200             proc_entry->write_proc = pidsu_write;
201         return ret;
202 }
203
204 module_init(pidsu_init);
205 module_exit(pidsu_exit);