Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 211666
b: refs/heads/master
c: 1190416
h: refs/heads/master
v: v3
  • Loading branch information
KaiGai Kohei authored and James Morris committed Oct 20, 2010
1 parent fe4f415 commit 204cbf4
Show file tree
Hide file tree
Showing 6 changed files with 211 additions and 2 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 4b04a7cfc5ccb573ca3752429c81d37f8dd2f7c6
refs/heads/master: 119041672592d1890d89dd8f194bd0919d801dc8
21 changes: 21 additions & 0 deletions trunk/security/selinux/include/security.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,5 +191,26 @@ static inline int security_netlbl_sid_to_secattr(u32 sid,

const char *security_get_initial_sid_context(u32 sid);

/*
* status notifier using mmap interface
*/
extern struct page *selinux_kernel_status_page(void);

#define SELINUX_KERNEL_STATUS_VERSION 1
struct selinux_kernel_status
{
u32 version; /* version number of thie structure */
u32 sequence; /* sequence number of seqlock logic */
u32 enforcing; /* current setting of enforcing mode */
u32 policyload; /* times of policy reloaded */
u32 deny_unknown; /* current setting of deny_unknown */
/*
* The version > 0 supports above members.
*/
} __attribute__((packed));

extern void selinux_status_update_setenforce(int enforcing);
extern void selinux_status_update_policyload(int seqno);

#endif /* _SELINUX_SECURITY_H_ */

56 changes: 56 additions & 0 deletions trunk/security/selinux/selinuxfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ enum sel_inos {
SEL_COMPAT_NET, /* whether to use old compat network packet controls */
SEL_REJECT_UNKNOWN, /* export unknown reject handling to userspace */
SEL_DENY_UNKNOWN, /* export unknown deny handling to userspace */
SEL_STATUS, /* export current status using mmap() */
SEL_INO_NEXT, /* The next inode number to use */
};

Expand Down Expand Up @@ -171,6 +172,7 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf,
if (selinux_enforcing)
avc_ss_reset(0);
selnl_notify_setenforce(selinux_enforcing);
selinux_status_update_setenforce(selinux_enforcing);
}
length = count;
out:
Expand Down Expand Up @@ -205,6 +207,59 @@ static const struct file_operations sel_handle_unknown_ops = {
.llseek = generic_file_llseek,
};

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,
};

#ifdef CONFIG_SECURITY_SELINUX_DISABLE
static ssize_t sel_write_disable(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
Expand Down Expand Up @@ -1612,6 +1667,7 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent)
[SEL_CHECKREQPROT] = {"checkreqprot", &sel_checkreqprot_ops, S_IRUGO|S_IWUSR},
[SEL_REJECT_UNKNOWN] = {"reject_unknown", &sel_handle_unknown_ops, S_IRUGO},
[SEL_DENY_UNKNOWN] = {"deny_unknown", &sel_handle_unknown_ops, S_IRUGO},
[SEL_STATUS] = {"status", &sel_handle_status_ops, S_IRUGO},
/* last one */ {""}
};
ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files);
Expand Down
2 changes: 1 addition & 1 deletion trunk/security/selinux/ss/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@
EXTRA_CFLAGS += -Isecurity/selinux -Isecurity/selinux/include
obj-y := ss.o

ss-y := ebitmap.o hashtab.o symtab.o sidtab.o avtab.o policydb.o services.o conditional.o mls.o
ss-y := ebitmap.o hashtab.o symtab.o sidtab.o avtab.o policydb.o services.o conditional.o mls.o status.o

3 changes: 3 additions & 0 deletions trunk/security/selinux/ss/services.c
Original file line number Diff line number Diff line change
Expand Up @@ -1791,6 +1791,7 @@ int security_load_policy(void *data, size_t len)
selinux_complete_init();
avc_ss_reset(seqno);
selnl_notify_policyload(seqno);
selinux_status_update_policyload(seqno);
selinux_netlbl_cache_invalidate();
selinux_xfrm_notify_policyload();
return 0;
Expand Down Expand Up @@ -1870,6 +1871,7 @@ int security_load_policy(void *data, size_t len)

