commented early_printk patch because of rejects.
[linux-flexiantxendom0-3.2.10.git] / security / selinux / selinuxfs.c
1 #include <linux/config.h>
2 #include <linux/kernel.h>
3 #include <linux/slab.h>
4 #include <linux/vmalloc.h>
5 #include <linux/fs.h>
6 #include <linux/init.h>
7 #include <linux/string.h>
8 #include <linux/security.h>
9 #include <asm/uaccess.h>
10
11 /* selinuxfs pseudo filesystem for exporting the security policy API.
12    Based on the proc code and the fs/nfsd/nfsctl.c code. */
13
14 #include "flask.h"
15 #include "avc.h"
16 #include "avc_ss.h"
17 #include "security.h"
18 #include "objsec.h"
19
20 /* Check whether a task is allowed to use a security operation. */
21 int task_has_security(struct task_struct *tsk,
22                       u32 perms)
23 {
24         struct task_security_struct *tsec;
25
26         tsec = tsk->security;
27
28         return avc_has_perm(tsec->sid, SECINITSID_SECURITY,
29                             SECCLASS_SECURITY, perms, NULL, NULL);
30 }
31
32 enum sel_inos {
33         SEL_ROOT_INO = 2,
34         SEL_LOAD,       /* load policy */
35         SEL_ENFORCE,    /* get or set enforcing status */
36         SEL_CONTEXT,    /* validate context */
37         SEL_ACCESS,     /* compute access decision */
38         SEL_CREATE,     /* compute create labeling decision */
39         SEL_RELABEL,    /* compute relabeling decision */
40         SEL_USER        /* compute reachable user contexts */
41 };
42
43 static ssize_t sel_read_enforce(struct file *filp, char *buf,
44                                 size_t count, loff_t *ppos)
45 {
46         char *page;
47         ssize_t length;
48         ssize_t end;
49
50         if (count < 0 || count > PAGE_SIZE)
51                 return -EINVAL;
52         if (!(page = (char*)__get_free_page(GFP_KERNEL)))
53                 return -ENOMEM;
54         memset(page, 0, PAGE_SIZE);
55
56         length = snprintf(page, PAGE_SIZE, "%d", selinux_enforcing);
57         if (length < 0) {
58                 free_page((unsigned long)page);
59                 return length;
60         }
61
62         if (*ppos >= length) {
63                 free_page((unsigned long)page);
64                 return 0;
65         }
66         if (count + *ppos > length)
67                 count = length - *ppos;
68         end = count + *ppos;
69         if (copy_to_user(buf, (char *) page + *ppos, count)) {
70                 count = -EFAULT;
71                 goto out;
72         }
73         *ppos = end;
74 out:
75         free_page((unsigned long)page);
76         return count;
77 }
78
79 #ifdef CONFIG_SECURITY_SELINUX_DEVELOP
80 static ssize_t sel_write_enforce(struct file * file, const char * buf,
81                                  size_t count, loff_t *ppos)
82
83 {
84         char *page;
85         ssize_t length;
86         int new_value;
87
88         if (count < 0 || count >= PAGE_SIZE)
89                 return -ENOMEM;
90         if (*ppos != 0) {
91                 /* No partial writes. */
92                 return -EINVAL;
93         }
94         page = (char*)__get_free_page(GFP_KERNEL);
95         if (!page)
96                 return -ENOMEM;
97         memset(page, 0, PAGE_SIZE);
98         length = -EFAULT;
99         if (copy_from_user(page, buf, count))
100                 goto out;
101
102         length = -EINVAL;
103         if (sscanf(page, "%d", &new_value) != 1)
104                 goto out;
105
106         if (new_value != selinux_enforcing) {
107                 length = task_has_security(current, SECURITY__SETENFORCE);
108                 if (length)
109                         goto out;
110                 selinux_enforcing = new_value;
111                 if (selinux_enforcing)
112                         avc_ss_reset(0);
113         }
114         length = count;
115 out:
116         free_page((unsigned long) page);
117         return length;
118 }
119 #else
120 #define sel_write_enforce NULL
121 #endif
122
123 static struct file_operations sel_enforce_ops = {
124         .read           = sel_read_enforce,
125         .write          = sel_write_enforce,
126 };
127
128 static ssize_t sel_write_load(struct file * file, const char * buf,
129                               size_t count, loff_t *ppos)
130
131 {
132         ssize_t length;
133         void *data;
134
135         length = task_has_security(current, SECURITY__LOAD_POLICY);
136         if (length)
137                 return length;
138
139         if (*ppos != 0) {
140                 /* No partial writes. */
141                 return -EINVAL;
142         }
143
144         if ((count < 0) || (count > 64 * 1024 * 1024) || (data = vmalloc(count)) == NULL)
145                 return -ENOMEM;
146
147         length = -EFAULT;
148         if (copy_from_user(data, buf, count) != 0)
149                 goto out;
150
151         length = security_load_policy(data, count);
152         if (length)
153                 goto out;
154
155         length = count;
156 out:
157         vfree(data);
158         return length;
159 }
160
161 static struct file_operations sel_load_ops = {
162         .write          = sel_write_load,
163 };
164
165
166 static ssize_t sel_write_context(struct file * file, const char * buf,
167                                  size_t count, loff_t *ppos)
168
169 {
170         char *page;
171         u32 sid;
172         ssize_t length;
173
174         length = task_has_security(current, SECURITY__CHECK_CONTEXT);
175         if (length)
176                 return length;
177
178         if (count < 0 || count >= PAGE_SIZE)
179                 return -ENOMEM;
180         if (*ppos != 0) {
181                 /* No partial writes. */
182                 return -EINVAL;
183         }
184         page = (char*)__get_free_page(GFP_KERNEL);
185         if (!page)
186                 return -ENOMEM;
187         memset(page, 0, PAGE_SIZE);
188         length = -EFAULT;
189         if (copy_from_user(page, buf, count))
190                 goto out;
191
192         length = security_context_to_sid(page, count, &sid);
193         if (length < 0)
194                 goto out;
195
196         length = count;
197 out:
198         free_page((unsigned long) page);
199         return length;
200 }
201
202 static struct file_operations sel_context_ops = {
203         .write          = sel_write_context,
204 };
205
206
207 /*
208  * Remaining nodes use transaction based IO methods like nfsd/nfsctl.c
209  */
210 static ssize_t sel_write_access(struct file * file, char *buf, size_t size);
211 static ssize_t sel_write_create(struct file * file, char *buf, size_t size);
212 static ssize_t sel_write_relabel(struct file * file, char *buf, size_t size);
213 static ssize_t sel_write_user(struct file * file, char *buf, size_t size);
214
215 static ssize_t (*write_op[])(struct file *, char *, size_t) = {
216         [SEL_ACCESS] = sel_write_access,
217         [SEL_CREATE] = sel_write_create,
218         [SEL_RELABEL] = sel_write_relabel,
219         [SEL_USER] = sel_write_user,
220 };
221
222 /* an argresp is stored in an allocated page and holds the
223  * size of the argument or response, along with its content
224  */
225 struct argresp {
226         ssize_t size;
227         char data[0];
228 };
229
230 #define PAYLOAD_SIZE (PAGE_SIZE - sizeof(struct argresp))
231
232 /*
233  * transaction based IO methods.
234  * The file expects a single write which triggers the transaction, and then
235  * possibly a read which collects the result - which is stored in a
236  * file-local buffer.
237  */
238 static ssize_t TA_write(struct file *file, const char *buf, size_t size, loff_t *pos)
239 {
240         ino_t ino =  file->f_dentry->d_inode->i_ino;
241         struct argresp *ar;
242         ssize_t rv = 0;
243
244         if (ino >= sizeof(write_op)/sizeof(write_op[0]) || !write_op[ino])
245                 return -EINVAL;
246         if (file->private_data)
247                 return -EINVAL; /* only one write allowed per open */
248         if (size > PAYLOAD_SIZE - 1) /* allow one byte for null terminator */
249                 return -EFBIG;
250
251         ar = kmalloc(PAGE_SIZE, GFP_KERNEL);
252         if (!ar)
253                 return -ENOMEM;
254         memset(ar, 0, PAGE_SIZE); /* clear buffer, particularly last byte */
255         ar->size = 0;
256         down(&file->f_dentry->d_inode->i_sem);
257         if (file->private_data)
258                 rv = -EINVAL;
259         else
260                 file->private_data = ar;
261         up(&file->f_dentry->d_inode->i_sem);
262         if (rv) {
263                 kfree(ar);
264                 return rv;
265         }
266         if (copy_from_user(ar->data, buf, size))
267                 return -EFAULT;
268
269         rv =  write_op[ino](file, ar->data, size);
270         if (rv>0) {
271                 ar->size = rv;
272                 rv = size;
273         }
274         return rv;
275 }
276
277 static ssize_t TA_read(struct file *file, char *buf, size_t size, loff_t *pos)
278 {
279         struct argresp *ar;
280         ssize_t rv = 0;
281
282         if (file->private_data == NULL)
283                 rv = TA_write(file, buf, 0, pos);
284         if (rv < 0)
285                 return rv;
286
287         ar = file->private_data;
288         if (!ar)
289                 return 0;
290         if (*pos >= ar->size)
291                 return 0;
292         if (*pos + size > ar->size)
293                 size = ar->size - *pos;
294         if (copy_to_user(buf, ar->data + *pos, size))
295                 return -EFAULT;
296         *pos += size;
297         return size;
298 }
299
300 static int TA_open(struct inode *inode, struct file *file)
301 {
302         file->private_data = NULL;
303         return 0;
304 }
305
306 static int TA_release(struct inode *inode, struct file *file)
307 {
308         void *p = file->private_data;
309         file->private_data = NULL;
310         kfree(p);
311         return 0;
312 }
313
314 static struct file_operations transaction_ops = {
315         .write          = TA_write,
316         .read           = TA_read,
317         .open           = TA_open,
318         .release        = TA_release,
319 };
320
321 /*
322  * payload - write methods
323  * If the method has a response, the response should be put in buf,
324  * and the length returned.  Otherwise return 0 or and -error.
325  */
326
327 static ssize_t sel_write_access(struct file * file, char *buf, size_t size)
328 {
329         char *scon, *tcon;
330         u32 ssid, tsid;
331         u16 tclass;
332         u32 req;
333         struct av_decision avd;
334         ssize_t length;
335
336         length = task_has_security(current, SECURITY__COMPUTE_AV);
337         if (length)
338                 return length;
339
340         length = -ENOMEM;
341         scon = kmalloc(size+1, GFP_KERNEL);
342         if (!scon)
343                 return length;
344         memset(scon, 0, size+1);
345
346         tcon = kmalloc(size+1, GFP_KERNEL);
347         if (!tcon)
348                 goto out;
349         memset(tcon, 0, size+1);
350
351         length = -EINVAL;
352         if (sscanf(buf, "%s %s %hu %x", scon, tcon, &tclass, &req) != 4)
353                 goto out2;
354
355         length = security_context_to_sid(scon, strlen(scon)+1, &ssid);
356         if (length < 0)
357                 goto out2;
358         length = security_context_to_sid(tcon, strlen(tcon)+1, &tsid);
359         if (length < 0)
360                 goto out2;
361
362         length = security_compute_av(ssid, tsid, tclass, req, &avd);
363         if (length < 0)
364                 goto out2;
365
366         length = snprintf(buf, PAYLOAD_SIZE, "%x %x %x %x %u",
367                           avd.allowed, avd.decided,
368                           avd.auditallow, avd.auditdeny,
369                           avd.seqno);
370 out2:
371         kfree(tcon);
372 out:
373         kfree(scon);
374         return length;
375 }
376
377 static ssize_t sel_write_create(struct file * file, char *buf, size_t size)
378 {
379         char *scon, *tcon;
380         u32 ssid, tsid, newsid;
381         u16 tclass;
382         ssize_t length;
383         char *newcon;
384         u32 len;
385
386         length = task_has_security(current, SECURITY__COMPUTE_CREATE);
387         if (length)
388                 return length;
389
390         length = -ENOMEM;
391         scon = kmalloc(size+1, GFP_KERNEL);
392         if (!scon)
393                 return length;
394         memset(scon, 0, size+1);
395
396         tcon = kmalloc(size+1, GFP_KERNEL);
397         if (!tcon)
398                 goto out;
399         memset(tcon, 0, size+1);
400
401         length = -EINVAL;
402         if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
403                 goto out2;
404
405         length = security_context_to_sid(scon, strlen(scon)+1, &ssid);
406         if (length < 0)
407                 goto out2;
408         length = security_context_to_sid(tcon, strlen(tcon)+1, &tsid);
409         if (length < 0)
410                 goto out2;
411
412         length = security_transition_sid(ssid, tsid, tclass, &newsid);
413         if (length < 0)
414                 goto out2;
415
416         length = security_sid_to_context(newsid, &newcon, &len);
417         if (length < 0)
418                 goto out2;
419
420         if (len > PAYLOAD_SIZE) {
421                 printk(KERN_ERR "%s:  context size (%u) exceeds payload "
422                        "max\n", __FUNCTION__, len);
423                 length = -ERANGE;
424                 goto out3;
425         }
426
427         memcpy(buf, newcon, len);
428         length = len;
429 out3:
430         kfree(newcon);
431 out2:
432         kfree(tcon);
433 out:
434         kfree(scon);
435         return length;
436 }
437
438 static ssize_t sel_write_relabel(struct file * file, char *buf, size_t size)
439 {
440         char *scon, *tcon;
441         u32 ssid, tsid, newsid;
442         u16 tclass;
443         ssize_t length;
444         char *newcon;
445         u32 len;
446
447         length = task_has_security(current, SECURITY__COMPUTE_RELABEL);
448         if (length)
449                 return length;
450
451         length = -ENOMEM;
452         scon = kmalloc(size+1, GFP_KERNEL);
453         if (!scon)
454                 return length;
455         memset(scon, 0, size+1);
456
457         tcon = kmalloc(size+1, GFP_KERNEL);
458         if (!tcon)
459                 goto out;
460         memset(tcon, 0, size+1);
461
462         length = -EINVAL;
463         if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
464                 goto out2;
465
466         length = security_context_to_sid(scon, strlen(scon)+1, &ssid);
467         if (length < 0)
468                 goto out2;
469         length = security_context_to_sid(tcon, strlen(tcon)+1, &tsid);
470         if (length < 0)
471                 goto out2;
472
473         length = security_change_sid(ssid, tsid, tclass, &newsid);
474         if (length < 0)
475                 goto out2;
476
477         length = security_sid_to_context(newsid, &newcon, &len);
478         if (length < 0)
479                 goto out2;
480
481         if (len > PAYLOAD_SIZE) {
482                 length = -ERANGE;
483                 goto out3;
484         }
485
486         memcpy(buf, newcon, len);
487         length = len;
488 out3:
489         kfree(newcon);
490 out2:
491         kfree(tcon);
492 out:
493         kfree(scon);
494         return length;
495 }
496
497 static ssize_t sel_write_user(struct file * file, char *buf, size_t size)
498 {
499         char *con, *user, *ptr;
500         u32 sid, *sids;
501         ssize_t length;
502         char *newcon;
503         int i, rc;
504         u32 len, nsids;
505
506         length = task_has_security(current, SECURITY__COMPUTE_USER);
507         if (length)
508                 return length;
509
510         length = -ENOMEM;
511         con = kmalloc(size+1, GFP_KERNEL);
512         if (!con)
513                 return length;
514         memset(con, 0, size+1);
515
516         user = kmalloc(size+1, GFP_KERNEL);
517         if (!user)
518                 goto out;
519         memset(user, 0, size+1);
520
521         length = -EINVAL;
522         if (sscanf(buf, "%s %s", con, user) != 2)
523                 goto out2;
524
525         length = security_context_to_sid(con, strlen(con)+1, &sid);
526         if (length < 0)
527                 goto out2;
528
529         length = security_get_user_sids(sid, user, &sids, &nsids);
530         if (length < 0)
531                 goto out2;
532
533         length = sprintf(buf, "%u", nsids) + 1;
534         ptr = buf + length;
535         for (i = 0; i < nsids; i++) {
536                 rc = security_sid_to_context(sids[i], &newcon, &len);
537                 if (rc) {
538                         length = rc;
539                         goto out3;
540                 }
541                 if ((length + len) >= PAYLOAD_SIZE) {
542                         kfree(newcon);
543                         length = -ERANGE;
544                         goto out3;
545                 }
546                 memcpy(ptr, newcon, len);
547                 kfree(newcon);
548                 ptr += len;
549                 length += len;
550         }
551 out3:
552         kfree(sids);
553 out2:
554         kfree(user);
555 out:
556         kfree(con);
557         return length;
558 }
559
560
561 static int sel_fill_super(struct super_block * sb, void * data, int silent)
562 {
563         static struct tree_descr selinux_files[] = {
564                 [SEL_LOAD] = {"load", &sel_load_ops, S_IRUSR|S_IWUSR},
565                 [SEL_ENFORCE] = {"enforce", &sel_enforce_ops, S_IRUSR|S_IWUSR},
566                 [SEL_CONTEXT] = {"context", &sel_context_ops, S_IRUGO|S_IWUGO},
567                 [SEL_ACCESS] = {"access", &transaction_ops, S_IRUGO|S_IWUGO},
568                 [SEL_CREATE] = {"create", &transaction_ops, S_IRUGO|S_IWUGO},
569                 [SEL_RELABEL] = {"relabel", &transaction_ops, S_IRUGO|S_IWUGO},
570                 [SEL_USER] = {"user", &transaction_ops, S_IRUGO|S_IWUGO},
571                 /* last one */ {""}
572         };
573         return simple_fill_super(sb, SELINUX_MAGIC, selinux_files);
574 }
575
576 static struct super_block *sel_get_sb(struct file_system_type *fs_type,
577                                       int flags, const char *dev_name, void *data)
578 {
579         return get_sb_single(fs_type, flags, data, sel_fill_super);
580 }
581
582 static struct file_system_type sel_fs_type = {
583         .name           = "selinuxfs",
584         .get_sb         = sel_get_sb,
585         .kill_sb        = kill_litter_super,
586 };
587
588 static int __init init_sel_fs(void)
589 {
590         return register_filesystem(&sel_fs_type);
591 }
592
593 __initcall(init_sel_fs);