]>
Commit | Line | Data |
---|---|---|
bb330e25 AF |
1 | commit 0699f766b10c86912b75f35bef697106b70c1cf6 |
2 | Author: Carlos O'Donell <carlos@redhat.com> | |
3 | Date: Thu Apr 10 18:31:53 2014 -0400 | |
4 | ||
5 | nscd: Make SELinux checks dynamic. | |
6 | ||
7 | The SELinux team has indicated to me that glibc's SELinux checks | |
8 | in nscd are not being carried out as they would expect the API | |
9 | to be used today. They would like to move away from static header | |
10 | defines for class and permissions and instead use dynamic checks | |
11 | at runtime that provide an answer which is dependent on the runtime | |
12 | status of SELinux i.e. more dynamic. | |
13 | ||
14 | The following patch is a minimal change that moves us forward in | |
15 | this direction. | |
16 | ||
17 | It does the following: | |
18 | ||
19 | * Stop checking for SELinux headers that define NSCD__SHMEMHOST. | |
20 | Check only for the presence or absence of the library. | |
21 | ||
22 | * Don't encode the specific SELinux permission constants into a | |
23 | table at build time, and instead use the symbolic name for the | |
24 | permission as expected. | |
25 | ||
26 | * Lookup the "What do we do if we don't know this permission?" | |
27 | policy and use that if we find SELinux's policy is older than | |
28 | the glibc policy e.g. we make a request for a permission that | |
29 | SELinux doesn't know about. | |
30 | ||
31 | * Lastly, translate the class and permission and then make | |
32 | the permission check. This is done every time we lookup | |
33 | a permission, and this is the expected way to use the API. | |
34 | SELinux will optimize this for us, and we expect the network | |
35 | latencies to hide these extra library calls. | |
36 | ||
37 | Tested on x86, x86-64, and via Fedora Rawhide since November 2013. | |
38 | ||
39 | See: | |
40 | https://sourceware.org/ml/libc-alpha/2014-04/msg00179.html | |
41 | ||
42 | diff --git a/configure b/configure | |
43 | index abefcdb..8b0b222 100755 | |
44 | --- a/configure | |
45 | +++ b/configure | |
46 | @@ -7774,64 +7774,10 @@ else | |
47 | have_selinux=no | |
48 | fi | |
49 | ||
50 | - # See if we have the SELinux header with the NSCD permissions in it. | |
51 | - if test x$have_selinux = xyes ; then | |
52 | - { $as_echo "$as_me:$LINENO: checking for NSCD Flask permissions in selinux/av_permissions.h" >&5 | |
53 | -$as_echo_n "checking for NSCD Flask permissions in selinux/av_permissions.h... " >&6; } | |
54 | - cat >conftest.$ac_ext <<_ACEOF | |
55 | -/* confdefs.h. */ | |
56 | -_ACEOF | |
57 | -cat confdefs.h >>conftest.$ac_ext | |
58 | -cat >>conftest.$ac_ext <<_ACEOF | |
59 | -/* end confdefs.h. */ | |
60 | -#include <selinux/av_permissions.h> | |
61 | -int | |
62 | -main () | |
63 | -{ | |
64 | -#ifdef NSCD__SHMEMHOST | |
65 | - return 0; | |
66 | - #else | |
67 | - #error NSCD__SHMEMHOST not defined | |
68 | - #endif | |
69 | - ; | |
70 | - return 0; | |
71 | -} | |
72 | -_ACEOF | |
73 | -rm -f conftest.$ac_objext | |
74 | -if { (ac_try="$ac_compile" | |
75 | -case "(($ac_try" in | |
76 | - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; | |
77 | - *) ac_try_echo=$ac_try;; | |
78 | -esac | |
79 | -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" | |
80 | -$as_echo "$ac_try_echo") >&5 | |
81 | - (eval "$ac_compile") 2>conftest.er1 | |
82 | - ac_status=$? | |
83 | - grep -v '^ *+' conftest.er1 >conftest.err | |
84 | - rm -f conftest.er1 | |
85 | - cat conftest.err >&5 | |
86 | - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 | |
87 | - (exit $ac_status); } && { | |
88 | - test -z "$ac_c_werror_flag" || | |
89 | - test ! -s conftest.err | |
90 | - } && test -s conftest.$ac_objext; then | |
91 | - have_selinux=yes | |
92 | -else | |
93 | - $as_echo "$as_me: failed program was:" >&5 | |
94 | -sed 's/^/| /' conftest.$ac_ext >&5 | |
95 | - | |
96 | - have_selinux=no | |
97 | -fi | |
98 | - | |
99 | -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext | |
100 | - { $as_echo "$as_me:$LINENO: result: $have_selinux" >&5 | |
101 | -$as_echo "$have_selinux" >&6; } | |
102 | - fi | |
103 | - | |
104 | if test x$with_selinux = xyes ; then | |
105 | if test x$have_selinux = xno ; then | |
106 | - { { $as_echo "$as_me:$LINENO: error: SELinux explicitly required, but sufficiently recent SELinux library not found" >&5 | |
107 | -$as_echo "$as_me: error: SELinux explicitly required, but sufficiently recent SELinux library not found" >&2;} | |
108 | + { { $as_echo "$as_me:$LINENO: error: SELinux explicitly required, but SELinux library not found" >&5 | |
109 | +$as_echo "$as_me: error: SELinux explicitly required, but SELinux library not found" >&2;} | |
110 | { (exit 1); exit 1; }; } | |
111 | fi | |
112 | fi | |
113 | diff --git a/configure.in b/configure.in | |
114 | index 6291872..97a9591 100644 | |
115 | --- a/configure.in | |
116 | +++ b/configure.in | |
117 | @@ -1945,22 +1945,9 @@ else | |
118 | # See if we have the SELinux library | |
119 | AC_CHECK_LIB(selinux, is_selinux_enabled, | |
120 | have_selinux=yes, have_selinux=no) | |
121 | - # See if we have the SELinux header with the NSCD permissions in it. | |
122 | - if test x$have_selinux = xyes ; then | |
123 | - AC_MSG_CHECKING([for NSCD Flask permissions in selinux/av_permissions.h]) | |
124 | - AC_TRY_COMPILE([#include <selinux/av_permissions.h>], | |
125 | - [#ifdef NSCD__SHMEMHOST | |
126 | - return 0; | |
127 | - #else | |
128 | - #error NSCD__SHMEMHOST not defined | |
129 | - #endif], | |
130 | - have_selinux=yes, have_selinux=no) | |
131 | - AC_MSG_RESULT($have_selinux) | |
132 | - fi | |
133 | - | |
134 | if test x$with_selinux = xyes ; then | |
135 | if test x$have_selinux = xno ; then | |
136 | - AC_MSG_ERROR([SELinux explicitly required, but sufficiently recent SELinux library not found]) | |
137 | + AC_MSG_ERROR([SELinux explicitly required, but SELinux library not found]) | |
138 | fi | |
139 | fi | |
140 | fi | |
141 | diff --git a/nscd/selinux.c b/nscd/selinux.c | |
142 | index 46b0ea9..9a8a5a8 100644 | |
143 | --- a/nscd/selinux.c | |
144 | +++ b/nscd/selinux.c | |
145 | @@ -28,7 +28,6 @@ | |
146 | #include <syslog.h> | |
147 | #include <unistd.h> | |
148 | #include <sys/prctl.h> | |
149 | -#include <selinux/av_permissions.h> | |
150 | #include <selinux/avc.h> | |
151 | #include <selinux/flask.h> | |
152 | #include <selinux/selinux.h> | |
153 | @@ -44,35 +43,31 @@ | |
154 | /* Global variable to tell if the kernel has SELinux support. */ | |
155 | int selinux_enabled; | |
156 | ||
157 | -/* Define mappings of access vector permissions to request types. */ | |
158 | -static const access_vector_t perms[LASTREQ] = | |
159 | +/* Define mappings of request type to AVC permission name. */ | |
160 | +static const char *perms[LASTREQ] = | |
161 | { | |
162 | - [GETPWBYNAME] = NSCD__GETPWD, | |
163 | - [GETPWBYUID] = NSCD__GETPWD, | |
164 | - [GETGRBYNAME] = NSCD__GETGRP, | |
165 | - [GETGRBYGID] = NSCD__GETGRP, | |
166 | - [GETHOSTBYNAME] = NSCD__GETHOST, | |
167 | - [GETHOSTBYNAMEv6] = NSCD__GETHOST, | |
168 | - [GETHOSTBYADDR] = NSCD__GETHOST, | |
169 | - [GETHOSTBYADDRv6] = NSCD__GETHOST, | |
170 | - [GETSTAT] = NSCD__GETSTAT, | |
171 | - [SHUTDOWN] = NSCD__ADMIN, | |
172 | - [INVALIDATE] = NSCD__ADMIN, | |
173 | - [GETFDPW] = NSCD__SHMEMPWD, | |
174 | - [GETFDGR] = NSCD__SHMEMGRP, | |
175 | - [GETFDHST] = NSCD__SHMEMHOST, | |
176 | - [GETAI] = NSCD__GETHOST, | |
177 | - [INITGROUPS] = NSCD__GETGRP, | |
178 | -#ifdef NSCD__GETSERV | |
179 | - [GETSERVBYNAME] = NSCD__GETSERV, | |
180 | - [GETSERVBYPORT] = NSCD__GETSERV, | |
181 | - [GETFDSERV] = NSCD__SHMEMSERV, | |
182 | -#endif | |
183 | -#ifdef NSCD__GETNETGRP | |
184 | - [GETNETGRENT] = NSCD__GETNETGRP, | |
185 | - [INNETGR] = NSCD__GETNETGRP, | |
186 | - [GETFDNETGR] = NSCD__SHMEMNETGRP, | |
187 | -#endif | |
188 | + [GETPWBYNAME] = "getpwd", | |
189 | + [GETPWBYUID] = "getpwd", | |
190 | + [GETGRBYNAME] = "getgrp", | |
191 | + [GETGRBYGID] = "getgrp", | |
192 | + [GETHOSTBYNAME] = "gethost", | |
193 | + [GETHOSTBYNAMEv6] = "gethost", | |
194 | + [GETHOSTBYADDR] = "gethost", | |
195 | + [GETHOSTBYADDRv6] = "gethost", | |
196 | + [SHUTDOWN] = "admin", | |
197 | + [GETSTAT] = "getstat", | |
198 | + [INVALIDATE] = "admin", | |
199 | + [GETFDPW] = "shmempwd", | |
200 | + [GETFDGR] = "shmemgrp", | |
201 | + [GETFDHST] = "shmemhost", | |
202 | + [GETAI] = "gethost", | |
203 | + [INITGROUPS] = "getgrp", | |
204 | + [GETSERVBYNAME] = "getserv", | |
205 | + [GETSERVBYPORT] = "getserv", | |
206 | + [GETFDSERV] = "shmemserv", | |
207 | + [GETNETGRENT] = "getnetgrp", | |
208 | + [INNETGR] = "getnetgrp", | |
209 | + [GETFDNETGR] = "shmemnetgrp", | |
210 | }; | |
211 | ||
212 | /* Store an entry ref to speed AVC decisions. */ | |
213 | @@ -344,7 +339,16 @@ nscd_avc_init (void) | |
214 | ||
215 | ||
216 | /* Check the permission from the caller (via getpeercon) to nscd. | |
217 | - Returns 0 if access is allowed, 1 if denied, and -1 on error. */ | |
218 | + Returns 0 if access is allowed, 1 if denied, and -1 on error. | |
219 | + | |
220 | + The SELinux policy, enablement, and permission bits are all dynamic and the | |
221 | + caching done by glibc is not entirely correct. This nscd support should be | |
222 | + rewritten to use selinux_check_permission. A rewrite is risky though and | |
223 | + requires some refactoring. Currently we use symbolic mappings instead of | |
224 | + compile time constants (which SELinux upstream says are going away), and we | |
225 | + use security_deny_unknown to determine what to do if selinux-policy* doesn't | |
226 | + have a definition for the the permission or object class we are looking | |
227 | + up. */ | |
228 | int | |
229 | nscd_request_avc_has_perm (int fd, request_type req) | |
230 | { | |
231 | @@ -354,6 +358,33 @@ nscd_request_avc_has_perm (int fd, request_type req) | |
232 | security_id_t ssid = NULL; | |
233 | security_id_t tsid = NULL; | |
234 | int rc = -1; | |
235 | + security_class_t sc_nscd; | |
236 | + access_vector_t perm; | |
237 | + int avc_deny_unknown; | |
238 | + | |
239 | + /* Check if SELinux denys or allows unknown object classes | |
240 | + and permissions. It is 0 if they are allowed, 1 if they | |
241 | + are not allowed and -1 on error. */ | |
242 | + if ((avc_deny_unknown = security_deny_unknown ()) == -1) | |
243 | + dbg_log (_("Error querying policy for undefined object classes " | |
244 | + "or permissions.")); | |
245 | + | |
246 | + /* Get the security class for nscd. If this fails we will likely be | |
247 | + unable to do anything unless avc_deny_unknown is 0. */ | |
248 | + sc_nscd = string_to_security_class ("nscd"); | |
249 | + if (perm == 0 && avc_deny_unknown == 1) | |
250 | + dbg_log (_("Error getting security class for nscd.")); | |
251 | + | |
252 | + /* Convert permission to AVC bits. */ | |
253 | + perm = string_to_av_perm (sc_nscd, perms[req]); | |
254 | + if (perm == 0 && avc_deny_unknown == 1) | |
255 | + dbg_log (_("Error translating permission name " | |
256 | + "\"%s\" to access vector bit."), perms[req]); | |
257 | + | |
258 | + /* If the nscd security class was not found or perms were not | |
259 | + found and AVC does not deny unknown values then allow it. */ | |
260 | + if ((sc_nscd == 0 || perm == 0) && avc_deny_unknown == 0) | |
261 | + return 0; | |
262 | ||
263 | if (getpeercon (fd, &scon) < 0) | |
264 | { | |
265 | @@ -372,15 +403,13 @@ nscd_request_avc_has_perm (int fd, request_type req) | |
266 | goto out; | |
267 | } | |
268 | ||
269 | -#ifndef NSCD__GETSERV | |
270 | - if (perms[req] == 0) | |
271 | - { | |
272 | - dbg_log (_("compile-time support for database policy missing")); | |
273 | - goto out; | |
274 | - } | |
275 | -#endif | |
276 | - | |
277 | - rc = avc_has_perm (ssid, tsid, SECCLASS_NSCD, perms[req], &aeref, NULL) < 0; | |
278 | + /* The SELinux API for avc_has_perm conflates access denied and error into | |
279 | + the return code -1, while nscd_request_avs_has_perm has distinct error | |
280 | + (-1) and denied (1) return codes. We map the avc_has_perm access denied or | |
281 | + error into an access denied at the nscd interface level (we do accurately | |
282 | + report error for the getpeercon, getcon, and avc_context_to_sid interfaces | |
283 | + used above). */ | |
284 | + rc = avc_has_perm (ssid, tsid, sc_nscd, perm, &aeref, NULL) < 0; | |
285 | ||
286 | out: | |
287 | if (scon) |