Blame view

security/selinux/selinuxfs.c 43 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
  /* Updated: Karl MacMillan <kmacmillan@tresys.com>
   *
1872981b5   Eric Paris   SELinux: cleanup ...
3
   *	Added conditional policy language extensions
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
   *
82c21bfab   Paul Moore   doc: Update the e...
5
   *  Updated: Hewlett-Packard <paul@paul-moore.com>
3bb56b25d   Paul Moore   SELinux: Add a ca...
6
   *
1872981b5   Eric Paris   SELinux: cleanup ...
7
   *	Added support for the policy capability bitmap
3bb56b25d   Paul Moore   SELinux: Add a ca...
8
9
   *
   * Copyright (C) 2007 Hewlett-Packard Development Company, L.P.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
11
12
   * Copyright (C) 2003 - 2004 Tresys Technology, LLC
   * Copyright (C) 2004 Red Hat, Inc., James Morris <jmorris@redhat.com>
   *	This program is free software; you can redistribute it and/or modify
1872981b5   Eric Paris   SELinux: cleanup ...
13
   *	it under the terms of the GNU General Public License as published by
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
15
   *	the Free Software Foundation, version 2.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
17
18
19
20
  #include <linux/kernel.h>
  #include <linux/pagemap.h>
  #include <linux/slab.h>
  #include <linux/vmalloc.h>
  #include <linux/fs.h>
bb0030797   Ingo Molnar   [PATCH] sem2mutex...
21
  #include <linux/mutex.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
23
24
25
26
27
  #include <linux/init.h>
  #include <linux/string.h>
  #include <linux/security.h>
  #include <linux/major.h>
  #include <linux/seq_file.h>
  #include <linux/percpu.h>
af601e462   Steve Grubb   [PATCH] SE Linux ...
28
  #include <linux/audit.h>
f52697107   Eric Paris   SELinux: keep the...
29
  #include <linux/uaccess.h>
7a627e3b9   Greg Kroah-Hartman   SELINUX: add /sys...
30
  #include <linux/kobject.h>
0f7e4c33e   Kohei Kaigai   selinux: fix case...
31
  #include <linux/ctype.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
33
34
35
36
37
38
39
40
41
  
  /* selinuxfs pseudo filesystem for exporting the security policy API.
     Based on the proc code and the fs/nfsd/nfsctl.c code. */
  
  #include "flask.h"
  #include "avc.h"
  #include "avc_ss.h"
  #include "security.h"
  #include "objsec.h"
  #include "conditional.h"
3bb56b25d   Paul Moore   SELinux: Add a ca...
42
43
  /* Policy capability filenames */
  static char *policycap_names[] = {
b0c636b99   Eric Paris   SELinux: create n...
44
  	"network_peer_controls",
2be4d74f2   Chris PeBenito   Add SELinux polic...
45
46
47
  	"open_perms",
  	"redhat1",
  	"always_check_network"
3bb56b25d   Paul Moore   SELinux: Add a ca...
48
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
50
51
52
  unsigned int selinux_checkreqprot = CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE;
  
  static int __init checkreqprot_setup(char *str)
  {
f52697107   Eric Paris   SELinux: keep the...
53
  	unsigned long checkreqprot;
29707b206   Jingoo Han   security: replace...
54
  	if (!kstrtoul(str, 0, &checkreqprot))
f52697107   Eric Paris   SELinux: keep the...
55
  		selinux_checkreqprot = checkreqprot ? 1 : 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
57
58
  	return 1;
  }
  __setup("checkreqprot=", checkreqprot_setup);
bb0030797   Ingo Molnar   [PATCH] sem2mutex...
59
  static DEFINE_MUTEX(sel_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60
61
  
  /* global data for booleans */
1872981b5   Eric Paris   SELinux: cleanup ...
62
63
  static struct dentry *bool_dir;
  static int bool_num;
d313f9483   Stephen Smalley   SELinux: detect d...
64
  static char **bool_pending_names;
1872981b5   Eric Paris   SELinux: cleanup ...
65
  static int *bool_pending_values;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66

e47c8fc58   Christopher J. PeBenito   selinux: add seli...
67
  /* global data for classes */
1872981b5   Eric Paris   SELinux: cleanup ...
68
  static struct dentry *class_dir;
e47c8fc58   Christopher J. PeBenito   selinux: add seli...
69
  static unsigned long last_class_ino;
cee74f47a   Eric Paris   SELinux: allow us...
70
  static char policy_opened;
3bb56b25d   Paul Moore   SELinux: Add a ca...
71
  /* global data for policy capabilities */
1872981b5   Eric Paris   SELinux: cleanup ...
72
  static struct dentry *policycap_dir;
3bb56b25d   Paul Moore   SELinux: Add a ca...
73

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74
75
76
77
  /* Check whether a task is allowed to use a security operation. */
  static int task_has_security(struct task_struct *tsk,
  			     u32 perms)
  {
c69e8d9c0   David Howells   CRED: Use RCU to ...
78
79
80
81
82
83
84
85
  	const struct task_security_struct *tsec;
  	u32 sid = 0;
  
  	rcu_read_lock();
  	tsec = __task_cred(tsk)->security;
  	if (tsec)
  		sid = tsec->sid;
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
87
  	if (!tsec)
  		return -EACCES;
c69e8d9c0   David Howells   CRED: Use RCU to ...
88
  	return avc_has_perm(sid, SECINITSID_SECURITY,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
  			    SECCLASS_SECURITY, perms, NULL);
  }
  
  enum sel_inos {
  	SEL_ROOT_INO = 2,
  	SEL_LOAD,	/* load policy */
  	SEL_ENFORCE,	/* get or set enforcing status */
  	SEL_CONTEXT,	/* validate context */
  	SEL_ACCESS,	/* compute access decision */
  	SEL_CREATE,	/* compute create labeling decision */
  	SEL_RELABEL,	/* compute relabeling decision */
  	SEL_USER,	/* compute reachable user contexts */
  	SEL_POLICYVERS,	/* return policy version for this kernel */
  	SEL_COMMIT_BOOLS, /* commit new boolean values */
  	SEL_MLS,	/* return if MLS policy is enabled */
  	SEL_DISABLE,	/* disable SELinux until next reboot */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
106
  	SEL_MEMBER,	/* compute polyinstantiation membership decision */
  	SEL_CHECKREQPROT, /* check requested protection, not kernel-applied one */
4e5ab4cb8   James Morris   [SECMARK]: Add ne...
107
  	SEL_COMPAT_NET,	/* whether to use old compat network packet controls */
3f12070e2   Eric Paris   SELinux: policy s...
108
109
  	SEL_REJECT_UNKNOWN, /* export unknown reject handling to userspace */
  	SEL_DENY_UNKNOWN, /* export unknown deny handling to userspace */
119041672   KaiGai Kohei   selinux: fast sta...
110
  	SEL_STATUS,	/* export current status using mmap() */
cee74f47a   Eric Paris   SELinux: allow us...
111
  	SEL_POLICY,	/* allow userspace to read the in kernel policy */
6174eafce   James Carter   selinux: explicit...
112
  	SEL_INO_NEXT,	/* The next inode number to use */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113
  };
6174eafce   James Carter   selinux: explicit...
114
  static unsigned long sel_last_ino = SEL_INO_NEXT - 1;
3bb56b25d   Paul Moore   SELinux: Add a ca...
115
116
117
118
119
  #define SEL_INITCON_INO_OFFSET		0x01000000
  #define SEL_BOOL_INO_OFFSET		0x02000000
  #define SEL_CLASS_INO_OFFSET		0x04000000
  #define SEL_POLICYCAP_INO_OFFSET	0x08000000
  #define SEL_INO_MASK			0x00ffffff
f0ee2e467   James Carter   selinux: export i...
120

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
122
123
124
125
126
127
128
129
130
131
132
  #define TMPBUFLEN	12
  static ssize_t sel_read_enforce(struct file *filp, char __user *buf,
  				size_t count, loff_t *ppos)
  {
  	char tmpbuf[TMPBUFLEN];
  	ssize_t length;
  
  	length = scnprintf(tmpbuf, TMPBUFLEN, "%d", selinux_enforcing);
  	return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
  }
  
  #ifdef CONFIG_SECURITY_SELINUX_DEVELOP
1872981b5   Eric Paris   SELinux: cleanup ...
133
  static ssize_t sel_write_enforce(struct file *file, const char __user *buf,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134
135
136
  				 size_t count, loff_t *ppos)
  
  {
b77a493b1   Eric Paris   SELinux: standard...
137
  	char *page = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
138
139
  	ssize_t length;
  	int new_value;
b77a493b1   Eric Paris   SELinux: standard...
140
  	length = -ENOMEM;
bfd51626c   Davi Arnaut   [PATCH] SELinux: ...
141
  	if (count >= PAGE_SIZE)
b77a493b1   Eric Paris   SELinux: standard...
142
143
144
145
146
147
148
149
  		goto out;
  
  	/* No partial writes. */
  	length = EINVAL;
  	if (*ppos != 0)
  		goto out;
  
  	length = -ENOMEM;
1872981b5   Eric Paris   SELinux: cleanup ...
150
  	page = (char *)get_zeroed_page(GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
  	if (!page)
b77a493b1   Eric Paris   SELinux: standard...
152
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
154
155
156
157
158
159
160
161
162
163
164
  	length = -EFAULT;
  	if (copy_from_user(page, buf, count))
  		goto out;
  
  	length = -EINVAL;
  	if (sscanf(page, "%d", &new_value) != 1)
  		goto out;
  
  	if (new_value != selinux_enforcing) {
  		length = task_has_security(current, SECURITY__SETENFORCE);
  		if (length)
  			goto out;
af601e462   Steve Grubb   [PATCH] SE Linux ...
165
  		audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS,
4746ec5b0   Eric Paris   [AUDIT] add sessi...
166
167
  			"enforcing=%d old_enforcing=%d auid=%u ses=%u",
  			new_value, selinux_enforcing,
581abc09c   Eric W. Biederman   userns: Convert s...
168
  			from_kuid(&init_user_ns, audit_get_loginuid(current)),
4746ec5b0   Eric Paris   [AUDIT] add sessi...
169
  			audit_get_sessionid(current));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170
171
172
173
  		selinux_enforcing = new_value;
  		if (selinux_enforcing)
  			avc_ss_reset(0);
  		selnl_notify_setenforce(selinux_enforcing);
119041672   KaiGai Kohei   selinux: fast sta...
174
  		selinux_status_update_setenforce(selinux_enforcing);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
176
177
178
179
180
181
182
183
  	}
  	length = count;
  out:
  	free_page((unsigned long) page);
  	return length;
  }
  #else
  #define sel_write_enforce NULL
  #endif
9c2e08c59   Arjan van de Ven   [PATCH] mark stru...
184
  static const struct file_operations sel_enforce_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
186
  	.read		= sel_read_enforce,
  	.write		= sel_write_enforce,
57a62c231   Arnd Bergmann   selinux: use gene...
187
  	.llseek		= generic_file_llseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188
  };
3f12070e2   Eric Paris   SELinux: policy s...
189
190
191
192
193
  static ssize_t sel_read_handle_unknown(struct file *filp, char __user *buf,
  					size_t count, loff_t *ppos)
  {
  	char tmpbuf[TMPBUFLEN];
  	ssize_t length;
496ad9aa8   Al Viro   new helper: file_...
194
  	ino_t ino = file_inode(filp)->i_ino;
3f12070e2   Eric Paris   SELinux: policy s...
195
196
197
198
199
200
201
202
203
  	int handle_unknown = (ino == SEL_REJECT_UNKNOWN) ?
  		security_get_reject_unknown() : !security_get_allow_unknown();
  
  	length = scnprintf(tmpbuf, TMPBUFLEN, "%d", handle_unknown);
  	return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
  }
  
  static const struct file_operations sel_handle_unknown_ops = {
  	.read		= sel_read_handle_unknown,
57a62c231   Arnd Bergmann   selinux: use gene...
204
  	.llseek		= generic_file_llseek,
3f12070e2   Eric Paris   SELinux: policy s...
205
  };
119041672   KaiGai Kohei   selinux: fast sta...
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
  static int sel_open_handle_status(struct inode *inode, struct file *filp)
  {
  	struct page    *status = selinux_kernel_status_page();
  
  	if (!status)
  		return -ENOMEM;
  
  	filp->private_data = status;
  
  	return 0;
  }
  
  static ssize_t sel_read_handle_status(struct file *filp, char __user *buf,
  				      size_t count, loff_t *ppos)
  {
  	struct page    *status = filp->private_data;
  
  	BUG_ON(!status);
  
  	return simple_read_from_buffer(buf, count, ppos,
  				       page_address(status),
  				       sizeof(struct selinux_kernel_status));
  }
  
  static int sel_mmap_handle_status(struct file *filp,
  				  struct vm_area_struct *vma)
  {
  	struct page    *status = filp->private_data;
  	unsigned long	size = vma->vm_end - vma->vm_start;
  
  	BUG_ON(!status);
  
  	/* only allows one page from the head */
  	if (vma->vm_pgoff > 0 || size != PAGE_SIZE)
  		return -EIO;
  	/* disallow writable mapping */
  	if (vma->vm_flags & VM_WRITE)
  		return -EPERM;
  	/* disallow mprotect() turns it into writable */
  	vma->vm_flags &= ~VM_MAYWRITE;
  
  	return remap_pfn_range(vma, vma->vm_start,
  			       page_to_pfn(status),
  			       size, vma->vm_page_prot);
  }
  
  static const struct file_operations sel_handle_status_ops = {
  	.open		= sel_open_handle_status,
  	.read		= sel_read_handle_status,
  	.mmap		= sel_mmap_handle_status,
  	.llseek		= generic_file_llseek,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
258
  #ifdef CONFIG_SECURITY_SELINUX_DISABLE
1872981b5   Eric Paris   SELinux: cleanup ...
259
  static ssize_t sel_write_disable(struct file *file, const char __user *buf,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
260
261
262
  				 size_t count, loff_t *ppos)
  
  {
b77a493b1   Eric Paris   SELinux: standard...
263
  	char *page = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
264
265
  	ssize_t length;
  	int new_value;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266

b77a493b1   Eric Paris   SELinux: standard...
267
  	length = -ENOMEM;
bfd51626c   Davi Arnaut   [PATCH] SELinux: ...
268
  	if (count >= PAGE_SIZE)
6eab04a87   Justin P. Mattock   treewide: remove ...
269
  		goto out;
b77a493b1   Eric Paris   SELinux: standard...
270
271
272
273
274
275
276
  
  	/* No partial writes. */
  	length = -EINVAL;
  	if (*ppos != 0)
  		goto out;
  
  	length = -ENOMEM;
1872981b5   Eric Paris   SELinux: cleanup ...
277
  	page = (char *)get_zeroed_page(GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
278
  	if (!page)
b77a493b1   Eric Paris   SELinux: standard...
279
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
280
281
282
283
284
285
286
287
288
289
  	length = -EFAULT;
  	if (copy_from_user(page, buf, count))
  		goto out;
  
  	length = -EINVAL;
  	if (sscanf(page, "%d", &new_value) != 1)
  		goto out;
  
  	if (new_value) {
  		length = selinux_disable();
b77a493b1   Eric Paris   SELinux: standard...
290
  		if (length)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291
  			goto out;
af601e462   Steve Grubb   [PATCH] SE Linux ...
292
  		audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS,
4746ec5b0   Eric Paris   [AUDIT] add sessi...
293
  			"selinux=0 auid=%u ses=%u",
581abc09c   Eric W. Biederman   userns: Convert s...
294
  			from_kuid(&init_user_ns, audit_get_loginuid(current)),
4746ec5b0   Eric Paris   [AUDIT] add sessi...
295
  			audit_get_sessionid(current));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296
297
298
299
300
301
302
303
304
305
  	}
  
  	length = count;
  out:
  	free_page((unsigned long) page);
  	return length;
  }
  #else
  #define sel_write_disable NULL
  #endif
9c2e08c59   Arjan van de Ven   [PATCH] mark stru...
306
  static const struct file_operations sel_disable_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
307
  	.write		= sel_write_disable,
57a62c231   Arnd Bergmann   selinux: use gene...
308
  	.llseek		= generic_file_llseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
309
310
311
  };
  
  static ssize_t sel_read_policyvers(struct file *filp, char __user *buf,
1872981b5   Eric Paris   SELinux: cleanup ...
312
  				   size_t count, loff_t *ppos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
313
314
315
316
317
318
319
  {
  	char tmpbuf[TMPBUFLEN];
  	ssize_t length;
  
  	length = scnprintf(tmpbuf, TMPBUFLEN, "%u", POLICYDB_VERSION_MAX);
  	return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
  }
9c2e08c59   Arjan van de Ven   [PATCH] mark stru...
320
  static const struct file_operations sel_policyvers_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
321
  	.read		= sel_read_policyvers,
57a62c231   Arnd Bergmann   selinux: use gene...
322
  	.llseek		= generic_file_llseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
323
324
325
326
  };
  
  /* declaration for sel_write_load */
  static int sel_make_bools(void);
e47c8fc58   Christopher J. PeBenito   selinux: add seli...
327
  static int sel_make_classes(void);
3bb56b25d   Paul Moore   SELinux: Add a ca...
328
  static int sel_make_policycap(void);
e47c8fc58   Christopher J. PeBenito   selinux: add seli...
329
330
  
  /* declaration for sel_make_class_dirs */
a1c2aa1e8   Al Viro   selinuxfs: merge ...
331
  static struct dentry *sel_make_dir(struct dentry *dir, const char *name,
e47c8fc58   Christopher J. PeBenito   selinux: add seli...
332
  			unsigned long *ino);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
333
334
335
336
337
338
  
  static ssize_t sel_read_mls(struct file *filp, char __user *buf,
  				size_t count, loff_t *ppos)
  {
  	char tmpbuf[TMPBUFLEN];
  	ssize_t length;
0719aaf5e   Guido Trentalancia   selinux: allow ML...
339
340
  	length = scnprintf(tmpbuf, TMPBUFLEN, "%d",
  			   security_mls_enabled());
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
341
342
  	return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
  }
9c2e08c59   Arjan van de Ven   [PATCH] mark stru...
343
  static const struct file_operations sel_mls_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
  	.read		= sel_read_mls,
57a62c231   Arnd Bergmann   selinux: use gene...
345
  	.llseek		= generic_file_llseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
346
  };
