aboutsummaryrefslogtreecommitdiffstats
path: root/security/selinux/selinuxfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/selinux/selinuxfs.c')
-rw-r--r--security/selinux/selinuxfs.c195
1 files changed, 195 insertions, 0 deletions
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 79a1bb635662..87e0556bae70 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -68,6 +68,8 @@ static int *bool_pending_values;
68static struct dentry *class_dir; 68static struct dentry *class_dir;
69static unsigned long last_class_ino; 69static unsigned long last_class_ino;
70 70
71static char policy_opened;
72
71/* global data for policy capabilities */ 73/* global data for policy capabilities */
72static struct dentry *policycap_dir; 74static struct dentry *policycap_dir;
73 75
@@ -110,6 +112,8 @@ enum sel_inos {
110 SEL_COMPAT_NET, /* whether to use old compat network packet controls */ 112 SEL_COMPAT_NET, /* whether to use old compat network packet controls */
111 SEL_REJECT_UNKNOWN, /* export unknown reject handling to userspace */ 113 SEL_REJECT_UNKNOWN, /* export unknown reject handling to userspace */
112 SEL_DENY_UNKNOWN, /* export unknown deny handling to userspace */ 114 SEL_DENY_UNKNOWN, /* export unknown deny handling to userspace */
115 SEL_STATUS, /* export current status using mmap() */
116 SEL_POLICY, /* allow userspace to read the in kernel policy */
113 SEL_INO_NEXT, /* The next inode number to use */ 117 SEL_INO_NEXT, /* The next inode number to use */
114}; 118};
115 119
@@ -171,6 +175,7 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf,
171 if (selinux_enforcing) 175 if (selinux_enforcing)
172 avc_ss_reset(0); 176 avc_ss_reset(0);
173 selnl_notify_setenforce(selinux_enforcing); 177 selnl_notify_setenforce(selinux_enforcing);
178 selinux_status_update_setenforce(selinux_enforcing);
174 } 179 }
175 length = count; 180 length = count;
176out: 181out:
@@ -205,6 +210,59 @@ static const struct file_operations sel_handle_unknown_ops = {
205 .llseek = generic_file_llseek, 210 .llseek = generic_file_llseek,
206}; 211};
207 212
213static int sel_open_handle_status(struct inode *inode, struct file *filp)
214{
215 struct page *status = selinux_kernel_status_page();
216
217 if (!status)
218 return -ENOMEM;
219
220 filp->private_data = status;
221
222 return 0;
223}
224
225static ssize_t sel_read_handle_status(struct file *filp, char __user *buf,
226 size_t count, loff_t *ppos)
227{
228 struct page *status = filp->private_data;
229
230 BUG_ON(!status);
231
232 return simple_read_from_buffer(buf, count, ppos,
233 page_address(status),
234 sizeof(struct selinux_kernel_status));
235}
236
237static int sel_mmap_handle_status(struct file *filp,
238 struct vm_area_struct *vma)
239{
240 struct page *status = filp->private_data;
241 unsigned long size = vma->vm_end - vma->vm_start;
242
243 BUG_ON(!status);
244
245 /* only allows one page from the head */
246 if (vma->vm_pgoff > 0 || size != PAGE_SIZE)
247 return -EIO;
248 /* disallow writable mapping */
249 if (vma->vm_flags & VM_WRITE)
250 return -EPERM;
251 /* disallow mprotect() turns it into writable */
252 vma->vm_flags &= ~VM_MAYWRITE;
253
254 return remap_pfn_range(vma, vma->vm_start,
255 page_to_pfn(status),
256 size, vma->vm_page_prot);
257}
258
259static const struct file_operations sel_handle_status_ops = {
260 .open = sel_open_handle_status,
261 .read = sel_read_handle_status,
262 .mmap = sel_mmap_handle_status,
263 .llseek = generic_file_llseek,
264};
265
208#ifdef CONFIG_SECURITY_SELINUX_DISABLE 266#ifdef CONFIG_SECURITY_SELINUX_DISABLE
209static ssize_t sel_write_disable(struct file *file, const char __user *buf, 267static ssize_t sel_write_disable(struct file *file, const char __user *buf,
210 size_t count, loff_t *ppos) 268 size_t count, loff_t *ppos)
@@ -296,6 +354,141 @@ static const struct file_operations sel_mls_ops = {
296 .llseek = generic_file_llseek, 354 .llseek = generic_file_llseek,
297}; 355};
298 356
357struct policy_load_memory {
358 size_t len;
359 void *data;
360};
361
362static int sel_open_policy(struct inode *inode, struct file *filp)
363{
364 struct policy_load_memory *plm = NULL;
365 int rc;
366
367 BUG_ON(filp->private_data);
368
369 mutex_lock(&sel_mutex);
370
371 rc = task_has_security(current, SECURITY__READ_POLICY);
372 if (rc)
373 goto err;
374
375 rc = -EBUSY;
376 if (policy_opened)
377 goto err;
378
379 rc = -ENOMEM;
380 plm = kzalloc(sizeof(*plm), GFP_KERNEL);
381 if (!plm)
382 goto err;
383
384 if (i_size_read(inode) != security_policydb_len()) {
385 mutex_lock(&inode->i_mutex);
386 i_size_write(inode, security_policydb_len());
387 mutex_unlock(&inode->i_mutex);
388 }
389
390 rc = security_read_policy(&plm->data, &plm->len);
391 if (rc)
392 goto err;
393
394 policy_opened = 1;
395
396 filp->private_data = plm;
397
398 mutex_unlock(&sel_mutex);
399
400 return 0;
401err:
402 mutex_unlock(&sel_mutex);
403
404 if (plm)
405 vfree(plm->data);
406 kfree(plm);
407 return rc;
408}
409
410static int sel_release_policy(struct inode *inode, struct file *filp)
411{
412 struct policy_load_memory *plm = filp->private_data;
413
414 BUG_ON(!plm);
415
416 policy_opened = 0;
417
418 vfree(plm->data);
419 kfree(plm);
420
421 return 0;
422}
423
424static ssize_t sel_read_policy(struct file *filp, char __user *buf,
425 size_t count, loff_t *ppos)
426{
427 struct policy_load_memory *plm = filp->private_data;
428 int ret;
429
430 mutex_lock(&sel_mutex);
431
432 ret = task_has_security(current, SECURITY__READ_POLICY);
433 if (ret)
434 goto out;
435
436 ret = simple_read_from_buffer(buf, count, ppos, plm->data, plm->len);
437out:
438 mutex_unlock(&sel_mutex);
439 return ret;
440}
441
442static int sel_mmap_policy_fault(struct vm_area_struct *vma,
443 struct vm_fault *vmf)
444{
445 struct policy_load_memory *plm = vma->vm_file->private_data;
446 unsigned long offset;
447 struct page *page;
448
449 if (vmf->flags & (FAULT_FLAG_MKWRITE | FAULT_FLAG_WRITE))
450 return VM_FAULT_SIGBUS;
451
452 offset = vmf->pgoff << PAGE_SHIFT;
453 if (offset >= roundup(plm->len, PAGE_SIZE))
454 return VM_FAULT_SIGBUS;
455
456 page = vmalloc_to_page(plm->data + offset);
457 get_page(page);
458
459 vmf->page = page;
460
461 return 0;
462}
463
464static struct vm_operations_struct sel_mmap_policy_ops = {
465 .fault = sel_mmap_policy_fault,
466 .page_mkwrite = sel_mmap_policy_fault,
467};
468
469int sel_mmap_policy(struct file *filp, struct vm_area_struct *vma)
470{
471 if (vma->vm_flags & VM_SHARED) {
472 /* do not allow mprotect to make mapping writable */
473 vma->vm_flags &= ~VM_MAYWRITE;
474
475 if (vma->vm_flags & VM_WRITE)
476 return -EACCES;
477 }
478
479 vma->vm_flags |= VM_RESERVED;
480 vma->vm_ops = &sel_mmap_policy_ops;
481
482 return 0;
483}
484
485static const struct file_operations sel_policy_ops = {
486 .open = sel_open_policy,
487 .read = sel_read_policy,
488 .mmap = sel_mmap_policy,
489 .release = sel_release_policy,
490};
491
299static ssize_t sel_write_load(struct file *file, const char __user *buf, 492static ssize_t sel_write_load(struct file *file, const char __user *buf,
300 size_t count, loff_t *ppos) 493 size_t count, loff_t *ppos)
301 494
@@ -1612,6 +1805,8 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent)
1612 [SEL_CHECKREQPROT] = {"checkreqprot", &sel_checkreqprot_ops, S_IRUGO|S_IWUSR}, 1805 [SEL_CHECKREQPROT] = {"checkreqprot", &sel_checkreqprot_ops, S_IRUGO|S_IWUSR},
1613 [SEL_REJECT_UNKNOWN] = {"reject_unknown", &sel_handle_unknown_ops, S_IRUGO}, 1806 [SEL_REJECT_UNKNOWN] = {"reject_unknown", &sel_handle_unknown_ops, S_IRUGO},
1614 [SEL_DENY_UNKNOWN] = {"deny_unknown", &sel_handle_unknown_ops, S_IRUGO}, 1807 [SEL_DENY_UNKNOWN] = {"deny_unknown", &sel_handle_unknown_ops, S_IRUGO},
1808 [SEL_STATUS] = {"status", &sel_handle_status_ops, S_IRUGO},
1809 [SEL_POLICY] = {"policy", &sel_policy_ops, S_IRUSR},
1615 /* last one */ {""} 1810 /* last one */ {""}
1616 }; 1811 };
1617 ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files); 1812 ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files);