1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21: #include "config.h"
22: #include <error.h>
23: #include <errno.h>
24: #include <libintl.h>
25: #include <pthread.h>
26: #include <stdarg.h>
27: #include <stdio.h>
28: #include <stdlib.h>
29: #include <syslog.h>
30: #include <unistd.h>
31: #include <sys/prctl.h>
32: #include <selinux/av_permissions.h>
33: #include <selinux/avc.h>
34: #include <selinux/flask.h>
35: #include <selinux/selinux.h>
36: #ifdef HAVE_LIBAUDIT
37: # include <libaudit.h>
38: #endif
39:
40: #include "dbg_log.h"
41: #include "selinux.h"
42:
43:
44: #ifdef HAVE_SELINUX
45:
46: int selinux_enabled;
47:
48:
49: static const int perms[LASTREQ] =
50: {
51: [GETPWBYNAME] = NSCD__GETPWD,
52: [GETPWBYUID] = NSCD__GETPWD,
53: [GETGRBYNAME] = NSCD__GETGRP,
54: [GETGRBYGID] = NSCD__GETGRP,
55: [GETHOSTBYNAME] = NSCD__GETHOST,
56: [GETHOSTBYNAMEv6] = NSCD__GETHOST,
57: [GETHOSTBYADDR] = NSCD__GETHOST,
58: [GETHOSTBYADDRv6] = NSCD__GETHOST,
59: [GETSTAT] = NSCD__GETSTAT,
60: [SHUTDOWN] = NSCD__ADMIN,
61: [INVALIDATE] = NSCD__ADMIN,
62: [GETFDPW] = NSCD__SHMEMPWD,
63: [GETFDGR] = NSCD__SHMEMGRP,
64: [GETFDHST] = NSCD__SHMEMHOST,
65: [GETAI] = NSCD__GETHOST,
66: [INITGROUPS] = NSCD__GETGRP,
67: #ifdef NSCD__GETSERV
68: [GETSERVBYNAME] = NSCD__GETSERV,
69: [GETSERVBYPORT] = NSCD__GETSERV,
70: [GETFDSERV] = NSCD__SHMEMSERV,
71: #endif
72: };
73:
74:
75: static struct avc_entry_ref aeref;
76:
77:
78: static pthread_t avc_notify_thread;
79:
80: #ifdef HAVE_LIBAUDIT
81:
82: static void log_callback (const char *fmt, ...);
83: #endif
84:
85:
86: static void *avc_create_thread (void (*run) (void));
87: static void avc_stop_thread (void *thread);
88: static void *avc_alloc_lock (void);
89: static void avc_get_lock (void *lock);
90: static void avc_release_lock (void *lock);
91: static void avc_free_lock (void *lock);
92:
93:
94: static const struct avc_log_callback log_cb =
95: {
96: #ifdef HAVE_LIBAUDIT
97: .func_log = log_callback,
98: #else
99: .func_log = dbg_log,
100: #endif
101: .func_audit = NULL
102: };
103: static const struct avc_thread_callback thread_cb =
104: {
105: .func_create_thread = avc_create_thread,
106: .func_stop_thread = avc_stop_thread
107: };
108: static const struct avc_lock_callback lock_cb =
109: {
110: .func_alloc_lock = avc_alloc_lock,
111: .func_get_lock = avc_get_lock,
112: .func_release_lock = avc_release_lock,
113: .func_free_lock = avc_free_lock
114: };
115:
116: #ifdef HAVE_LIBAUDIT
117:
118: static int audit_fd = -1;
119:
120:
121: static void
122: log_callback (const char *fmt, ...)
123: {
124: if (audit_fd >= 0)
125: {
126: va_list ap;
127: va_start (ap, fmt);
128:
129: char *buf;
130: int e = vasprintf (&buf, fmt, ap);
131: if (e < 0)
132: {
133: buf = alloca (BUFSIZ);
134: vsnprintf (buf, BUFSIZ, fmt, ap);
135: }
136:
137:
138: audit_log_user_avc_message (audit_fd, AUDIT_USER_AVC, buf, NULL, NULL,
139: NULL, getuid ());
140:
141: if (e >= 0)
142: free (buf);
143:
144: va_end (ap);
145: }
146: }
147:
148:
149: static void
150: audit_init (void)
151: {
152: audit_fd = audit_open ();
153: if (audit_fd < 0
154:
155: && errno != EINVAL && errno != EPROTONOSUPPORT && errno != EAFNOSUPPORT)
156: dbg_log (_("Failed opening connection to the audit subsystem: %m"));
157: }
158:
159:
160: # ifdef HAVE_LIBCAP
161: static const cap_value_t new_cap_list[] =
162: { CAP_AUDIT_WRITE };
163: # define nnew_cap_list (sizeof (new_cap_list) / sizeof (new_cap_list[0]))
164: static const cap_value_t tmp_cap_list[] =
165: { CAP_AUDIT_WRITE, CAP_SETUID, CAP_SETGID };
166: # define ntmp_cap_list (sizeof (tmp_cap_list) / sizeof (tmp_cap_list[0]))
167:
168: cap_t
169: preserve_capabilities (void)
170: {
171: if (getuid () != 0)
172:
173: return NULL;
174:
175: if (prctl (PR_SET_KEEPCAPS, 1) == -1)
176: {
177: dbg_log (_("Failed to set keep-capabilities"));
178: error (EXIT_FAILURE, errno, _("prctl(KEEPCAPS) failed"));
179:
180: }
181:
182: cap_t tmp_caps = cap_init ();
183: cap_t new_caps = NULL;
184: if (tmp_caps != NULL)
185: new_caps = cap_init ();
186:
187: if (tmp_caps == NULL || new_caps == NULL)
188: {
189: if (tmp_caps != NULL)
190: cap_free (tmp_caps);
191:
192: dbg_log (_("Failed to initialize drop of capabilities"));
193: error (EXIT_FAILURE, 0, _("cap_init failed"));
194: }
195:
196:
197: cap_set_flag (new_caps, CAP_PERMITTED, nnew_cap_list,
198: (cap_value_t *) new_cap_list, CAP_SET);
199: cap_set_flag (new_caps, CAP_EFFECTIVE, nnew_cap_list,
200: (cap_value_t *) new_cap_list, CAP_SET);
201:
202: cap_set_flag (tmp_caps, CAP_PERMITTED, ntmp_cap_list,
203: (cap_value_t *) tmp_cap_list, CAP_SET);
204: cap_set_flag (tmp_caps, CAP_EFFECTIVE, ntmp_cap_list,
205: (cap_value_t *) tmp_cap_list, CAP_SET);
206:
207: int res = cap_set_proc (tmp_caps);
208:
209: cap_free (tmp_caps);
210:
211: if (__builtin_expect (res != 0, 0))
212: {
213: cap_free (new_caps);
214: dbg_log (_("Failed to drop capabilities"));
215: error (EXIT_FAILURE, 0, _("cap_set_proc failed"));
216: }
217:
218: return new_caps;
219: }
220:
221: void
222: install_real_capabilities (cap_t new_caps)
223: {
224:
225: if (new_caps == NULL)
226: return;
227:
228: if (cap_set_proc (new_caps))
229: {
230: cap_free (new_caps);
231: dbg_log (_("Failed to drop capabilities"));
232: error (EXIT_FAILURE, 0, _("cap_set_proc failed"));
233:
234: }
235:
236: cap_free (new_caps);
237:
238: if (prctl (PR_SET_KEEPCAPS, 0) == -1)
239: {
240: dbg_log (_("Failed to unset keep-capabilities"));
241: error (EXIT_FAILURE, errno, _("prctl(KEEPCAPS) failed"));
242:
243: }
244: }
245: # endif
246: #endif
247:
248:
249:
250: void
251: nscd_selinux_enabled (int *selinux_enabled)
252: {
253: *selinux_enabled = is_selinux_enabled ();
254: if (*selinux_enabled < 0)
255: {
256: dbg_log (_("Failed to determine if kernel supports SELinux"));
257: exit (EXIT_FAILURE);
258: }
259: }
260:
261:
262:
263: static void *
264: avc_create_thread (void (*run) (void))
265: {
266: int rc;
267:
268: rc =
269: pthread_create (&avc_notify_thread, NULL, (void *(*) (void *)) run, NULL);
270: if (rc != 0)
271: error (EXIT_FAILURE, rc, _("Failed to start AVC thread"));
272:
273: return &avc_notify_thread;
274: }
275:
276:
277:
278: static void
279: avc_stop_thread (void *thread)
280: {
281: pthread_cancel (*(pthread_t *) thread);
282: }
283:
284:
285:
286: static void *
287: avc_alloc_lock (void)
288: {
289: pthread_mutex_t *avc_mutex;
290:
291: avc_mutex = malloc (sizeof (pthread_mutex_t));
292: if (avc_mutex == NULL)
293: error (EXIT_FAILURE, errno, _("Failed to create AVC lock"));
294: pthread_mutex_init (avc_mutex, NULL);
295:
296: return avc_mutex;
297: }
298:
299:
300:
301: static void
302: avc_get_lock (void *lock)
303: {
304: pthread_mutex_lock (lock);
305: }
306:
307:
308:
309: static void
310: avc_release_lock (void *lock)
311: {
312: pthread_mutex_unlock (lock);
313: }
314:
315:
316:
317: static void
318: avc_free_lock (void *lock)
319: {
320: pthread_mutex_destroy (lock);
321: free (lock);
322: }
323:
324:
325:
326:
327: void
328: nscd_avc_init (void)
329: {
330: avc_entry_ref_init (&aeref);
331:
332: if (avc_init ("avc", NULL, &log_cb, &thread_cb, &lock_cb) < 0)
333: error (EXIT_FAILURE, errno, _("Failed to start AVC"));
334: else
335: dbg_log (_("Access Vector Cache (AVC) started"));
336: #ifdef HAVE_LIBAUDIT
337: audit_init ();
338: #endif
339: }
340:
341:
342:
343:
344: int
345: nscd_request_avc_has_perm (int fd, request_type req)
346: {
347:
348: security_context_t scon = NULL;
349: security_context_t tcon = NULL;
350: security_id_t ssid = NULL;
351: security_id_t tsid = NULL;
352: int rc = -1;
353:
354: if (getpeercon (fd, &scon) < 0)
355: {
356: dbg_log (_("Error getting context of socket peer"));
357: goto out;
358: }
359: if (getcon (&tcon) < 0)
360: {
361: dbg_log (_("Error getting context of nscd"));
362: goto out;
363: }
364: if (avc_context_to_sid (scon, &ssid) < 0
365: || avc_context_to_sid (tcon, &tsid) < 0)
366: {
367: dbg_log (_("Error getting sid from context"));
368: goto out;
369: }
370:
371: rc = avc_has_perm (ssid, tsid, SECCLASS_NSCD, perms[req], &aeref, NULL) < 0;
372:
373: out:
374: if (scon)
375: freecon (scon);
376: if (tcon)
377: freecon (tcon);
378: if (ssid)
379: sidput (ssid);
380: if (tsid)
381: sidput (tsid);
382:
383: return rc;
384: }
385:
386:
387:
388: void
389: nscd_avc_cache_stats (struct avc_cache_stats *cstats)
390: {
391: avc_cache_stats (cstats);
392: }
393:
394:
395:
396: void
397: nscd_avc_print_stats (struct avc_cache_stats *cstats)
398: {
399: printf (_("\nSELinux AVC Statistics:\n\n"
400: "%15u entry lookups\n"
401: "%15u entry hits\n"
402: "%15u entry misses\n"
403: "%15u entry discards\n"
404: "%15u CAV lookups\n"
405: "%15u CAV hits\n"
406: "%15u CAV probes\n"
407: "%15u CAV misses\n"),
408: cstats->entry_lookups, cstats->entry_hits, cstats->entry_misses,
409: cstats->entry_discards, cstats->cav_lookups, cstats->cav_hits,
410: cstats->cav_probes, cstats->cav_misses);
411: }
412:
413:
414:
415: void
416: nscd_avc_destroy (void)
417: {
418: avc_destroy ();
419: #ifdef HAVE_LIBAUDIT
420: audit_close (audit_fd);
421: #endif
422: }
423:
424: #endif