cee74f47a   Eric Paris   SELinux: allow us...
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
  struct policy_load_memory {
  	size_t len;
  	void *data;
  };
  
  static int sel_open_policy(struct inode *inode, struct file *filp)
  {
  	struct policy_load_memory *plm = NULL;
  	int rc;
  
  	BUG_ON(filp->private_data);
  
  	mutex_lock(&sel_mutex);
  
  	rc = task_has_security(current, SECURITY__READ_POLICY);
  	if (rc)
  		goto err;
  
  	rc = -EBUSY;
  	if (policy_opened)
  		goto err;
  
  	rc = -ENOMEM;
  	plm = kzalloc(sizeof(*plm), GFP_KERNEL);
  	if (!plm)
  		goto err;
  
  	if (i_size_read(inode) != security_policydb_len()) {
  		mutex_lock(&inode->i_mutex);
  		i_size_write(inode, security_policydb_len());
  		mutex_unlock(&inode->i_mutex);
  	}
  
  	rc = security_read_policy(&plm->data, &plm->len);
  	if (rc)
  		goto err;
  
  	policy_opened = 1;
  
  	filp->private_data = plm;
  
  	mutex_unlock(&sel_mutex);
  
  	return 0;
  err:
  	mutex_unlock(&sel_mutex);
  
  	if (plm)
  		vfree(plm->data);
  	kfree(plm);
  	return rc;
  }
  
  static int sel_release_policy(struct inode *inode, struct file *filp)
  {
  	struct policy_load_memory *plm = filp->private_data;
  
  	BUG_ON(!plm);
  
  	policy_opened = 0;
  
  	vfree(plm->data);
  	kfree(plm);
  
  	return 0;
  }
  
  static ssize_t sel_read_policy(struct file *filp, char __user *buf,
  			       size_t count, loff_t *ppos)
  {
  	struct policy_load_memory *plm = filp->private_data;
  	int ret;
  
  	mutex_lock(&sel_mutex);
  
  	ret = task_has_security(current, SECURITY__READ_POLICY);
  	if (ret)
  		goto out;
  
  	ret = simple_read_from_buffer(buf, count, ppos, plm->data, plm->len);
  out:
  	mutex_unlock(&sel_mutex);
  	return ret;
  }
845ca30fe   Eric Paris   selinux: implemen...
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
  static int sel_mmap_policy_fault(struct vm_area_struct *vma,
  				 struct vm_fault *vmf)
  {
  	struct policy_load_memory *plm = vma->vm_file->private_data;
  	unsigned long offset;
  	struct page *page;
  
  	if (vmf->flags & (FAULT_FLAG_MKWRITE | FAULT_FLAG_WRITE))
  		return VM_FAULT_SIGBUS;
  
  	offset = vmf->pgoff << PAGE_SHIFT;
  	if (offset >= roundup(plm->len, PAGE_SIZE))
  		return VM_FAULT_SIGBUS;
  
  	page = vmalloc_to_page(plm->data + offset);
  	get_page(page);
  
  	vmf->page = page;
  
  	return 0;
  }
  
  static struct vm_operations_struct sel_mmap_policy_ops = {
  	.fault = sel_mmap_policy_fault,
  	.page_mkwrite = sel_mmap_policy_fault,
  };
ad3fa08c4   James Morris   selinux: sparse f...
457
  static int sel_mmap_policy(struct file *filp, struct vm_area_struct *vma)
845ca30fe   Eric Paris   selinux: implemen...
458
459
460
461
462
463
464
465
  {
  	if (vma->vm_flags & VM_SHARED) {
  		/* do not allow mprotect to make mapping writable */
  		vma->vm_flags &= ~VM_MAYWRITE;
  
  		if (vma->vm_flags & VM_WRITE)
  			return -EACCES;
  	}
314e51b98   Konstantin Khlebnikov   mm: kill vma flag...
466
  	vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
845ca30fe   Eric Paris   selinux: implemen...
467
468
469
470
  	vma->vm_ops = &sel_mmap_policy_ops;
  
  	return 0;
  }
cee74f47a   Eric Paris   SELinux: allow us...
471
472
473
  static const struct file_operations sel_policy_ops = {
  	.open		= sel_open_policy,
  	.read		= sel_read_policy,
845ca30fe   Eric Paris   selinux: implemen...
474
  	.mmap		= sel_mmap_policy,
cee74f47a   Eric Paris   SELinux: allow us...
475
  	.release	= sel_release_policy,
47a93a5bc   Eric Paris   SELinux: allow se...
476
  	.llseek		= generic_file_llseek,
cee74f47a   Eric Paris   SELinux: allow us...
477
  };
1872981b5   Eric Paris   SELinux: cleanup ...
478
  static ssize_t sel_write_load(struct file *file, const char __user *buf,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
479
480
481
  			      size_t count, loff_t *ppos)
  
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482
483
  	ssize_t length;
  	void *data = NULL;