avc_ss_reset(seqno);
selnl_notify_policyload(seqno);
selinux_status_update_policyload(seqno);
selinux_netlbl_cache_invalidate();
selinux_xfrm_notify_policyload();

Expand Down Expand Up @@ -2374,6 +2376,7 @@ int security_set_bools(int len, int *values)
if (!rc) {
avc_ss_reset(seqno);
selnl_notify_policyload(seqno);
selinux_status_update_policyload(seqno);
selinux_xfrm_notify_policyload();
}
return rc;
Expand Down
129 changes: 129 additions & 0 deletions trunk/security/selinux/ss/status.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/*
* mmap based event notifications for SELinux
*
* Author: KaiGai Kohei <kaigai@ak.jp.nec.com>
*
* Copyright (C) 2010 NEC corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/gfp.h>
#include <linux/mm.h>
#include <linux/mutex.h>
#include "avc.h"
#include "services.h"

/*
* The selinux_status_page shall be exposed to userspace applications
* using mmap interface on /selinux/status.
* It enables to notify applications a few events that will cause reset
* of userspace access vector without context switching.
*
* The selinux_kernel_status structure on the head of status page is
* protected from concurrent accesses using seqlock logic, so userspace
* application should reference the status page according to the seqlock
* logic.
*
* Typically, application checks status->sequence at the head of access
* control routine. If it is odd-number, kernel is updating the status,
* so please wait for a moment. If it is changed from the last sequence
* number, it means something happen, so application will reset userspace
* avc, if needed.
* In most cases, application shall confirm the kernel status is not
* changed without any system call invocations.
*/
static struct page *selinux_status_page = NULL;
static DEFINE_MUTEX(selinux_status_lock);

/*
* selinux_kernel_status_page
*
* It returns a reference to selinux_status_page. If the status page is
* not allocated yet, it also tries to allocate it at the first time.
*/
struct page *selinux_kernel_status_page(void)
{
struct selinux_kernel_status *status;
struct page *result = NULL;

mutex_lock(&selinux_status_lock);
if (!selinux_status_page)
{
selinux_status_page = alloc_page(GFP_KERNEL|__GFP_ZERO);
if (selinux_status_page)
{
status = page_address(selinux_status_page);

status->version = SELINUX_KERNEL_STATUS_VERSION;
status->sequence = 0;
status->enforcing = selinux_enforcing;
/*
* NOTE: the next policyload event shall set
* a positive value on the status->policyload,
* although it may not be 1, but never zero.
* So, application can know it was updated.
*/
status->policyload = 0;
status->deny_unknown = !security_get_allow_unknown();
}
}
result = selinux_status_page;
mutex_unlock(&selinux_status_lock);

return result;
}

/*
* selinux_status_update_setenforce
*
* It updates status of the current enforcing/permissive mode.
*/
void selinux_status_update_setenforce(int enforcing)
{
struct selinux_kernel_status *status;

mutex_lock(&selinux_status_lock);
if (selinux_status_page)
{
status = page_address(selinux_status_page);

status->sequence++;
smp_wmb();

status->enforcing = enforcing;

smp_wmb();
status->sequence++;
}
mutex_unlock(&selinux_status_lock);
}

/*
* selinux_status_update_policyload
*
* It updates status of the times of policy reloaded, and current
* setting of deny_unknown.
*/
void selinux_status_update_policyload(int seqno)
{
struct selinux_kernel_status *status;

mutex_lock(&selinux_status_lock);
if (selinux_status_page)
{
status = page_address(selinux_status_page);

status->sequence++;
smp_wmb();

status->policyload = seqno;
status->deny_unknown = !security_get_allow_unknown();

smp_wmb();
status->sequence++;
}
mutex_unlock(&selinux_status_lock);
}

0 comments on commit 204cbf4

Please sign in to comment.