NEWS: Add entry for CVE-2021-27645
[glibc.git] / nscd / selinux.c
blob8123bcd2d9e54cebbf453eb7eb93fd5539990349
1 /* SELinux access controls for nscd.
2 Copyright (C) 2004-2021 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Matthew Rickard <mjricka@epoch.ncsc.mil>, 2004.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, see
18 <https://www.gnu.org/licenses/>. */
20 #include "config.h"
21 #include <error.h>
22 #include <errno.h>
23 #include <libintl.h>
24 #include <pthread.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <syslog.h>
29 #include <unistd.h>
30 #include <sys/prctl.h>
31 #include <selinux/avc.h>
32 #include <selinux/selinux.h>
33 #ifdef HAVE_LIBAUDIT
34 # include <libaudit.h>
35 #endif
36 #include <libc-diag.h>
38 #include "dbg_log.h"
39 #include "selinux.h"
42 #ifdef HAVE_SELINUX
43 /* Global variable to tell if the kernel has SELinux support. */
44 int selinux_enabled;
46 /* Define mappings of request type to AVC permission name. */
47 static const char *perms[LASTREQ] =
49 [GETPWBYNAME] = "getpwd",
50 [GETPWBYUID] = "getpwd",
51 [GETGRBYNAME] = "getgrp",
52 [GETGRBYGID] = "getgrp",
53 [GETHOSTBYNAME] = "gethost",
54 [GETHOSTBYNAMEv6] = "gethost",
55 [GETHOSTBYADDR] = "gethost",
56 [GETHOSTBYADDRv6] = "gethost",
57 [SHUTDOWN] = "admin",
58 [GETSTAT] = "getstat",
59 [INVALIDATE] = "admin",
60 [GETFDPW] = "shmempwd",
61 [GETFDGR] = "shmemgrp",
62 [GETFDHST] = "shmemhost",
63 [GETAI] = "gethost",
64 [INITGROUPS] = "getgrp",
65 [GETSERVBYNAME] = "getserv",
66 [GETSERVBYPORT] = "getserv",
67 [GETFDSERV] = "shmemserv",
68 [GETNETGRENT] = "getnetgrp",
69 [INNETGR] = "getnetgrp",
70 [GETFDNETGR] = "shmemnetgrp",
73 /* Store an entry ref to speed AVC decisions. */
74 static struct avc_entry_ref aeref;
76 /* Thread to listen for SELinux status changes via netlink. */
77 static pthread_t avc_notify_thread;
79 #ifdef HAVE_LIBAUDIT
80 /* Prototype for supporting the audit daemon */
81 static void log_callback (const char *fmt, ...);
82 #endif
84 /* Prototypes for AVC callback functions. */
85 static void *avc_create_thread (void (*run) (void));
86 static void avc_stop_thread (void *thread);
87 static void *avc_alloc_lock (void);
88 static void avc_get_lock (void *lock);
89 static void avc_release_lock (void *lock);
90 static void avc_free_lock (void *lock);
92 /* AVC callback structures for use in avc_init. */
93 static const struct avc_log_callback log_cb =
95 #ifdef HAVE_LIBAUDIT
96 .func_log = log_callback,
97 #else
98 .func_log = dbg_log,
99 #endif
100 .func_audit = NULL
102 static const struct avc_thread_callback thread_cb =
104 .func_create_thread = avc_create_thread,
105 .func_stop_thread = avc_stop_thread
107 static const struct avc_lock_callback lock_cb =
109 .func_alloc_lock = avc_alloc_lock,
110 .func_get_lock = avc_get_lock,
111 .func_release_lock = avc_release_lock,
112 .func_free_lock = avc_free_lock
115 #ifdef HAVE_LIBAUDIT
116 /* The audit system's netlink socket descriptor */
117 static int audit_fd = -1;
119 /* When an avc denial occurs, log it to audit system */
120 static void
121 log_callback (const char *fmt, ...)
123 if (audit_fd >= 0)
125 va_list ap;
126 va_start (ap, fmt);
128 char *buf;
129 int e = vasprintf (&buf, fmt, ap);
130 if (e < 0)
132 buf = alloca (BUFSIZ);
133 vsnprintf (buf, BUFSIZ, fmt, ap);
136 /* FIXME: need to attribute this to real user, using getuid for now */
137 audit_log_user_avc_message (audit_fd, AUDIT_USER_AVC, buf, NULL, NULL,
138 NULL, getuid ());
140 if (e >= 0)
141 free (buf);
143 va_end (ap);
147 /* Initialize the connection to the audit system */
148 static void
149 audit_init (void)
151 audit_fd = audit_open ();
152 if (audit_fd < 0
153 /* If kernel doesn't support audit, bail out */
154 && errno != EINVAL && errno != EPROTONOSUPPORT && errno != EAFNOSUPPORT)
155 dbg_log (_("Failed opening connection to the audit subsystem: %m"));
159 # ifdef HAVE_LIBCAP
160 static const cap_value_t new_cap_list[] =
161 { CAP_AUDIT_WRITE };
162 # define nnew_cap_list (sizeof (new_cap_list) / sizeof (new_cap_list[0]))
163 static const cap_value_t tmp_cap_list[] =
164 { CAP_AUDIT_WRITE, CAP_SETUID, CAP_SETGID };
165 # define ntmp_cap_list (sizeof (tmp_cap_list) / sizeof (tmp_cap_list[0]))
167 cap_t
168 preserve_capabilities (void)
170 if (getuid () != 0)
171 /* Not root, then we cannot preserve anything. */
172 return NULL;
174 if (prctl (PR_SET_KEEPCAPS, 1) == -1)
176 dbg_log (_("Failed to set keep-capabilities"));
177 do_exit (EXIT_FAILURE, errno, _("prctl(KEEPCAPS) failed"));
178 /* NOTREACHED */
181 cap_t tmp_caps = cap_init ();
182 cap_t new_caps = NULL;
183 if (tmp_caps != NULL)
184 new_caps = cap_init ();
186 if (tmp_caps == NULL || new_caps == NULL)
188 if (tmp_caps != NULL)
189 cap_free (tmp_caps);
191 dbg_log (_("Failed to initialize drop of capabilities"));
192 do_exit (EXIT_FAILURE, 0, _("cap_init failed"));
195 /* There is no reason why these should not work. */
196 cap_set_flag (new_caps, CAP_PERMITTED, nnew_cap_list,
197 (cap_value_t *) new_cap_list, CAP_SET);
198 cap_set_flag (new_caps, CAP_EFFECTIVE, nnew_cap_list,
199 (cap_value_t *) new_cap_list, CAP_SET);
201 cap_set_flag (tmp_caps, CAP_PERMITTED, ntmp_cap_list,
202 (cap_value_t *) tmp_cap_list, CAP_SET);
203 cap_set_flag (tmp_caps, CAP_EFFECTIVE, ntmp_cap_list,
204 (cap_value_t *) tmp_cap_list, CAP_SET);
206 int res = cap_set_proc (tmp_caps);
208 cap_free (tmp_caps);
210 if (__glibc_unlikely (res != 0))
212 cap_free (new_caps);
213 dbg_log (_("Failed to drop capabilities"));
214 do_exit (EXIT_FAILURE, 0, _("cap_set_proc failed"));
217 return new_caps;
220 void
221 install_real_capabilities (cap_t new_caps)
223 /* If we have no capabilities there is nothing to do here. */
224 if (new_caps == NULL)
225 return;
227 if (cap_set_proc (new_caps))
229 cap_free (new_caps);
230 dbg_log (_("Failed to drop capabilities"));
231 do_exit (EXIT_FAILURE, 0, _("cap_set_proc failed"));
232 /* NOTREACHED */
235 cap_free (new_caps);
237 if (prctl (PR_SET_KEEPCAPS, 0) == -1)
239 dbg_log (_("Failed to unset keep-capabilities"));
240 do_exit (EXIT_FAILURE, errno, _("prctl(KEEPCAPS) failed"));
241 /* NOTREACHED */
244 # endif /* HAVE_LIBCAP */
245 #endif /* HAVE_LIBAUDIT */
247 /* Determine if we are running on an SELinux kernel. Set selinux_enabled
248 to the result. */
249 void
250 nscd_selinux_enabled (int *selinux_enabled)
252 *selinux_enabled = is_selinux_enabled ();
253 if (*selinux_enabled < 0)
255 dbg_log (_("Failed to determine if kernel supports SELinux"));
256 do_exit (EXIT_FAILURE, 0, NULL);
261 /* Create thread for AVC netlink notification. */
262 static void *
263 avc_create_thread (void (*run) (void))
265 int rc;
267 rc =
268 pthread_create (&avc_notify_thread, NULL, (void *(*) (void *)) run, NULL);
269 if (rc != 0)
270 do_exit (EXIT_FAILURE, rc, _("Failed to start AVC thread"));
272 return &avc_notify_thread;
276 /* Stop AVC netlink thread. */
277 static void
278 avc_stop_thread (void *thread)
280 pthread_cancel (*(pthread_t *) thread);
284 /* Allocate a new AVC lock. */
285 static void *
286 avc_alloc_lock (void)
288 pthread_mutex_t *avc_mutex;
290 avc_mutex = malloc (sizeof (pthread_mutex_t));
291 if (avc_mutex == NULL)
292 do_exit (EXIT_FAILURE, errno, _("Failed to create AVC lock"));
293 pthread_mutex_init (avc_mutex, NULL);
295 return avc_mutex;
299 /* Acquire an AVC lock. */
300 static void
301 avc_get_lock (void *lock)
303 pthread_mutex_lock (lock);
307 /* Release an AVC lock. */
308 static void
309 avc_release_lock (void *lock)
311 pthread_mutex_unlock (lock);
315 /* Free an AVC lock. */
316 static void
317 avc_free_lock (void *lock)
319 pthread_mutex_destroy (lock);
320 free (lock);
324 /* avc_init (along with several other symbols) was marked as deprecated by the
325 SELinux API starting from version 3.1. We use it here, but should
326 eventually switch to the newer API. */
327 DIAG_PUSH_NEEDS_COMMENT
328 DIAG_IGNORE_NEEDS_COMMENT (10, "-Wdeprecated-declarations");
330 /* Initialize the user space access vector cache (AVC) for NSCD along with
331 log/thread/lock callbacks. */
332 void
333 nscd_avc_init (void)
335 avc_entry_ref_init (&aeref);
337 if (avc_init ("avc", NULL, &log_cb, &thread_cb, &lock_cb) < 0)
338 do_exit (EXIT_FAILURE, errno, _("Failed to start AVC"));
339 else
340 dbg_log (_("Access Vector Cache (AVC) started"));
341 #ifdef HAVE_LIBAUDIT
342 audit_init ();
343 #endif
345 DIAG_POP_NEEDS_COMMENT
348 /* security_context_t and sidput (along with several other symbols) were marked
349 as deprecated by the SELinux API starting from version 3.1. We use them
350 here, but should eventually switch to the newer API. */
351 DIAG_PUSH_NEEDS_COMMENT
352 DIAG_IGNORE_NEEDS_COMMENT (10, "-Wdeprecated-declarations");
354 /* Check the permission from the caller (via getpeercon) to nscd.
355 Returns 0 if access is allowed, 1 if denied, and -1 on error.
357 The SELinux policy, enablement, and permission bits are all dynamic and the
358 caching done by glibc is not entirely correct. This nscd support should be
359 rewritten to use selinux_check_permission. A rewrite is risky though and
360 requires some refactoring. Currently we use symbolic mappings instead of
361 compile time constants (which SELinux upstream says are going away), and we
362 use security_deny_unknown to determine what to do if selinux-policy* doesn't
363 have a definition for the the permission or object class we are looking
364 up. */
366 nscd_request_avc_has_perm (int fd, request_type req)
368 /* Initialize to NULL so we know what to free in case of failure. */
369 security_context_t scon = NULL;
370 security_context_t tcon = NULL;
371 security_id_t ssid = NULL;
372 security_id_t tsid = NULL;
373 int rc = -1;
374 security_class_t sc_nscd;
375 access_vector_t perm;
376 int avc_deny_unknown;
378 /* Check if SELinux denys or allows unknown object classes
379 and permissions. It is 0 if they are allowed, 1 if they
380 are not allowed and -1 on error. */
381 if ((avc_deny_unknown = security_deny_unknown ()) == -1)
382 dbg_log (_("Error querying policy for undefined object classes "
383 "or permissions."));
385 /* Get the security class for nscd. If this fails we will likely be
386 unable to do anything unless avc_deny_unknown is 0. */
387 sc_nscd = string_to_security_class ("nscd");
388 if (sc_nscd == 0 && avc_deny_unknown == 1)
389 dbg_log (_("Error getting security class for nscd."));
391 /* Convert permission to AVC bits. */
392 perm = string_to_av_perm (sc_nscd, perms[req]);
393 if (perm == 0 && avc_deny_unknown == 1)
394 dbg_log (_("Error translating permission name "
395 "\"%s\" to access vector bit."), perms[req]);
397 /* If the nscd security class was not found or perms were not
398 found and AVC does not deny unknown values then allow it. */
399 if ((sc_nscd == 0 || perm == 0) && avc_deny_unknown == 0)
400 return 0;
402 if (getpeercon (fd, &scon) < 0)
404 dbg_log (_("Error getting context of socket peer"));
405 goto out;
407 if (getcon (&tcon) < 0)
409 dbg_log (_("Error getting context of nscd"));
410 goto out;
412 if (avc_context_to_sid (scon, &ssid) < 0
413 || avc_context_to_sid (tcon, &tsid) < 0)
415 dbg_log (_("Error getting sid from context"));
416 goto out;
419 /* The SELinux API for avc_has_perm conflates access denied and error into
420 the return code -1, while nscd_request_avs_has_perm has distinct error
421 (-1) and denied (1) return codes. We map the avc_has_perm access denied or
422 error into an access denied at the nscd interface level (we do accurately
423 report error for the getpeercon, getcon, and avc_context_to_sid interfaces
424 used above). */
425 rc = avc_has_perm (ssid, tsid, sc_nscd, perm, &aeref, NULL) < 0;
427 out:
428 if (scon)
429 freecon (scon);
430 if (tcon)
431 freecon (tcon);
432 if (ssid)
433 sidput (ssid);
434 if (tsid)
435 sidput (tsid);
437 return rc;
439 DIAG_POP_NEEDS_COMMENT
442 /* Wrapper to get AVC statistics. */
443 void
444 nscd_avc_cache_stats (struct avc_cache_stats *cstats)
446 avc_cache_stats (cstats);
450 /* Print the AVC statistics to stdout. */
451 void
452 nscd_avc_print_stats (struct avc_cache_stats *cstats)
454 printf (_("\nSELinux AVC Statistics:\n\n"
455 "%15u entry lookups\n"
456 "%15u entry hits\n"
457 "%15u entry misses\n"
458 "%15u entry discards\n"
459 "%15u CAV lookups\n"
460 "%15u CAV hits\n"
461 "%15u CAV probes\n"
462 "%15u CAV misses\n"),
463 cstats->entry_lookups, cstats->entry_hits, cstats->entry_misses,
464 cstats->entry_discards, cstats->cav_lookups, cstats->cav_hits,
465 cstats->cav_probes, cstats->cav_misses);
468 #endif /* HAVE_SELINUX */