aboutsummaryrefslogtreecommitdiffstats
path: root/security/selinux/ss/status.c
diff options
context:
space:
mode:
authorKaiGai Kohei <kaigai@ak.jp.nec.com>2010-09-14 05:28:39 -0400
committerJames Morris <jmorris@namei.org>2010-10-20 19:12:36 -0400
commit119041672592d1890d89dd8f194bd0919d801dc8 (patch)
treeb994abb42446b8637f072194c57359fd80d52a97 /security/selinux/ss/status.c
parent4b04a7cfc5ccb573ca3752429c81d37f8dd2f7c6 (diff)
selinux: fast status update interface (/selinux/status)
This patch provides a new /selinux/status entry which allows applications read-only mmap(2). This region reflects selinux_kernel_status structure in kernel space. struct selinux_kernel_status { u32 length; /* length of this 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 */ }; When userspace object manager caches access control decisions provided by SELinux, it needs to invalidate the cache on policy reload and setenforce to keep consistency. However, the applications need to check the kernel state for each accesses on userspace avc, or launch a background worker process. In heuristic, frequency of invalidation is much less than frequency of making access control decision, so it is annoying to invoke a system call to check we don't need to invalidate the userspace cache. If we can use a background worker thread, it allows to receive invalidation messages from the kernel. But it requires us an invasive coding toward the base application in some cases; E.g, when we provide a feature performing with SELinux as a plugin module, it is unwelcome manner to launch its own worker thread from the module. If we could map /selinux/status to process memory space, application can know updates of selinux status; policy reload or setenforce. A typical application checks selinux_kernel_status::sequence when it tries to reference userspace avc. If it was changed from the last time when it checked userspace avc, it means something was updated in the kernel space. Then, the application can reset userspace avc or update current enforcing mode, without any system call invocations. This sequence number is updated according to the seqlock logic, so we need to wait for a while if it is odd number. Signed-off-by: KaiGai Kohei <kaigai@ak.jp.nec.com> Acked-by: Eric Paris <eparis@redhat.com> -- security/selinux/include/security.h | 21 ++++++ security/selinux/selinuxfs.c | 56 +++++++++++++++ security/selinux/ss/Makefile | 2 +- security/selinux/ss/services.c | 3 + security/selinux/ss/status.c | 129 +++++++++++++++++++++++++++++++++++ 5 files changed, 210 insertions(+), 1 deletions(-) Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/selinux/ss/status.c')
-rw-r--r--security/selinux/ss/status.c129
1 files changed, 129 insertions, 0 deletions
diff --git a/security/selinux/ss/status.c b/security/selinux/ss/status.c
new file mode 100644
index 000000000000..5d9b225f8568
--- /dev/null
+++ b/security/selinux/ss/status.c
@@ -0,0 +1,129 @@
1/*
2 * mmap based event notifications for SELinux
3 *
4 * Author: KaiGai Kohei <kaigai@ak.jp.nec.com>
5 *
6 * Copyright (C) 2010 NEC corporation
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2,
10 * as published by the Free Software Foundation.
11 */
12#include <linux/kernel.h>
13#include <linux/gfp.h>
14#include <linux/mm.h>
15#include <linux/mutex.h>
16#include "avc.h"
17#include "services.h"
18
19/*
20 * The selinux_status_page shall be exposed to userspace applications
21 * using mmap interface on /selinux/status.
22 * It enables to notify applications a few events that will cause reset
23 * of userspace access vector without context switching.
24 *
25 * The selinux_kernel_status structure on the head of status page is
26 * protected from concurrent accesses using seqlock logic, so userspace
27 * application should reference the status page according to the seqlock
28 * logic.
29 *
30 * Typically, application checks status->sequence at the head of access
31 * control routine. If it is odd-number, kernel is updating the status,
32 * so please wait for a moment. If it is changed from the last sequence
33 * number, it means something happen, so application will reset userspace
34 * avc, if needed.
35 * In most cases, application shall confirm the kernel status is not
36 * changed without any system call invocations.
37 */
38static struct page *selinux_status_page = NULL;
39static DEFINE_MUTEX(selinux_status_lock);
40
41/*
42 * selinux_kernel_status_page
43 *
44 * It returns a reference to selinux_status_page. If the status page is
45 * not allocated yet, it also tries to allocate it at the first time.
46 */
47struct page *selinux_kernel_status_page(void)
48{
49 struct selinux_kernel_status *status;
50 struct page *result = NULL;
51
52 mutex_lock(&selinux_status_lock);
53 if (!selinux_status_page)
54 {
55 selinux_status_page = alloc_page(GFP_KERNEL|__GFP_ZERO);
56 if (selinux_status_page)
57 {
58 status = page_address(selinux_status_page);
59
60 status->version = SELINUX_KERNEL_STATUS_VERSION;
61 status->sequence = 0;
62 status->enforcing = selinux_enforcing;
63 /*
64 * NOTE: the next policyload event shall set
65 * a positive value on the status->policyload,
66 * although it may not be 1, but never zero.
67 * So, application can know it was updated.
68 */
69 status->policyload = 0;
70 status->deny_unknown = !security_get_allow_unknown();
71 }
72 }
73 result = selinux_status_page;
74 mutex_unlock(&selinux_status_lock);
75
76 return result;
77}
78
79/*
80 * selinux_status_update_setenforce
81 *
82 * It updates status of the current enforcing/permissive mode.
83 */
84void selinux_status_update_setenforce(int enforcing)
85{
86 struct selinux_kernel_status *status;
87
88 mutex_lock(&selinux_status_lock);
89 if (selinux_status_page)
90 {
91 status = page_address(selinux_status_page);
92
93 status->sequence++;
94 smp_wmb();
95
96 status->enforcing = enforcing;
97
98 smp_wmb();
99 status->sequence++;
100 }
101 mutex_unlock(&selinux_status_lock);
102}
103
104/*
105 * selinux_status_update_policyload
106 *
107 * It updates status of the times of policy reloaded, and current
108 * setting of deny_unknown.
109 */
110void selinux_status_update_policyload(int seqno)
111{
112 struct selinux_kernel_status *status;
113
114 mutex_lock(&selinux_status_lock);
115 if (selinux_status_page)
116 {
117 status = page_address(selinux_status_page);
118
119 status->sequence++;
120 smp_wmb();
121
122 status->policyload = seqno;
123 status->deny_unknown = !security_get_allow_unknown();
124
125 smp_wmb();
126 status->sequence++;
127 }
128 mutex_unlock(&selinux_status_lock);
129}