bb0030797   Ingo Molnar   [PATCH] sem2mutex...
484
  	mutex_lock(&sel_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
485
486
487
488
  
  	length = task_has_security(current, SECURITY__LOAD_POLICY);
  	if (length)
  		goto out;
b77a493b1   Eric Paris   SELinux: standard...
489
490
491
  	/* No partial writes. */
  	length = -EINVAL;
  	if (*ppos != 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
492
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
493

b77a493b1   Eric Paris   SELinux: standard...
494
495
496
497
498
499
500
  	length = -EFBIG;
  	if (count > 64 * 1024 * 1024)
  		goto out;
  
  	length = -ENOMEM;
  	data = vmalloc(count);
  	if (!data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
501
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
502
503
504
505
506
507
508
509
  
  	length = -EFAULT;
  	if (copy_from_user(data, buf, count) != 0)
  		goto out;
  
  	length = security_load_policy(data, count);
  	if (length)
  		goto out;
b77a493b1   Eric Paris   SELinux: standard...
510
511
  	length = sel_make_bools();
  	if (length)
e47c8fc58   Christopher J. PeBenito   selinux: add seli...
512
  		goto out1;
e47c8fc58   Christopher J. PeBenito   selinux: add seli...
513

b77a493b1   Eric Paris   SELinux: standard...
514
515
  	length = sel_make_classes();
  	if (length)
3bb56b25d   Paul Moore   SELinux: Add a ca...
516
  		goto out1;
3bb56b25d   Paul Moore   SELinux: Add a ca...
517

b77a493b1   Eric Paris   SELinux: standard...
518
519
520
521
522
  	length = sel_make_policycap();
  	if (length)
  		goto out1;
  
  	length = count;
e47c8fc58   Christopher J. PeBenito   selinux: add seli...
523
524
  
  out1:
af601e462   Steve Grubb   [PATCH] SE Linux ...
525
  	audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_POLICY_LOAD,
4746ec5b0   Eric Paris   [AUDIT] add sessi...
526
  		"policy loaded auid=%u ses=%u",
581abc09c   Eric W. Biederman   userns: Convert s...
527
  		from_kuid(&init_user_ns, audit_get_loginuid(current)),
4746ec5b0   Eric Paris   [AUDIT] add sessi...
528
  		audit_get_sessionid(current));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
529
  out:
bb0030797   Ingo Molnar   [PATCH] sem2mutex...
530
  	mutex_unlock(&sel_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
531
532
533
  	vfree(data);
  	return length;
  }
9c2e08c59   Arjan van de Ven   [PATCH] mark stru...
534
  static const struct file_operations sel_load_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
535
  	.write		= sel_write_load,
57a62c231   Arnd Bergmann   selinux: use gene...
536
  	.llseek		= generic_file_llseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
537
  };
1872981b5   Eric Paris   SELinux: cleanup ...
538
  static ssize_t sel_write_context(struct file *file, char *buf, size_t size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
539
  {
b77a493b1   Eric Paris   SELinux: standard...
540
  	char *canon = NULL;
ce9982d04   Stephen Smalley   [PATCH] selinux: ...
541
  	u32 sid, len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542
543
544
545
  	ssize_t length;
  
  	length = task_has_security(current, SECURITY__CHECK_CONTEXT);
  	if (length)
b77a493b1   Eric Paris   SELinux: standard...
546
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
547

52a4c6404   Nikolay Aleksandrov   selinux: add gfp ...
548
  	length = security_context_to_sid(buf, size, &sid, GFP_KERNEL);
b77a493b1   Eric Paris   SELinux: standard...
549
550
  	if (length)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
551

ce9982d04   Stephen Smalley   [PATCH] selinux: ...
552
  	length = security_sid_to_context(sid, &canon, &len);
b77a493b1   Eric Paris   SELinux: standard...
553
554
  	if (length)
  		goto out;
ce9982d04   Stephen Smalley   [PATCH] selinux: ...
555

b77a493b1   Eric Paris   SELinux: standard...
556
  	length = -ERANGE;
ce9982d04   Stephen Smalley   [PATCH] selinux: ...
557
  	if (len > SIMPLE_TRANSACTION_LIMIT) {
744ba35e4   Eric Paris   SELinux: clean up...
558
559
560
  		printk(KERN_ERR "SELinux: %s:  context size (%u) exceeds "
  			"payload max
  ", __func__, len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
561
  		goto out;
ce9982d04   Stephen Smalley   [PATCH] selinux: ...
562
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
563

ce9982d04   Stephen Smalley   [PATCH] selinux: ...
564
565
  	memcpy(buf, canon, len);
  	length = len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
566
  out:
ce9982d04   Stephen Smalley   [PATCH] selinux: ...
567
  	kfree(canon);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
568
569
  	return length;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
570
571
572
573
574
575
576
577
578
  static ssize_t sel_read_checkreqprot(struct file *filp, char __user *buf,
  				     size_t count, loff_t *ppos)
  {
  	char tmpbuf[TMPBUFLEN];
  	ssize_t length;
  
  	length = scnprintf(tmpbuf, TMPBUFLEN, "%u", selinux_checkreqprot);
  	return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
  }
1872981b5   Eric Paris   SELinux: cleanup ...
579
  static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
580
581
  				      size_t count, loff_t *ppos)
  {
b77a493b1   Eric Paris   SELinux: standard...
582
  	char *page = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
583
584
585
586
587
  	ssize_t length;
  	unsigned int new_value;
  
  	length = task_has_security(current, SECURITY__SETCHECKREQPROT);
  	if (length)
b77a493b1   Eric Paris   SELinux: standard...
588
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
589

b77a493b1   Eric Paris   SELinux: standard...
590
  	length = -ENOMEM;
bfd51626c   Davi Arnaut   [PATCH] SELinux: ...
591
  	if (count >= PAGE_SIZE)
b77a493b1   Eric Paris   SELinux: standard...
592
593
594
595
596
597
598
599
  		goto out;
  
  	/* No partial writes. */
  	length = -EINVAL;
  	if (*ppos != 0)
  		goto out;
  
  	length = -ENOMEM;
1872981b5   Eric Paris   SELinux: cleanup ...
600
  	page = (char *)get_zeroed_page(GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
601
  	if (!page)
b77a493b1   Eric Paris   SELinux: standard...
602
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
603
604
605
606
607
608
609
610
611
612
613
614
615
616
  	length = -EFAULT;
  	if (copy_from_user(page, buf, count))
  		goto out;
  
  	length = -EINVAL;
  	if (sscanf(page, "%u", &new_value) != 1)
  		goto out;
  
  	selinux_checkreqprot = new_value ? 1 : 0;
  	length = count;
  out:
  	free_page((unsigned long) page);
  	return length;
  }
9c2e08c59   Arjan van de Ven   [PATCH] mark stru...
617
  static const struct file_operations sel_checkreqprot_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
618
619
  	.read		= sel_read_checkreqprot,
  	.write		= sel_write_checkreqprot,
57a62c231   Arnd Bergmann   selinux: use gene...
620
  	.llseek		= generic_file_llseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
621
622
623
624
625
  };
  
  /*
   * Remaining nodes use transaction based IO methods like nfsd/nfsctl.c
   */
1872981b5   Eric Paris   SELinux: cleanup ...
626
627
628
629
630
  static ssize_t sel_write_access(struct file *file, char *buf, size_t size);
  static ssize_t sel_write_create(struct file *file, char *buf, size_t size);
  static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size);
  static ssize_t sel_write_user(struct file *file, char *buf, size_t size);
  static ssize_t sel_write_member(struct file *file, char *buf, size_t size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
631
632
633
634
635
636
637
  
  static ssize_t (*write_op[])(struct file *, char *, size_t) = {
  	[SEL_ACCESS] = sel_write_access,
  	[SEL_CREATE] = sel_write_create,
  	[SEL_RELABEL] = sel_write_relabel,
  	[SEL_USER] = sel_write_user,
  	[SEL_MEMBER] = sel_write_member,
ce9982d04   Stephen Smalley   [PATCH] selinux: ...
638
  	[SEL_CONTEXT] = sel_write_context,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
639
640
641
642
  };
  
  static ssize_t selinux_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos)
  {
496ad9aa8   Al Viro   new helper: file_...
643
  	ino_t ino = file_inode(file)->i_ino;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
644
645
  	char *data;
  	ssize_t rv;
6e20a64a3   Nicolas Kaiser   [PATCH] selinux: ...
646
  	if (ino >= ARRAY_SIZE(write_op) || !write_op[ino])
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
647
648
649
650
651
  		return -EINVAL;
  
  	data = simple_transaction_get(file, buf, size);
  	if (IS_ERR(data))
  		return PTR_ERR(data);
1872981b5   Eric Paris   SELinux: cleanup ...
652
653
  	rv = write_op[ino](file, data, size);
  	if (rv > 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
654
655
656
657
658
  		simple_transaction_set(file, rv);
  		rv = size;
  	}
  	return rv;
  }
9c2e08c59   Arjan van de Ven   [PATCH] mark stru...
659
  static const struct file_operations transaction_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
660
661
662
  	.write		= selinux_transaction_write,
  	.read		= simple_transaction_read,
  	.release	= simple_transaction_release,
57a62c231   Arnd Bergmann   selinux: use gene...
663
  	.llseek		= generic_file_llseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
664
665
666
667
668
669
670
  };
  
  /*
   * payload - write methods
   * If the method has a response, the response should be put in buf,
   * and the length returned.  Otherwise return 0 or and -error.
   */
1872981b5   Eric Paris   SELinux: cleanup ...
671
  static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
672
  {
b77a493b1   Eric Paris   SELinux: standard...
673
  	char *scon = NULL, *tcon = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
674
675
  	u32 ssid, tsid;
  	u16 tclass;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
676
677
678
679
680
  	struct av_decision avd;
  	ssize_t length;
  
  	length = task_has_security(current, SECURITY__COMPUTE_AV);
  	if (length)
b77a493b1   Eric Paris   SELinux: standard...
681
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
682
683
  
  	length = -ENOMEM;
c1a7368a6   wzt.wzt@gmail.com   Security: Fix cod...
684
  	scon = kzalloc(size + 1, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
685
  	if (!scon)
b77a493b1   Eric Paris   SELinux: standard...
686
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
687

b77a493b1   Eric Paris   SELinux: standard...
688
  	length = -ENOMEM;
c1a7368a6   wzt.wzt@gmail.com   Security: Fix cod...
689
  	tcon = kzalloc(size + 1, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
690
691
  	if (!tcon)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
692
693
  
  	length = -EINVAL;
19439d05b   Stephen Smalley   selinux: change t...
694
  	if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
b77a493b1   Eric Paris   SELinux: standard...
695
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
696

52a4c6404   Nikolay Aleksandrov   selinux: add gfp ...
697
698
  	length = security_context_to_sid(scon, strlen(scon) + 1, &ssid,
  					 GFP_KERNEL);
b77a493b1   Eric Paris   SELinux: standard...
699
700
  	if (length)
  		goto out;
52a4c6404   Nikolay Aleksandrov   selinux: add gfp ...
701
702
  	length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid,
  					 GFP_KERNEL);
b77a493b1   Eric Paris   SELinux: standard...
703
704
  	if (length)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
705

19439d05b   Stephen Smalley   selinux: change t...
706
  	security_compute_av_user(ssid, tsid, tclass, &avd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
707
708
  
  	length = scnprintf(buf, SIMPLE_TRANSACTION_LIMIT,
8a6f83afd   KaiGai Kohei   Permissive domain...
709
  			  "%x %x %x %x %u %x",
f1c6381a6   Eric Paris   SELinux: remove u...
710
  			  avd.allowed, 0xffffffff,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
711
  			  avd.auditallow, avd.auditdeny,
8a6f83afd   KaiGai Kohei   Permissive domain...
712
  			  avd.seqno, avd.flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
713
  out:
b77a493b1   Eric Paris   SELinux: standard...
714
  	kfree(tcon);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
715
716
717
  	kfree(scon);
  	return length;
  }
1872981b5   Eric Paris   SELinux: cleanup ...
718
  static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
719
  {
b77a493b1   Eric Paris   SELinux: standard...
720
  	char *scon = NULL, *tcon = NULL;
f50a3ec96   Kohei Kaigai   selinux: add type...
721
  	char *namebuf = NULL, *objname = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
722
723
724
  	u32 ssid, tsid, newsid;
  	u16 tclass;
  	ssize_t length;
b77a493b1   Eric Paris   SELinux: standard...
725
  	char *newcon = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
726
  	u32 len;
f50a3ec96   Kohei Kaigai   selinux: add type...
727
  	int nargs;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
728
729
730
  
  	length = task_has_security(current, SECURITY__COMPUTE_CREATE);
  	if (length)
b77a493b1   Eric Paris   SELinux: standard...
731
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
732
733
  
  	length = -ENOMEM;
c1a7368a6   wzt.wzt@gmail.com   Security: Fix cod...
734
  	scon = kzalloc(size + 1, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
735
  	if (!scon)
b77a493b1   Eric Paris   SELinux: standard...
736
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
737

b77a493b1   Eric Paris   SELinux: standard...
738
  	length = -ENOMEM;
c1a7368a6   wzt.wzt@gmail.com   Security: Fix cod...
739
  	tcon = kzalloc(size + 1, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
740
741
  	if (!tcon)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
742

f50a3ec96   Kohei Kaigai   selinux: add type...
743
744
745
746
  	length = -ENOMEM;
  	namebuf = kzalloc(size + 1, GFP_KERNEL);
  	if (!namebuf)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
747
  	length = -EINVAL;
f50a3ec96   Kohei Kaigai   selinux: add type...
748
749
  	nargs = sscanf(buf, "%s %s %hu %s", scon, tcon, &tclass, namebuf);
  	if (nargs < 3 || nargs > 4)
b77a493b1   Eric Paris   SELinux: standard...
750
  		goto out;
0f7e4c33e   Kohei Kaigai   selinux: fix case...
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
  	if (nargs == 4) {
  		/*
  		 * If and when the name of new object to be queried contains
  		 * either whitespace or multibyte characters, they shall be
  		 * encoded based on the percentage-encoding rule.
  		 * If not encoded, the sscanf logic picks up only left-half
  		 * of the supplied name; splitted by a whitespace unexpectedly.
  		 */
  		char   *r, *w;
  		int     c1, c2;
  
  		r = w = namebuf;
  		do {
  			c1 = *r++;
  			if (c1 == '+')
  				c1 = ' ';
  			else if (c1 == '%') {
af7ff2c2c   Andy Shevchenko   selinuxfs: remove...
768
769
  				c1 = hex_to_bin(*r++);
  				if (c1 < 0)
0f7e4c33e   Kohei Kaigai   selinux: fix case...
770
  					goto out;
af7ff2c2c   Andy Shevchenko   selinuxfs: remove...
771
772
  				c2 = hex_to_bin(*r++);
  				if (c2 < 0)
0f7e4c33e   Kohei Kaigai   selinux: fix case...
773
774
775
776
777
  					goto out;
  				c1 = (c1 << 4) | c2;
  			}
  			*w++ = c1;
  		} while (c1 != '\0');
f50a3ec96   Kohei Kaigai   selinux: add type...
778
  		objname = namebuf;
0f7e4c33e   Kohei Kaigai   selinux: fix case...
779
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
780

52a4c6404   Nikolay Aleksandrov   selinux: add gfp ...
781
782
  	length = security_context_to_sid(scon, strlen(scon) + 1, &ssid,
  					 GFP_KERNEL);
b77a493b1   Eric Paris   SELinux: standard...
783
784
  	if (length)
  		goto out;
52a4c6404   Nikolay Aleksandrov   selinux: add gfp ...
785
786
  	length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid,
  					 GFP_KERNEL);
b77a493b1   Eric Paris   SELinux: standard...
787
788
  	if (length)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
789

f50a3ec96   Kohei Kaigai   selinux: add type...
790
791
  	length = security_transition_sid_user(ssid, tsid, tclass,
  					      objname, &newsid);
b77a493b1   Eric Paris   SELinux: standard...
792
793
  	if (length)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
794
795
  
  	length = security_sid_to_context(newsid, &newcon, &len);
b77a493b1   Eric Paris   SELinux: standard...
796
797
  	if (length)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
798

b77a493b1   Eric Paris   SELinux: standard...
799
  	length = -ERANGE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
800
  	if (len > SIMPLE_TRANSACTION_LIMIT) {
744ba35e4   Eric Paris   SELinux: clean up...
801
802
803
  		printk(KERN_ERR "SELinux: %s:  context size (%u) exceeds "
  			"payload max
  ", __func__, len);
b77a493b1   Eric Paris   SELinux: standard...
804
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
805
806
807
808
  	}
  
  	memcpy(buf, newcon, len);
  	length = len;
b77a493b1   Eric Paris   SELinux: standard...
809
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
810
  	kfree(newcon);
f50a3ec96   Kohei Kaigai   selinux: add type...
811
  	kfree(namebuf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
812
  	kfree(tcon);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
813
814
815
  	kfree(scon);
  	return length;
  }
1872981b5   Eric Paris   SELinux: cleanup ...
816
  static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
817
  {
b77a493b1   Eric Paris   SELinux: standard...
818
  	char *scon = NULL, *tcon = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
819
820
821
  	u32 ssid, tsid, newsid;
  	u16 tclass;
  	ssize_t length;
b77a493b1   Eric Paris   SELinux: standard...
822
  	char *newcon = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
823
824
825
826
  	u32 len;
  
  	length = task_has_security(current, SECURITY__COMPUTE_RELABEL);
  	if (length)
b77a493b1   Eric Paris   SELinux: standard...
827
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
828
829
  
  	length = -ENOMEM;
c1a7368a6   wzt.wzt@gmail.com   Security: Fix cod...
830
  	scon = kzalloc(size + 1, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
831
  	if (!scon)
b77a493b1   Eric Paris   SELinux: standard...
832
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
833

b77a493b1   Eric Paris   SELinux: standard...
834
  	length = -ENOMEM;
c1a7368a6   wzt.wzt@gmail.com   Security: Fix cod...
835
  	tcon = kzalloc(size + 1, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
836
837
  	if (!tcon)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
838
839
840
  
  	length = -EINVAL;
  	if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
b77a493b1   Eric Paris   SELinux: standard...
841
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
842

52a4c6404   Nikolay Aleksandrov   selinux: add gfp ...
843
844
  	length = security_context_to_sid(scon, strlen(scon) + 1, &ssid,
  					 GFP_KERNEL);
b77a493b1   Eric Paris   SELinux: standard...
845
846
  	if (length)
  		goto out;
52a4c6404   Nikolay Aleksandrov   selinux: add gfp ...
847
848
  	length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid,
  					 GFP_KERNEL);
b77a493b1   Eric Paris   SELinux: standard...
849
850
  	if (length)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
851
852
  
  	length = security_change_sid(ssid, tsid, tclass, &newsid);
b77a493b1   Eric Paris   SELinux: standard...
853
854
  	if (length)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
855
856
  
  	length = security_sid_to_context(newsid, &newcon, &len);
b77a493b1   Eric Paris   SELinux: standard...
857
858
  	if (length)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
859

b77a493b1   Eric Paris   SELinux: standard...
860
861
862
  	length = -ERANGE;
  	if (len > SIMPLE_TRANSACTION_LIMIT)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
863
864
865
  
  	memcpy(buf, newcon, len);
  	length = len;
b77a493b1   Eric Paris   SELinux: standard...
866
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
867
  	kfree(newcon);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
868
  	kfree(tcon);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
869
870
871
  	kfree(scon);
  	return length;
  }
1872981b5   Eric Paris   SELinux: cleanup ...
872
  static ssize_t sel_write_user(struct file *file, char *buf, size_t size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
873
  {
b77a493b1   Eric Paris   SELinux: standard...
874
875
  	char *con = NULL, *user = NULL, *ptr;
  	u32 sid, *sids = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
876
877
878
879
880
881
882
  	ssize_t length;
  	char *newcon;
  	int i, rc;
  	u32 len, nsids;
  
  	length = task_has_security(current, SECURITY__COMPUTE_USER);
  	if (length)
6eab04a87   Justin P. Mattock   treewide: remove ...
883
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
884
885
  
  	length = -ENOMEM;
c1a7368a6   wzt.wzt@gmail.com   Security: Fix cod...
886
  	con = kzalloc(size + 1, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
887
  	if (!con)
6eab04a87   Justin P. Mattock   treewide: remove ...
888
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
889

b77a493b1   Eric Paris   SELinux: standard...
890
  	length = -ENOMEM;
c1a7368a6   wzt.wzt@gmail.com   Security: Fix cod...
891
  	user = kzalloc(size + 1, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
892
893
  	if (!user)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
894
895
896
  
  	length = -EINVAL;
  	if (sscanf(buf, "%s %s", con, user) != 2)
b77a493b1   Eric Paris   SELinux: standard...
897
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
898

52a4c6404   Nikolay Aleksandrov   selinux: add gfp ...
899
  	length = security_context_to_sid(con, strlen(con) + 1, &sid, GFP_KERNEL);
b77a493b1   Eric Paris   SELinux: standard...
900
901
  	if (length)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
902
903
  
  	length = security_get_user_sids(sid, user, &sids, &nsids);
b77a493b1   Eric Paris   SELinux: standard...
904
905
  	if (length)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
906
907
908
909
910
911
912
  
  	length = sprintf(buf, "%u", nsids) + 1;
  	ptr = buf + length;
  	for (i = 0; i < nsids; i++) {
  		rc = security_sid_to_context(sids[i], &newcon, &len);
  		if (rc) {
  			length = rc;
b77a493b1   Eric Paris   SELinux: standard...
913
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
914
915
916
917
  		}
  		if ((length + len) >= SIMPLE_TRANSACTION_LIMIT) {
  			kfree(newcon);
  			length = -ERANGE;
b77a493b1   Eric Paris   SELinux: standard...
918
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
919
920
921
922
923
924
  		}
  		memcpy(ptr, newcon, len);
  		kfree(newcon);
  		ptr += len;
  		length += len;
  	}
b77a493b1   Eric Paris   SELinux: standard...
925
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
926
  	kfree(sids);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
927
  	kfree(user);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
928
929
930
  	kfree(con);
  	return length;
  }
1872981b5   Eric Paris   SELinux: cleanup ...
931
  static ssize_t sel_write_member(struct file *file, char *buf, size_t size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
932
  {
b77a493b1   Eric Paris   SELinux: standard...
933
  	char *scon = NULL, *tcon = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
934
935
936
  	u32 ssid, tsid, newsid;
  	u16 tclass;
  	ssize_t length;
b77a493b1   Eric Paris   SELinux: standard...
937
  	char *newcon = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
938
939
940
941
  	u32 len;
  
  	length = task_has_security(current, SECURITY__COMPUTE_MEMBER);
  	if (length)
b77a493b1   Eric Paris   SELinux: standard...
942
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
943
944
  
  	length = -ENOMEM;
c1a7368a6   wzt.wzt@gmail.com   Security: Fix cod...
945
  	scon = kzalloc(size + 1, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
946
  	if (!scon)
6eab04a87   Justin P. Mattock   treewide: remove ...
947
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
948

b77a493b1   Eric Paris   SELinux: standard...
949
  	length = -ENOMEM;
c1a7368a6   wzt.wzt@gmail.com   Security: Fix cod...
950
  	tcon = kzalloc(size + 1, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
951
952
  	if (!tcon)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
953
954
955
  
  	length = -EINVAL;
  	if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
b77a493b1   Eric Paris   SELinux: standard...
956
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
957

52a4c6404   Nikolay Aleksandrov   selinux: add gfp ...
958
959
  	length = security_context_to_sid(scon, strlen(scon) + 1, &ssid,
  					 GFP_KERNEL);
b77a493b1   Eric Paris   SELinux: standard...
960
961
  	if (length)
  		goto out;
52a4c6404   Nikolay Aleksandrov   selinux: add gfp ...
962
963
  	length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid,
  					 GFP_KERNEL);
b77a493b1   Eric Paris   SELinux: standard...
964
965
  	if (length)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
966
967
  
  	length = security_member_sid(ssid, tsid, tclass, &newsid);
b77a493b1   Eric Paris   SELinux: standard...
968
969
  	if (length)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
970
971
  
  	length = security_sid_to_context(newsid, &newcon, &len);
b77a493b1   Eric Paris   SELinux: standard...
972
973
  	if (length)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
974

b77a493b1   Eric Paris   SELinux: standard...
975
  	length = -ERANGE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
976
  	if (len > SIMPLE_TRANSACTION_LIMIT) {
744ba35e4   Eric Paris   SELinux: clean up...
977
978
979
  		printk(KERN_ERR "SELinux: %s:  context size (%u) exceeds "
  			"payload max
  ", __func__, len);
b77a493b1   Eric Paris   SELinux: standard...
980
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
981
982
983
984
  	}
  
  	memcpy(buf, newcon, len);
  	length = len;
b77a493b1   Eric Paris   SELinux: standard...
985
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
986
  	kfree(newcon);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
987
  	kfree(tcon);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
988
989
990
991
992
993
994
995
996
997
  	kfree(scon);
  	return length;
  }
  
  static struct inode *sel_make_inode(struct super_block *sb, int mode)
  {
  	struct inode *ret = new_inode(sb);
  
  	if (ret) {
  		ret->i_mode = mode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
998
999
1000
1001
  		ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME;
  	}
  	return ret;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1002
1003
1004
1005
1006
  static ssize_t sel_read_bool(struct file *filep, char __user *buf,
  			     size_t count, loff_t *ppos)
  {
  	char *page = NULL;
  	ssize_t length;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1007
1008
  	ssize_t ret;
  	int cur_enforcing;
496ad9aa8   Al Viro   new helper: file_...
1009
  	unsigned index = file_inode(filep)->i_ino & SEL_INO_MASK;
d313f9483   Stephen Smalley   SELinux: detect d...
1010
  	const char *name = filep->f_path.dentry->d_name.name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1011

bb0030797   Ingo Molnar   [PATCH] sem2mutex...
1012
  	mutex_lock(&sel_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1013

b77a493b1   Eric Paris   SELinux: standard...
1014
1015
  	ret = -EINVAL;
  	if (index >= bool_num || strcmp(name, bool_pending_names[index]))
d313f9483   Stephen Smalley   SELinux: detect d...
1016
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1017

b77a493b1   Eric Paris   SELinux: standard...
1018
  	ret = -ENOMEM;
1872981b5   Eric Paris   SELinux: cleanup ...
1019
  	page = (char *)get_zeroed_page(GFP_KERNEL);
b77a493b1   Eric Paris   SELinux: standard...
1020
  	if (!page)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1021
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1022

d313f9483   Stephen Smalley   SELinux: detect d...
1023
  	cur_enforcing = security_get_bool_value(index);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1024
1025
1026
1027
  	if (cur_enforcing < 0) {
  		ret = cur_enforcing;
  		goto out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1028
  	length = scnprintf(page, PAGE_SIZE, "%d %d", cur_enforcing,
d313f9483   Stephen Smalley   SELinux: detect d...
1029
  			  bool_pending_values[index]);
68bdcf28a   Stephen Smalley   [PATCH] selinux: ...
1030
  	ret = simple_read_from_buffer(buf, count, ppos, page, length);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1031
  out:
bb0030797   Ingo Molnar   [PATCH] sem2mutex...
1032
  	mutex_unlock(&sel_mutex);
b77a493b1   Eric Paris   SELinux: standard...
1033
  	free_page((unsigned long)page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1034
1035
1036
1037
1038
1039
1040
  	return ret;
  }
  
  static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
  			      size_t count, loff_t *ppos)
  {
  	char *page = NULL;
d313f9483   Stephen Smalley   SELinux: detect d...
1041
  	ssize_t length;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1042
  	int new_value;
496ad9aa8   Al Viro   new helper: file_...
1043
  	unsigned index = file_inode(filep)->i_ino & SEL_INO_MASK;
d313f9483   Stephen Smalley   SELinux: detect d...
1044
  	const char *name = filep->f_path.dentry->d_name.name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1045

bb0030797   Ingo Molnar   [PATCH] sem2mutex...
1046
  	mutex_lock(&sel_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1047
1048
1049
1050
  
  	length = task_has_security(current, SECURITY__SETBOOL);
  	if (length)
  		goto out;
b77a493b1   Eric Paris   SELinux: standard...
1051
1052
  	length = -EINVAL;
  	if (index >= bool_num || strcmp(name, bool_pending_names[index]))
d313f9483   Stephen Smalley   SELinux: detect d...
1053
  		goto out;
d313f9483   Stephen Smalley   SELinux: detect d...
1054

b77a493b1   Eric Paris   SELinux: standard...
1055
1056
  	length = -ENOMEM;
  	if (count >= PAGE_SIZE)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1057
  		goto out;
d313f9483   Stephen Smalley   SELinux: detect d...
1058

b77a493b1   Eric Paris   SELinux: standard...
1059
1060
1061
  	/* No partial writes. */
  	length = -EINVAL;
  	if (*ppos != 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1062
  		goto out;
b77a493b1   Eric Paris   SELinux: standard...
1063
1064
  
  	length = -ENOMEM;
1872981b5   Eric Paris   SELinux: cleanup ...
1065
  	page = (char *)get_zeroed_page(GFP_KERNEL);
b77a493b1   Eric Paris   SELinux: standard...
1066
  	if (!page)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1067
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1068

d313f9483   Stephen Smalley   SELinux: detect d...
1069
  	length = -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1070
1071
1072
1073
1074
1075
1076
1077
1078
  	if (copy_from_user(page, buf, count))
  		goto out;
  
  	length = -EINVAL;
  	if (sscanf(page, "%d", &new_value) != 1)
  		goto out;
  
  	if (new_value)
  		new_value = 1;
d313f9483   Stephen Smalley   SELinux: detect d...
1079
  	bool_pending_values[index] = new_value;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1080
1081
1082
  	length = count;
  
  out:
bb0030797   Ingo Molnar   [PATCH] sem2mutex...
1083
  	mutex_unlock(&sel_mutex);
b77a493b1   Eric Paris   SELinux: standard...
1084
  	free_page((unsigned long) page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1085
1086
  	return length;
  }
9c2e08c59   Arjan van de Ven   [PATCH] mark stru...
1087
  static const struct file_operations sel_bool_ops = {
1872981b5   Eric Paris   SELinux: cleanup ...
1088
1089
  	.read		= sel_read_bool,
  	.write		= sel_write_bool,
57a62c231   Arnd Bergmann   selinux: use gene...
1090
  	.llseek		= generic_file_llseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1091
1092
1093
1094
1095
1096
1097
  };
  
  static ssize_t sel_commit_bools_write(struct file *filep,
  				      const char __user *buf,
  				      size_t count, loff_t *ppos)
  {
  	char *page = NULL;
d313f9483   Stephen Smalley   SELinux: detect d...
1098
  	ssize_t length;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1099
  	int new_value;
bb0030797   Ingo Molnar   [PATCH] sem2mutex...
1100
  	mutex_lock(&sel_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1101
1102
1103
1104
  
  	length = task_has_security(current, SECURITY__SETBOOL);
  	if (length)
  		goto out;
b77a493b1   Eric Paris   SELinux: standard...
1105
1106
  	length = -ENOMEM;
  	if (count >= PAGE_SIZE)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1107
  		goto out;
b77a493b1   Eric Paris   SELinux: standard...
1108
1109
1110
1111
  
  	/* No partial writes. */
  	length = -EINVAL;
  	if (*ppos != 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1112
  		goto out;
b77a493b1   Eric Paris   SELinux: standard...
1113
1114
  
  	length = -ENOMEM;
1872981b5   Eric Paris   SELinux: cleanup ...
1115
  	page = (char *)get_zeroed_page(GFP_KERNEL);
b77a493b1   Eric Paris   SELinux: standard...
1116
  	if (!page)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1117
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1118

d313f9483   Stephen Smalley   SELinux: detect d...
1119
  	length = -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1120
1121
1122
1123
1124
1125
  	if (copy_from_user(page, buf, count))
  		goto out;
  
  	length = -EINVAL;
  	if (sscanf(page, "%d", &new_value) != 1)
  		goto out;
b77a493b1   Eric Paris   SELinux: standard...
1126
  	length = 0;
1872981b5   Eric Paris   SELinux: cleanup ...
1127
  	if (new_value && bool_pending_values)
b77a493b1   Eric Paris   SELinux: standard...
1128
  		length = security_set_bools(bool_num, bool_pending_values);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1129

b77a493b1   Eric Paris   SELinux: standard...
1130
1131
  	if (!length)
  		length = count;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1132
1133
  
  out:
bb0030797   Ingo Molnar   [PATCH] sem2mutex...
1134
  	mutex_unlock(&sel_mutex);
b77a493b1   Eric Paris   SELinux: standard...
1135
  	free_page((unsigned long) page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1136
1137
  	return length;
  }
9c2e08c59   Arjan van de Ven   [PATCH] mark stru...
1138
  static const struct file_operations sel_commit_bools_ops = {
1872981b5   Eric Paris   SELinux: cleanup ...
1139
  	.write		= sel_commit_bools_write,
57a62c231   Arnd Bergmann   selinux: use gene...
1140
  	.llseek		= generic_file_llseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1141
  };
0c92d7c73   Christopher J. PeBenito   selinux: rename s...
1142
  static void sel_remove_entries(struct dentry *de)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1143
  {
0955dc03a   Stephen Smalley   SELinux: do not c...
1144
  	struct list_head *node;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1145

2fd6b7f50   Nick Piggin   fs: dcache scale ...
1146
  	spin_lock(&de->d_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1147
1148
  	node = de->d_subdirs.next;
  	while (node != &de->d_subdirs) {
5160ee6fc   Eric Dumazet   [PATCH] shrink de...
1149
  		struct dentry *d = list_entry(node, struct dentry, d_u.d_child);
2fd6b7f50   Nick Piggin   fs: dcache scale ...
1150
1151
  
  		spin_lock_nested(&d->d_lock, DENTRY_D_LOCK_NESTED);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1152
1153
1154
  		list_del_init(node);
  
  		if (d->d_inode) {
dc0474be3   Nick Piggin   fs: dcache ration...
1155
  			dget_dlock(d);
2fd6b7f50   Nick Piggin   fs: dcache scale ...
1156
1157
  			spin_unlock(&de->d_lock);
  			spin_unlock(&d->d_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1158
1159
1160
  			d_delete(d);
  			simple_unlink(de->d_inode, d);
  			dput(d);
2fd6b7f50   Nick Piggin   fs: dcache scale ...
1161
1162
1163
  			spin_lock(&de->d_lock);
  		} else
  			spin_unlock(&d->d_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1164
1165
  		node = de->d_subdirs.next;
  	}
2fd6b7f50   Nick Piggin   fs: dcache scale ...
1166
  	spin_unlock(&de->d_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1167
1168
1169
1170
1171
1172
  }
  
  #define BOOL_DIR_NAME "booleans"
  
  static int sel_make_bools(void)
  {
b77a493b1   Eric Paris   SELinux: standard...
1173
  	int i, ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
  	ssize_t len;
  	struct dentry *dentry = NULL;
  	struct dentry *dir = bool_dir;
  	struct inode *inode = NULL;
  	struct inode_security_struct *isec;
  	char **names = NULL, *page;
  	int num;
  	int *values = NULL;
  	u32 sid;
  
  	/* remove any existing files */
8007f1025   Xiaotian Feng   selinux: fix memo...
1185
1186
  	for (i = 0; i < bool_num; i++)
  		kfree(bool_pending_names[i]);
d313f9483   Stephen Smalley   SELinux: detect d...
1187
  	kfree(bool_pending_names);
9a5f04bf7   Jesper Juhl   [PATCH] selinux: ...
1188
  	kfree(bool_pending_values);
154c50ca4   Eric Paris   SELinux: if sel_m...
1189
  	bool_num = 0;
d313f9483   Stephen Smalley   SELinux: detect d...
1190
  	bool_pending_names = NULL;
20c19e417   Davi Arnaut   [PATCH] SELinux: ...
1191
  	bool_pending_values = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1192

0c92d7c73   Christopher J. PeBenito   selinux: rename s...
1193
  	sel_remove_entries(dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1194

b77a493b1   Eric Paris   SELinux: standard...
1195
  	ret = -ENOMEM;
1872981b5   Eric Paris   SELinux: cleanup ...
1196
1197
  	page = (char *)get_zeroed_page(GFP_KERNEL);
  	if (!page)
b77a493b1   Eric Paris   SELinux: standard...
1198
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1199
1200
  
  	ret = security_get_bools(&num, &names, &values);
b77a493b1   Eric Paris   SELinux: standard...
1201
  	if (ret)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1202
1203
1204
  		goto out;
  
  	for (i = 0; i < num; i++) {
b77a493b1   Eric Paris   SELinux: standard...
1205
  		ret = -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1206
  		dentry = d_alloc_name(dir, names[i]);
b77a493b1   Eric Paris   SELinux: standard...
1207
1208
1209
1210
  		if (!dentry)
  			goto out;
  
  		ret = -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1211
  		inode = sel_make_inode(dir->d_sb, S_IFREG | S_IRUGO | S_IWUSR);
b77a493b1   Eric Paris   SELinux: standard...
1212
1213
  		if (!inode)
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1214

b77a493b1   Eric Paris   SELinux: standard...
1215
  		ret = -ENAMETOOLONG;
cc1dad718   Al Viro   selinuxfs snprint...
1216
  		len = snprintf(page, PAGE_SIZE, "/%s/%s", BOOL_DIR_NAME, names[i]);
b77a493b1   Eric Paris   SELinux: standard...
1217
1218
  		if (len >= PAGE_SIZE)
  			goto out;
1872981b5   Eric Paris   SELinux: cleanup ...
1219
1220
1221
  		isec = (struct inode_security_struct *)inode->i_security;
  		ret = security_genfs_sid("selinuxfs", page, SECCLASS_FILE, &sid);
  		if (ret)
b77a493b1   Eric Paris   SELinux: standard...
1222
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1223
1224
1225
  		isec->sid = sid;
  		isec->initialized = 1;
  		inode->i_fop = &sel_bool_ops;
bce34bc0e   James Carter   selinux: change n...
1226
  		inode->i_ino = i|SEL_BOOL_INO_OFFSET;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1227
1228
1229
  		d_add(dentry, inode);
  	}
  	bool_num = num;
d313f9483   Stephen Smalley   SELinux: detect d...
1230
  	bool_pending_names = names;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1231
  	bool_pending_values = values;
b77a493b1   Eric Paris   SELinux: standard...
1232
1233
1234
  
  	free_page((unsigned long)page);
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1235
1236
  out:
  	free_page((unsigned long)page);
b77a493b1   Eric Paris   SELinux: standard...
1237

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1238
  	if (names) {
9a5f04bf7   Jesper Juhl   [PATCH] selinux: ...
1239
1240
  		for (i = 0; i < num; i++)
  			kfree(names[i]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1241
1242
  		kfree(names);
  	}
20c19e417   Davi Arnaut   [PATCH] SELinux: ...
1243
  	kfree(values);
0c92d7c73   Christopher J. PeBenito   selinux: rename s...
1244
  	sel_remove_entries(dir);
b77a493b1   Eric Paris   SELinux: standard...
1245
1246
  
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1247
1248
1249
  }
  
  #define NULL_FILE_NAME "null"
765927b2d   Al Viro   switch dentry_ope...
1250
  struct path selinux_null;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
  
  static ssize_t sel_read_avc_cache_threshold(struct file *filp, char __user *buf,
  					    size_t count, loff_t *ppos)
  {
  	char tmpbuf[TMPBUFLEN];
  	ssize_t length;
  
  	length = scnprintf(tmpbuf, TMPBUFLEN, "%u", avc_cache_threshold);
  	return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
  }
1872981b5   Eric Paris   SELinux: cleanup ...
1261
1262
  static ssize_t sel_write_avc_cache_threshold(struct file *file,
  					     const char __user *buf,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1263
1264
1265
  					     size_t count, loff_t *ppos)
  
  {
b77a493b1   Eric Paris   SELinux: standard...
1266
  	char *page = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1267
1268
  	ssize_t ret;
  	int new_value;
b77a493b1   Eric Paris   SELinux: standard...
1269
1270
  	ret = task_has_security(current, SECURITY__SETSECPARAM);
  	if (ret)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1271
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1272

b77a493b1   Eric Paris   SELinux: standard...
1273
1274
  	ret = -ENOMEM;
  	if (count >= PAGE_SIZE)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1275
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1276

b77a493b1   Eric Paris   SELinux: standard...
1277
1278
1279
1280
1281
1282
  	/* No partial writes. */
  	ret = -EINVAL;
  	if (*ppos != 0)
  		goto out;
  
  	ret = -ENOMEM;
1872981b5   Eric Paris   SELinux: cleanup ...
1283
  	page = (char *)get_zeroed_page(GFP_KERNEL);
b77a493b1   Eric Paris   SELinux: standard...
1284
  	if (!page)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1285
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1286

b77a493b1   Eric Paris   SELinux: standard...
1287
1288
1289
  	ret = -EFAULT;
  	if (copy_from_user(page, buf, count))
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1290

b77a493b1   Eric Paris   SELinux: standard...
1291
1292
  	ret = -EINVAL;
  	if (sscanf(page, "%u", &new_value) != 1)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1293
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1294

b77a493b1   Eric Paris   SELinux: standard...
1295
  	avc_cache_threshold = new_value;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1296
  	ret = count;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1297
  out:
b77a493b1   Eric Paris   SELinux: standard...
1298
  	free_page((unsigned long)page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1299
1300
1301
1302
1303
1304
1305
  	return ret;
  }
  
  static ssize_t sel_read_avc_hash_stats(struct file *filp, char __user *buf,
  				       size_t count, loff_t *ppos)
  {
  	char *page;
b77a493b1   Eric Paris   SELinux: standard...
1306
  	ssize_t length;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1307
1308
  
  	page = (char *)__get_free_page(GFP_KERNEL);
b77a493b1   Eric Paris   SELinux: standard...
1309
1310
1311
1312
1313
1314
  	if (!page)
  		return -ENOMEM;
  
  	length = avc_get_hash_stats(page);
  	if (length >= 0)
  		length = simple_read_from_buffer(buf, count, ppos, page, length);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1315
  	free_page((unsigned long)page);
b77a493b1   Eric Paris   SELinux: standard...
1316
1317
  
  	return length;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1318
  }
9c2e08c59   Arjan van de Ven   [PATCH] mark stru...
1319
  static const struct file_operations sel_avc_cache_threshold_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1320
1321
  	.read		= sel_read_avc_cache_threshold,
  	.write		= sel_write_avc_cache_threshold,
57a62c231   Arnd Bergmann   selinux: use gene...
1322
  	.llseek		= generic_file_llseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1323
  };
9c2e08c59   Arjan van de Ven   [PATCH] mark stru...
1324
  static const struct file_operations sel_avc_hash_stats_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1325
  	.read		= sel_read_avc_hash_stats,
57a62c231   Arnd Bergmann   selinux: use gene...
1326
  	.llseek		= generic_file_llseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1327
1328
1329
1330
1331
1332
  };
  
  #ifdef CONFIG_SECURITY_SELINUX_AVC_STATS
  static struct avc_cache_stats *sel_avc_get_stat_idx(loff_t *idx)
  {
  	int cpu;
4f4b6c1a9   Rusty Russell   cpumask: prepare ...
1333
  	for (cpu = *idx; cpu < nr_cpu_ids; ++cpu) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
  		if (!cpu_possible(cpu))
  			continue;
  		*idx = cpu + 1;
  		return &per_cpu(avc_cache_stats, cpu);
  	}
  	return NULL;
  }
  
  static void *sel_avc_stats_seq_start(struct seq_file *seq, loff_t *pos)
  {
  	loff_t n = *pos - 1;
  
  	if (*pos == 0)
  		return SEQ_START_TOKEN;
  
  	return sel_avc_get_stat_idx(&n);
  }
  
  static void *sel_avc_stats_seq_next(struct seq_file *seq, void *v, loff_t *pos)
  {
  	return sel_avc_get_stat_idx(pos);
  }
  
  static int sel_avc_stats_seq_show(struct seq_file *seq, void *v)
  {
  	struct avc_cache_stats *st = v;
  
  	if (v == SEQ_START_TOKEN)
  		seq_printf(seq, "lookups hits misses allocations reclaims "
  			   "frees
  ");
257313b2a   Linus Torvalds   selinux: avoid un...
1365
1366
1367
1368
1369
1370
1371
  	else {
  		unsigned int lookups = st->lookups;
  		unsigned int misses = st->misses;
  		unsigned int hits = lookups - misses;
  		seq_printf(seq, "%u %u %u %u %u %u
  ", lookups,
  			   hits, misses, st->allocations,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1372
  			   st->reclaims, st->frees);
257313b2a   Linus Torvalds   selinux: avoid un...
1373
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1374
1375
1376
1377
1378
  	return 0;
  }
  
  static void sel_avc_stats_seq_stop(struct seq_file *seq, void *v)
  { }
1996a1094   Jan Engelhardt   security/selinux:...
1379
  static const struct seq_operations sel_avc_cache_stats_seq_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
  	.start		= sel_avc_stats_seq_start,
  	.next		= sel_avc_stats_seq_next,
  	.show		= sel_avc_stats_seq_show,
  	.stop		= sel_avc_stats_seq_stop,
  };
  
  static int sel_open_avc_cache_stats(struct inode *inode, struct file *file)
  {
  	return seq_open(file, &sel_avc_cache_stats_seq_ops);
  }
9c2e08c59   Arjan van de Ven   [PATCH] mark stru...
1390
  static const struct file_operations sel_avc_cache_stats_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1391
1392
1393
1394
1395
1396
1397
1398
1399
  	.open		= sel_open_avc_cache_stats,
  	.read		= seq_read,
  	.llseek		= seq_lseek,
  	.release	= seq_release,
  };
  #endif
  
  static int sel_make_avc_files(struct dentry *dir)
  {
b77a493b1   Eric Paris   SELinux: standard...
1400
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1401
1402
1403
1404
1405
1406
1407
1408
  	static struct tree_descr files[] = {
  		{ "cache_threshold",
  		  &sel_avc_cache_threshold_ops, S_IRUGO|S_IWUSR },
  		{ "hash_stats", &sel_avc_hash_stats_ops, S_IRUGO },
  #ifdef CONFIG_SECURITY_SELINUX_AVC_STATS
  		{ "cache_stats", &sel_avc_cache_stats_ops, S_IRUGO },
  #endif
  	};
6e20a64a3   Nicolas Kaiser   [PATCH] selinux: ...
1409
  	for (i = 0; i < ARRAY_SIZE(files); i++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1410
1411
1412
1413
  		struct inode *inode;
  		struct dentry *dentry;
  
  		dentry = d_alloc_name(dir, files[i].name);
b77a493b1   Eric Paris   SELinux: standard...
1414
1415
  		if (!dentry)
  			return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1416
1417
  
  		inode = sel_make_inode(dir->d_sb, S_IFREG|files[i].mode);
b77a493b1   Eric Paris   SELinux: standard...
1418
1419
  		if (!inode)
  			return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1420
  		inode->i_fop = files[i].ops;
6174eafce   James Carter   selinux: explicit...
1421
  		inode->i_ino = ++sel_last_ino;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1422
1423
  		d_add(dentry, inode);
  	}
b77a493b1   Eric Paris   SELinux: standard...
1424
1425
  
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1426
  }
1872981b5   Eric Paris   SELinux: cleanup ...
1427
  static ssize_t sel_read_initcon(struct file *file, char __user *buf,
f0ee2e467   James Carter   selinux: export i...
1428
1429
  				size_t count, loff_t *ppos)
  {
f0ee2e467   James Carter   selinux: export i...
1430
1431
1432
  	char *con;
  	u32 sid, len;
  	ssize_t ret;
496ad9aa8   Al Viro   new helper: file_...
1433
  	sid = file_inode(file)->i_ino&SEL_INO_MASK;
f0ee2e467   James Carter   selinux: export i...
1434
  	ret = security_sid_to_context(sid, &con, &len);
b77a493b1   Eric Paris   SELinux: standard...
1435
  	if (ret)
f0ee2e467   James Carter   selinux: export i...
1436
1437
1438
1439
1440
1441
1442
1443
1444
  		return ret;
  
  	ret = simple_read_from_buffer(buf, count, ppos, con, len);
  	kfree(con);
  	return ret;
  }
  
  static const struct file_operations sel_initcon_ops = {
  	.read		= sel_read_initcon,
57a62c231   Arnd Bergmann   selinux: use gene...
1445
  	.llseek		= generic_file_llseek,
f0ee2e467   James Carter   selinux: export i...
1446
1447
1448
1449
  };
  
  static int sel_make_initcon_files(struct dentry *dir)
  {
b77a493b1   Eric Paris   SELinux: standard...
1450
  	int i;
f0ee2e467   James Carter   selinux: export i...
1451
1452
1453
1454
1455
  
  	for (i = 1; i <= SECINITSID_NUM; i++) {
  		struct inode *inode;
  		struct dentry *dentry;
  		dentry = d_alloc_name(dir, security_get_initial_sid_context(i));
b77a493b1   Eric Paris   SELinux: standard...
1456
1457
  		if (!dentry)
  			return -ENOMEM;
f0ee2e467   James Carter   selinux: export i...
1458
1459
  
  		inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO);
b77a493b1   Eric Paris   SELinux: standard...
1460
1461
  		if (!inode)
  			return -ENOMEM;
f0ee2e467   James Carter   selinux: export i...
1462
1463
1464
1465
  		inode->i_fop = &sel_initcon_ops;
  		inode->i_ino = i|SEL_INITCON_INO_OFFSET;
  		d_add(dentry, inode);
  	}
b77a493b1   Eric Paris   SELinux: standard...
1466
1467
  
  	return 0;
f0ee2e467   James Carter   selinux: export i...
1468
  }
e47c8fc58   Christopher J. PeBenito   selinux: add seli...
1469
1470
1471
1472
1473
1474
1475
  static inline unsigned long sel_class_to_ino(u16 class)
  {
  	return (class * (SEL_VEC_MAX + 1)) | SEL_CLASS_INO_OFFSET;
  }
  
  static inline u16 sel_ino_to_class(unsigned long ino)
  {
92ae9e82d   Eric Paris   SELinux: remove n...
1476
  	return (ino & SEL_INO_MASK) / (SEL_VEC_MAX + 1);
e47c8fc58   Christopher J. PeBenito   selinux: add seli...
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
  }
  
  static inline unsigned long sel_perm_to_ino(u16 class, u32 perm)
  {
  	return (class * (SEL_VEC_MAX + 1) + perm) | SEL_CLASS_INO_OFFSET;
  }
  
  static inline u32 sel_ino_to_perm(unsigned long ino)
  {
  	return (ino & SEL_INO_MASK) % (SEL_VEC_MAX + 1);
  }
1872981b5   Eric Paris   SELinux: cleanup ...
1488
  static ssize_t sel_read_class(struct file *file, char __user *buf,
e47c8fc58   Christopher J. PeBenito   selinux: add seli...
1489
1490
  				size_t count, loff_t *ppos)
  {
496ad9aa8   Al Viro   new helper: file_...
1491
  	unsigned long ino = file_inode(file)->i_ino;
cc1dad718   Al Viro   selinuxfs snprint...
1492
1493
1494
  	char res[TMPBUFLEN];
  	ssize_t len = snprintf(res, sizeof(res), "%d", sel_ino_to_class(ino));
  	return simple_read_from_buffer(buf, count, ppos, res, len);
e47c8fc58   Christopher J. PeBenito   selinux: add seli...
1495
1496
1497
1498
  }
  
  static const struct file_operations sel_class_ops = {
  	.read		= sel_read_class,
57a62c231   Arnd Bergmann   selinux: use gene...
1499
  	.llseek		= generic_file_llseek,
e47c8fc58   Christopher J. PeBenito   selinux: add seli...
1500
  };
1872981b5   Eric Paris   SELinux: cleanup ...
1501
  static ssize_t sel_read_perm(struct file *file, char __user *buf,
e47c8fc58   Christopher J. PeBenito   selinux: add seli...
1502
1503
  				size_t count, loff_t *ppos)
  {
496ad9aa8   Al Viro   new helper: file_...
1504
  	unsigned long ino = file_inode(file)->i_ino;
cc1dad718   Al Viro   selinuxfs snprint...
1505
1506
1507
  	char res[TMPBUFLEN];
  	ssize_t len = snprintf(res, sizeof(res), "%d", sel_ino_to_perm(ino));
  	return simple_read_from_buffer(buf, count, ppos, res, len);
e47c8fc58   Christopher J. PeBenito   selinux: add seli...
1508
1509
1510
1511
  }
  
  static const struct file_operations sel_perm_ops = {
  	.read		= sel_read_perm,
57a62c231   Arnd Bergmann   selinux: use gene...
1512
  	.llseek		= generic_file_llseek,
e47c8fc58   Christopher J. PeBenito   selinux: add seli...
1513
  };
3bb56b25d   Paul Moore   SELinux: Add a ca...
1514
1515
1516
1517
1518
1519
  static ssize_t sel_read_policycap(struct file *file, char __user *buf,
  				  size_t count, loff_t *ppos)
  {
  	int value;
  	char tmpbuf[TMPBUFLEN];
  	ssize_t length;
496ad9aa8   Al Viro   new helper: file_...
1520
  	unsigned long i_ino = file_inode(file)->i_ino;
3bb56b25d   Paul Moore   SELinux: Add a ca...
1521
1522
1523
1524
1525
1526
1527
1528
1529
  
  	value = security_policycap_supported(i_ino & SEL_INO_MASK);
  	length = scnprintf(tmpbuf, TMPBUFLEN, "%d", value);
  
  	return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
  }
  
  static const struct file_operations sel_policycap_ops = {
  	.read		= sel_read_policycap,
57a62c231   Arnd Bergmann   selinux: use gene...
1530
  	.llseek		= generic_file_llseek,
3bb56b25d   Paul Moore   SELinux: Add a ca...
1531
  };
e47c8fc58   Christopher J. PeBenito   selinux: add seli...
1532
1533
1534
  static int sel_make_perm_files(char *objclass, int classvalue,
  				struct dentry *dir)
  {
b77a493b1   Eric Paris   SELinux: standard...
1535
  	int i, rc, nperms;
e47c8fc58   Christopher J. PeBenito   selinux: add seli...
1536
1537
1538
1539
  	char **perms;
  
  	rc = security_get_permissions(objclass, &perms, &nperms);
  	if (rc)
b77a493b1   Eric Paris   SELinux: standard...
1540
  		return rc;
e47c8fc58   Christopher J. PeBenito   selinux: add seli...
1541
1542
1543
1544
  
  	for (i = 0; i < nperms; i++) {
  		struct inode *inode;
  		struct dentry *dentry;
b77a493b1   Eric Paris   SELinux: standard...
1545
  		rc = -ENOMEM;
e47c8fc58   Christopher J. PeBenito   selinux: add seli...
1546
  		dentry = d_alloc_name(dir, perms[i]);
b77a493b1   Eric Paris   SELinux: standard...
1547
1548
  		if (!dentry)
  			goto out;
e47c8fc58   Christopher J. PeBenito   selinux: add seli...
1549

b77a493b1   Eric Paris   SELinux: standard...
1550
  		rc = -ENOMEM;
e47c8fc58   Christopher J. PeBenito   selinux: add seli...
1551
  		inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO);
b77a493b1   Eric Paris   SELinux: standard...
1552
1553
  		if (!inode)
  			goto out;
e47c8fc58   Christopher J. PeBenito   selinux: add seli...
1554
1555
  		inode->i_fop = &sel_perm_ops;
  		/* i+1 since perm values are 1-indexed */
c1a7368a6   wzt.wzt@gmail.com   Security: Fix cod...
1556
  		inode->i_ino = sel_perm_to_ino(classvalue, i + 1);
e47c8fc58   Christopher J. PeBenito   selinux: add seli...
1557
1558
  		d_add(dentry, inode);
  	}
b77a493b1   Eric Paris   SELinux: standard...
1559
1560
  	rc = 0;
  out:
e47c8fc58   Christopher J. PeBenito   selinux: add seli...
1561
1562
1563
  	for (i = 0; i < nperms; i++)
  		kfree(perms[i]);
  	kfree(perms);
e47c8fc58   Christopher J. PeBenito   selinux: add seli...
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
  	return rc;
  }
  
  static int sel_make_class_dir_entries(char *classname, int index,
  					struct dentry *dir)
  {
  	struct dentry *dentry = NULL;
  	struct inode *inode = NULL;
  	int rc;
  
  	dentry = d_alloc_name(dir, "index");
b77a493b1   Eric Paris   SELinux: standard...
1575
1576
  	if (!dentry)
  		return -ENOMEM;
e47c8fc58   Christopher J. PeBenito   selinux: add seli...
1577
1578
  
  	inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO);
b77a493b1   Eric Paris   SELinux: standard...
1579
1580
  	if (!inode)
  		return -ENOMEM;
e47c8fc58   Christopher J. PeBenito   selinux: add seli...
1581
1582
1583
1584
  
  	inode->i_fop = &sel_class_ops;
  	inode->i_ino = sel_class_to_ino(index);
  	d_add(dentry, inode);
a1c2aa1e8   Al Viro   selinuxfs: merge ...
1585
1586
1587
  	dentry = sel_make_dir(dir, "perms", &last_class_ino);
  	if (IS_ERR(dentry))
  		return PTR_ERR(dentry);
e47c8fc58   Christopher J. PeBenito   selinux: add seli...
1588
1589
  
  	rc = sel_make_perm_files(classname, index, dentry);
e47c8fc58   Christopher J. PeBenito   selinux: add seli...
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
  	return rc;
  }
  
  static void sel_remove_classes(void)
  {
  	struct list_head *class_node;
  
  	list_for_each(class_node, &class_dir->d_subdirs) {
  		struct dentry *class_subdir = list_entry(class_node,
  					struct dentry, d_u.d_child);
  		struct list_head *class_subdir_node;
  
  		list_for_each(class_subdir_node, &class_subdir->d_subdirs) {
  			struct dentry *d = list_entry(class_subdir_node,
  						struct dentry, d_u.d_child);
  
  			if (d->d_inode)
  				if (d->d_inode->i_mode & S_IFDIR)
  					sel_remove_entries(d);
  		}
  
  		sel_remove_entries(class_subdir);
  	}
  
  	sel_remove_entries(class_dir);
  }
  
  static int sel_make_classes(void)
  {
b77a493b1   Eric Paris   SELinux: standard...
1619
  	int rc, nclasses, i;
e47c8fc58   Christopher J. PeBenito   selinux: add seli...
1620
1621
1622
1623
1624
1625
  	char **classes;
  
  	/* delete any existing entries */
  	sel_remove_classes();
  
  	rc = security_get_classes(&classes, &nclasses);
b77a493b1   Eric Paris   SELinux: standard...
1626
1627
  	if (rc)
  		return rc;
e47c8fc58   Christopher J. PeBenito   selinux: add seli...
1628
1629
  
  	/* +2 since classes are 1-indexed */
c1a7368a6   wzt.wzt@gmail.com   Security: Fix cod...
1630
  	last_class_ino = sel_class_to_ino(nclasses + 2);
e47c8fc58   Christopher J. PeBenito   selinux: add seli...
1631
1632
1633
  
  	for (i = 0; i < nclasses; i++) {
  		struct dentry *class_name_dir;
a1c2aa1e8   Al Viro   selinuxfs: merge ...
1634
  		class_name_dir = sel_make_dir(class_dir, classes[i],
e47c8fc58   Christopher J. PeBenito   selinux: add seli...
1635
  				&last_class_ino);
a1c2aa1e8   Al Viro   selinuxfs: merge ...
1636
1637
  		if (IS_ERR(class_name_dir)) {
  			rc = PTR_ERR(class_name_dir);
b77a493b1   Eric Paris   SELinux: standard...
1638
  			goto out;
a1c2aa1e8   Al Viro   selinuxfs: merge ...
1639
  		}
e47c8fc58   Christopher J. PeBenito   selinux: add seli...
1640
1641
  
  		/* i+1 since class values are 1-indexed */
c1a7368a6   wzt.wzt@gmail.com   Security: Fix cod...
1642
  		rc = sel_make_class_dir_entries(classes[i], i + 1,
e47c8fc58   Christopher J. PeBenito   selinux: add seli...
1643
1644
  				class_name_dir);
  		if (rc)
b77a493b1   Eric Paris   SELinux: standard...
1645
  			goto out;
e47c8fc58   Christopher J. PeBenito   selinux: add seli...
1646
  	}
b77a493b1   Eric Paris   SELinux: standard...
1647
1648
  	rc = 0;
  out:
e47c8fc58   Christopher J. PeBenito   selinux: add seli...
1649
1650
1651
  	for (i = 0; i < nclasses; i++)
  		kfree(classes[i]);
  	kfree(classes);
e47c8fc58   Christopher J. PeBenito   selinux: add seli...
1652
1653
  	return rc;
  }
3bb56b25d   Paul Moore   SELinux: Add a ca...
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
  static int sel_make_policycap(void)
  {
  	unsigned int iter;
  	struct dentry *dentry = NULL;
  	struct inode *inode = NULL;
  
  	sel_remove_entries(policycap_dir);
  
  	for (iter = 0; iter <= POLICYDB_CAPABILITY_MAX; iter++) {
  		if (iter < ARRAY_SIZE(policycap_names))
  			dentry = d_alloc_name(policycap_dir,
  					      policycap_names[iter]);
  		else
  			dentry = d_alloc_name(policycap_dir, "unknown");
  
  		if (dentry == NULL)
  			return -ENOMEM;
  
  		inode = sel_make_inode(policycap_dir->d_sb, S_IFREG | S_IRUGO);
  		if (inode == NULL)
  			return -ENOMEM;
  
  		inode->i_fop = &sel_policycap_ops;
  		inode->i_ino = iter | SEL_POLICYCAP_INO_OFFSET;
  		d_add(dentry, inode);
  	}
  
  	return 0;
  }
a1c2aa1e8   Al Viro   selinuxfs: merge ...
1683
  static struct dentry *sel_make_dir(struct dentry *dir, const char *name,
0dd4ae516   Christopher J. PeBenito   selinux: change s...
1684
  			unsigned long *ino)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1685
  {
a1c2aa1e8   Al Viro   selinuxfs: merge ...
1686
  	struct dentry *dentry = d_alloc_name(dir, name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1687
  	struct inode *inode;
a1c2aa1e8   Al Viro   selinuxfs: merge ...
1688
1689
1690
1691
1692
1693
1694
1695
  	if (!dentry)
  		return ERR_PTR(-ENOMEM);
  
  	inode = sel_make_inode(dir->d_sb, S_IFDIR | S_IRUGO | S_IXUGO);
  	if (!inode) {
  		dput(dentry);
  		return ERR_PTR(-ENOMEM);
  	}
b77a493b1   Eric Paris   SELinux: standard...
1696

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1697
1698
  	inode->i_op = &simple_dir_inode_operations;
  	inode->i_fop = &simple_dir_operations;
0dd4ae516   Christopher J. PeBenito   selinux: change s...
1699
  	inode->i_ino = ++(*ino);
40e906f82   James Morris   [PATCH] selinuxfs...
1700
  	/* directory inodes start off with i_nlink == 2 (for "." entry) */
d8c76e6f4   Dave Hansen   [PATCH] r/o bind ...
1701
  	inc_nlink(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1702
  	d_add(dentry, inode);
edb20fb5b   James Morris   [PATCH] SELinux: ...
1703
  	/* bump link count on parent directory, too */
a1c2aa1e8   Al Viro   selinuxfs: merge ...
1704
  	inc_nlink(dir->d_inode);
b77a493b1   Eric Paris   SELinux: standard...
1705

a1c2aa1e8   Al Viro   selinuxfs: merge ...
1706
  	return dentry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1707
  }
1872981b5   Eric Paris   SELinux: cleanup ...
1708
  static int sel_fill_super(struct super_block *sb, void *data, int silent)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1709
1710
1711
  {
  	int ret;
  	struct dentry *dentry;
a1c2aa1e8   Al Viro   selinuxfs: merge ...
1712
  	struct inode *inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1713
1714
1715
1716
1717
  	struct inode_security_struct *isec;
  
  	static struct tree_descr selinux_files[] = {
  		[SEL_LOAD] = {"load", &sel_load_ops, S_IRUSR|S_IWUSR},
  		[SEL_ENFORCE] = {"enforce", &sel_enforce_ops, S_IRUGO|S_IWUSR},
ce9982d04   Stephen Smalley   [PATCH] selinux: ...
1718
  		[SEL_CONTEXT] = {"context", &transaction_ops, S_IRUGO|S_IWUGO},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
  		[SEL_ACCESS] = {"access", &transaction_ops, S_IRUGO|S_IWUGO},
  		[SEL_CREATE] = {"create", &transaction_ops, S_IRUGO|S_IWUGO},
  		[SEL_RELABEL] = {"relabel", &transaction_ops, S_IRUGO|S_IWUGO},
  		[SEL_USER] = {"user", &transaction_ops, S_IRUGO|S_IWUGO},
  		[SEL_POLICYVERS] = {"policyvers", &sel_policyvers_ops, S_IRUGO},
  		[SEL_COMMIT_BOOLS] = {"commit_pending_bools", &sel_commit_bools_ops, S_IWUSR},
  		[SEL_MLS] = {"mls", &sel_mls_ops, S_IRUGO},
  		[SEL_DISABLE] = {"disable", &sel_disable_ops, S_IWUSR},
  		[SEL_MEMBER] = {"member", &transaction_ops, S_IRUGO|S_IWUGO},
  		[SEL_CHECKREQPROT] = {"checkreqprot", &sel_checkreqprot_ops, S_IRUGO|S_IWUSR},
3f12070e2   Eric Paris   SELinux: policy s...
1729
1730
  		[SEL_REJECT_UNKNOWN] = {"reject_unknown", &sel_handle_unknown_ops, S_IRUGO},
  		[SEL_DENY_UNKNOWN] = {"deny_unknown", &sel_handle_unknown_ops, S_IRUGO},
119041672   KaiGai Kohei   selinux: fast sta...
1731
  		[SEL_STATUS] = {"status", &sel_handle_status_ops, S_IRUGO},
72e8c8593   Eric Paris   SELinux: loosen D...
1732
  		[SEL_POLICY] = {"policy", &sel_policy_ops, S_IRUGO},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1733
1734
1735
1736
  		/* last one */ {""}
  	};
  	ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files);
  	if (ret)
161ce45a8   James Morris   [PATCH] selinuxfs...
1737
  		goto err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1738

a1c2aa1e8   Al Viro   selinuxfs: merge ...
1739
1740
1741
1742
  	bool_dir = sel_make_dir(sb->s_root, BOOL_DIR_NAME, &sel_last_ino);
  	if (IS_ERR(bool_dir)) {
  		ret = PTR_ERR(bool_dir);
  		bool_dir = NULL;
161ce45a8   James Morris   [PATCH] selinuxfs...
1743
  		goto err;
a1c2aa1e8   Al Viro   selinuxfs: merge ...
1744
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1745

b77a493b1   Eric Paris   SELinux: standard...
1746
  	ret = -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1747
  	dentry = d_alloc_name(sb->s_root, NULL_FILE_NAME);
b77a493b1   Eric Paris   SELinux: standard...
1748
  	if (!dentry)
161ce45a8   James Morris   [PATCH] selinuxfs...
1749
  		goto err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1750

b77a493b1   Eric Paris   SELinux: standard...
1751
  	ret = -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1752
  	inode = sel_make_inode(sb, S_IFCHR | S_IRUGO | S_IWUGO);
b77a493b1   Eric Paris   SELinux: standard...
1753
  	if (!inode)
161ce45a8   James Morris   [PATCH] selinuxfs...
1754
  		goto err;
b77a493b1   Eric Paris   SELinux: standard...
1755

6174eafce   James Carter   selinux: explicit...
1756
  	inode->i_ino = ++sel_last_ino;
1872981b5   Eric Paris   SELinux: cleanup ...
1757
  	isec = (struct inode_security_struct *)inode->i_security;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1758
1759
1760
1761
1762
1763
  	isec->sid = SECINITSID_DEVNULL;
  	isec->sclass = SECCLASS_CHR_FILE;
  	isec->initialized = 1;
  
  	init_special_inode(inode, S_IFCHR | S_IRUGO | S_IWUGO, MKDEV(MEM_MAJOR, 3));
  	d_add(dentry, inode);
765927b2d   Al Viro   switch dentry_ope...
1764
  	selinux_null.dentry = dentry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1765

a1c2aa1e8   Al Viro   selinuxfs: merge ...
1766
1767
1768
  	dentry = sel_make_dir(sb->s_root, "avc", &sel_last_ino);
  	if (IS_ERR(dentry)) {
  		ret = PTR_ERR(dentry);
161ce45a8   James Morris   [PATCH] selinuxfs...
1769
  		goto err;
a1c2aa1e8   Al Viro   selinuxfs: merge ...
1770
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1771
1772
1773
  
  	ret = sel_make_avc_files(dentry);
  	if (ret)
161ce45a8   James Morris   [PATCH] selinuxfs...
1774
  		goto err;
f0ee2e467   James Carter   selinux: export i...
1775

a1c2aa1e8   Al Viro   selinuxfs: merge ...
1776
1777
1778
  	dentry = sel_make_dir(sb->s_root, "initial_contexts", &sel_last_ino);
  	if (IS_ERR(dentry)) {
  		ret = PTR_ERR(dentry);
f0ee2e467   James Carter   selinux: export i...
1779
  		goto err;
a1c2aa1e8   Al Viro   selinuxfs: merge ...
1780
  	}
f0ee2e467   James Carter   selinux: export i...
1781
1782
1783
1784
  
  	ret = sel_make_initcon_files(dentry);
  	if (ret)
  		goto err;
a1c2aa1e8   Al Viro   selinuxfs: merge ...
1785
1786
1787
1788
  	class_dir = sel_make_dir(sb->s_root, "class", &sel_last_ino);
  	if (IS_ERR(class_dir)) {
  		ret = PTR_ERR(class_dir);
  		class_dir = NULL;
3bb56b25d   Paul Moore   SELinux: Add a ca...
1789
  		goto err;
a1c2aa1e8   Al Viro   selinuxfs: merge ...
1790
  	}
3bb56b25d   Paul Moore   SELinux: Add a ca...
1791

a1c2aa1e8   Al Viro   selinuxfs: merge ...
1792
1793
1794
1795
  	policycap_dir = sel_make_dir(sb->s_root, "policy_capabilities", &sel_last_ino);
  	if (IS_ERR(policycap_dir)) {
  		ret = PTR_ERR(policycap_dir);
  		policycap_dir = NULL;
3bb56b25d   Paul Moore   SELinux: Add a ca...
1796
  		goto err;
a1c2aa1e8   Al Viro   selinuxfs: merge ...
1797
  	}
b77a493b1   Eric Paris   SELinux: standard...
1798
  	return 0;
161ce45a8   James Morris   [PATCH] selinuxfs...
1799
  err:
744ba35e4   Eric Paris   SELinux: clean up...
1800
1801
1802
  	printk(KERN_ERR "SELinux: %s:  failed while creating inodes
  ",
  		__func__);
b77a493b1   Eric Paris   SELinux: standard...
1803
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1804
  }
fc14f2fef   Al Viro   convert get_sb_si...
1805
1806
  static struct dentry *sel_mount(struct file_system_type *fs_type,
  		      int flags, const char *dev_name, void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1807
  {
fc14f2fef   Al Viro   convert get_sb_si...
1808
  	return mount_single(fs_type, flags, data, sel_fill_super);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1809
1810
1811
1812
  }
  
  static struct file_system_type sel_fs_type = {
  	.name		= "selinuxfs",
fc14f2fef   Al Viro   convert get_sb_si...
1813
  	.mount		= sel_mount,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1814
1815
1816
1817
  	.kill_sb	= kill_litter_super,
  };
  
  struct vfsmount *selinuxfs_mount;
7a627e3b9   Greg Kroah-Hartman   SELINUX: add /sys...
1818
  static struct kobject *selinuxfs_kobj;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1819
1820
1821
1822
1823
1824
1825
  
  static int __init init_sel_fs(void)
  {
  	int err;
  
  	if (!selinux_enabled)
  		return 0;
7a627e3b9   Greg Kroah-Hartman   SELINUX: add /sys...
1826
1827
1828
1829
  
  	selinuxfs_kobj = kobject_create_and_add("selinux", fs_kobj);
  	if (!selinuxfs_kobj)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1830
  	err = register_filesystem(&sel_fs_type);
7a627e3b9   Greg Kroah-Hartman   SELINUX: add /sys...
1831
1832
  	if (err) {
  		kobject_put(selinuxfs_kobj);
b77a493b1   Eric Paris   SELinux: standard...
1833
  		return err;
7a627e3b9   Greg Kroah-Hartman   SELINUX: add /sys...
1834
  	}
b77a493b1   Eric Paris   SELinux: standard...
1835

765927b2d   Al Viro   switch dentry_ope...
1836
  	selinux_null.mnt = selinuxfs_mount = kern_mount(&sel_fs_type);
b77a493b1   Eric Paris   SELinux: standard...
1837
1838
1839
1840
1841
  	if (IS_ERR(selinuxfs_mount)) {
  		printk(KERN_ERR "selinuxfs:  could not mount!
  ");
  		err = PTR_ERR(selinuxfs_mount);
  		selinuxfs_mount = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1842
  	}
b77a493b1   Eric Paris   SELinux: standard...
1843

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1844
1845
1846
1847
1848
1849
1850
1851
  	return err;
  }
  
  __initcall(init_sel_fs);
  
  #ifdef CONFIG_SECURITY_SELINUX_DISABLE
  void exit_sel_fs(void)
  {
7a627e3b9   Greg Kroah-Hartman   SELINUX: add /sys...
1852
  	kobject_put(selinuxfs_kobj);
423e0ab08   Tim Chen   VFS : mount lock ...
1853
  	kern_unmount(selinuxfs_mount);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1854
1855
1856
  	unregister_filesystem(&sel_fs_type);
  }
  #endif