Skip to content
Navigation Menu
Toggle navigation
Sign in
In this repository
All GitHub Enterprise
↵
Jump to
↵
No suggested jump to results
In this repository
All GitHub Enterprise
↵
Jump to
↵
In this organization
All GitHub Enterprise
↵
Jump to
↵
In this repository
All GitHub Enterprise
↵
Jump to
↵
Sign in
Reseting focus
You signed in with another tab or window.
Reload
to refresh your session.
You signed out in another tab or window.
Reload
to refresh your session.
You switched accounts on another tab or window.
Reload
to refresh your session.
Dismiss alert
{{ message }}
git-mirror
/
glibc
Public
Notifications
You must be signed in to change notification settings
Fork
0
Star
0
Code
Pull requests
0
Actions
Projects
0
Security
Insights
Additional navigation options
Code
Pull requests
Actions
Projects
Security
Insights
Files
1f063dc
abilist
aout
argp
assert
bits
catgets
conf
conform
crypt
csu
ctype
debug
dirent
dlfcn
elf
gmon
gnulib
grp
hesiod
hurd
iconv
iconvdata
include
inet
intl
io
libidn
libio
locale
localedata
login
mach
malloc
manual
math
misc
nis
nptl
nptl_db
nscd
Depend
Makefile
aicache.c
cache.c
connections.c
dbg_log.c
dbg_log.h
gai.c
getgrgid_r.c
getgrnam_r.c
gethstbyad_r.c
gethstbynm2_r.c
getpwnam_r.c
getpwuid_r.c
grpcache.c
hstcache.c
initgrcache.c
mem.c
nscd-client.h
nscd.c
nscd.conf
nscd.h
nscd.init
nscd_conf.c
nscd_getai.c
nscd_getgr_r.c
nscd_gethst_r.c
nscd_getpw_r.c
nscd_helper.c
nscd_initgroups.c
nscd_proto.h
nscd_setup_thread.c
nscd_stat.c
pwdcache.c
selinux.c
selinux.h
nss
po
posix
pwd
resolv
resource
rt
scripts
setjmp
shadow
signal
socket
soft-fp
stdio-common
stdlib
streams
string
sunrpc
sysdeps
sysvipc
termios
time
timezone
wcsmbs
wctype
.cvsignore
BUGS
CANCEL-FCT-WAIVE
CANCEL-FILE-WAIVE
CONFORMANCE
COPYING
COPYING.LIB
ChangeLog
ChangeLog.1
ChangeLog.10
ChangeLog.11
ChangeLog.12
ChangeLog.13
ChangeLog.14
ChangeLog.15
ChangeLog.2
ChangeLog.3
ChangeLog.4
ChangeLog.5
ChangeLog.6
ChangeLog.7
ChangeLog.8
ChangeLog.9
FAQ
FAQ.in
INSTALL
INTERFACE
LICENSES
Makeconfig
Makefile
Makefile.in
Makerules
NAMESPACE
NEWS
NOTES
PROJECTS
README
README.libm
README.template
Rules
Versions.def
WUR-REPORT
abi-tags
aclocal.m4
config-name.in
config.h.in
config.make.in
configure
configure.in
cppflags-iterator.mk
extra-lib.mk
extra-modules.mk
o-iterator.mk
shlib-versions
test-skeleton.c
tls.make.c
version.h
Breadcrumbs
glibc
/
nscd
/
selinux.c
Blame
Blame
Latest commit
History
History
415 lines (345 loc) · 9.99 KB
Breadcrumbs
glibc
/
nscd
/
selinux.c
Top
File metadata and controls
Code
Blame
415 lines (345 loc) · 9.99 KB
Raw
/* SELinux access controls for nscd. Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Matthew Rickard <mjricka@epoch.ncsc.mil>, 2004. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #include "config.h" #include <error.h> #include <errno.h> #include <libintl.h> #include <pthread.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <syslog.h> #include <unistd.h> #include <sys/prctl.h> #include <selinux/av_permissions.h> #include <selinux/avc.h> #include <selinux/flask.h> #include <selinux/selinux.h> #ifdef HAVE_LIBAUDIT # include <libaudit.h> #endif #include "dbg_log.h" #include "selinux.h" #ifdef HAVE_SELINUX /* Global variable to tell if the kernel has SELinux support. */ int selinux_enabled; /* Define mappings of access vector permissions to request types. */ static const int perms[LASTREQ] = { [GETPWBYNAME] = NSCD__GETPWD, [GETPWBYUID] = NSCD__GETPWD, [GETGRBYNAME] = NSCD__GETGRP, [GETGRBYGID] = NSCD__GETGRP, [GETHOSTBYNAME] = NSCD__GETHOST, [GETHOSTBYNAMEv6] = NSCD__GETHOST, [GETHOSTBYADDR] = NSCD__GETHOST, [GETHOSTBYADDRv6] = NSCD__GETHOST, [GETSTAT] = NSCD__GETSTAT, [SHUTDOWN] = NSCD__ADMIN, [INVALIDATE] = NSCD__ADMIN, [GETFDPW] = NSCD__SHMEMPWD, [GETFDGR] = NSCD__SHMEMGRP, [GETFDHST] = NSCD__SHMEMHOST, [GETAI] = NSCD__GETHOST, [INITGROUPS] = NSCD__GETGRP }; /* Store an entry ref to speed AVC decisions. */ static struct avc_entry_ref aeref; /* Thread to listen for SELinux status changes via netlink. */ static pthread_t avc_notify_thread; #ifdef HAVE_LIBAUDIT /* Prototype for supporting the audit daemon */ static void log_callback (const char *fmt, ...); #endif /* Prototypes for AVC callback functions. */ static void *avc_create_thread (void (*run) (void)); static void avc_stop_thread (void *thread); static void *avc_alloc_lock (void); static void avc_get_lock (void *lock); static void avc_release_lock (void *lock); static void avc_free_lock (void *lock); /* AVC callback structures for use in avc_init. */ static const struct avc_log_callback log_cb = { #ifdef HAVE_LIBAUDIT .func_log = log_callback, #else .func_log = dbg_log, #endif .func_audit = NULL }; static const struct avc_thread_callback thread_cb = { .func_create_thread = avc_create_thread, .func_stop_thread = avc_stop_thread }; static const struct avc_lock_callback lock_cb = { .func_alloc_lock = avc_alloc_lock, .func_get_lock = avc_get_lock, .func_release_lock = avc_release_lock, .func_free_lock = avc_free_lock }; #ifdef HAVE_LIBAUDIT /* The audit system's netlink socket descriptor */ static int audit_fd = -1; /* When an avc denial occurs, log it to audit system */ static void log_callback (const char *fmt, ...) { if (audit_fd >= 0) { va_list ap; va_start (ap, fmt); char *buf; int e = vasprintf (&buf, fmt, ap); if (e < 0) { buf = alloca (BUFSIZ); vsnprintf (buf, BUFSIZ, fmt, ap); } /* FIXME: need to attribute this to real user, using getuid for now */ audit_log_user_avc_message (audit_fd, AUDIT_USER_AVC, buf, NULL, NULL, NULL, getuid ()); if (e >= 0) free (buf); va_end (ap); } } /* Initialize the connection to the audit system */ static void audit_init (void) { audit_fd = audit_open (); if (audit_fd < 0 /* If kernel doesn't support audit, bail out */ && errno != EINVAL && errno != EPROTONOSUPPORT && errno != EAFNOSUPPORT) dbg_log (_("Failed opening connection to the audit subsystem: %m")); } # ifdef HAVE_LIBCAP static const cap_value_t new_cap_list[] = { CAP_AUDIT_WRITE }; # define nnew_cap_list (sizeof (new_cap_list) / sizeof (new_cap_list[0])) static const cap_value_t tmp_cap_list[] = { CAP_AUDIT_WRITE, CAP_SETUID, CAP_SETGID }; # define ntmp_cap_list (sizeof (tmp_cap_list) / sizeof (tmp_cap_list[0])) cap_t preserve_capabilities (void) { if (getuid () != 0) /* Not root, then we cannot preserve anything. */ return NULL; if (prctl (PR_SET_KEEPCAPS, 1) == -1) { dbg_log (_("Failed to set keep-capabilities")); error (EXIT_FAILURE, errno, _("prctl(KEEPCAPS) failed")); /* NOTREACHED */ } cap_t tmp_caps = cap_init (); cap_t new_caps; if (tmp_caps != NULL) new_caps = cap_init (); if (tmp_caps == NULL || new_caps == NULL) { if (tmp_caps != NULL) free_caps (tmp_caps); dbg_log (_("Failed to initialize drop of capabilities")); error (EXIT_FAILURE, 0, _("cap_init failed")); } /* There is no reason why these should not work. */ cap_set_flag (new_caps, CAP_PERMITTED, nnew_cap_list, new_cap_list, CAP_SET); cap_set_flag (new_caps, CAP_EFFECTIVE, nnew_cap_list, new_cap_list, CAP_SET); cap_set_flag (tmp_caps, CAP_PERMITTED, ntmp_cap_list, tmp_cap_list, CAP_SET); cap_set_flag (tmp_caps, CAP_EFFECTIVE, ntmp_cap_list, tmp_cap_list, CAP_SET); int res = cap_set_proc (tmp_caps); cap_free (tmp_caps); if (__builtin_expect (res != 0, 0)) { cap_free (new_caps); dbg_log (_("Failed to drop capabilities\n")); error (EXIT_FAILURE, 0, _("cap_set_proc failed")); } return new_caps; } void install_real_capabilities (cap_t new_caps) { /* If we have no capabilities there is nothing to do here. */ if (new_caps == NULL) return; if (cap_set_proc (new_caps)) { cap_free (new_caps); dbg_log (_("Failed to drop capabilities")); error (EXIT_FAILURE, 0, _("cap_set_proc failed")); /* NOTREACHED */ } cap_free (new_caps); if (prctl (PR_SET_KEEPCAPS, 0) == -1) { dbg_log (_("Failed to unset keep-capabilities")); error (EXIT_FAILURE, errno, _("prctl(KEEPCAPS) failed")); /* NOTREACHED */ } } # endif /* HAVE_LIBCAP */ #endif /* HAVE_LIBAUDIT */ /* Determine if we are running on an SELinux kernel. Set selinux_enabled to the result. */ void nscd_selinux_enabled (int *selinux_enabled) { *selinux_enabled = is_selinux_enabled (); if (*selinux_enabled < 0) { dbg_log (_("Failed to determine if kernel supports SELinux")); exit (EXIT_FAILURE); } } /* Create thread for AVC netlink notification. */ static void * avc_create_thread (void (*run) (void)) { int rc; rc = pthread_create (&avc_notify_thread, NULL, (void *(*) (void *)) run, NULL); if (rc != 0) error (EXIT_FAILURE, rc, _("Failed to start AVC thread")); return &avc_notify_thread; } /* Stop AVC netlink thread. */ static void avc_stop_thread (void *thread) { pthread_cancel (*(pthread_t *) thread); } /* Allocate a new AVC lock. */ static void * avc_alloc_lock (void) { pthread_mutex_t *avc_mutex; avc_mutex = malloc (sizeof (pthread_mutex_t)); if (avc_mutex == NULL) error (EXIT_FAILURE, errno, _("Failed to create AVC lock")); pthread_mutex_init (avc_mutex, NULL); return avc_mutex; } /* Acquire an AVC lock. */ static void avc_get_lock (void *lock) { pthread_mutex_lock (lock); } /* Release an AVC lock. */ static void avc_release_lock (void *lock) { pthread_mutex_unlock (lock); } /* Free an AVC lock. */ static void avc_free_lock (void *lock) { pthread_mutex_destroy (lock); free (lock); } /* Initialize the user space access vector cache (AVC) for NSCD along with log/thread/lock callbacks. */ void nscd_avc_init (void) { avc_entry_ref_init (&aeref); if (avc_init ("avc", NULL, &log_cb, &thread_cb, &lock_cb) < 0) error (EXIT_FAILURE, errno, _("Failed to start AVC")); else dbg_log (_("Access Vector Cache (AVC) started")); #ifdef HAVE_LIBAUDIT audit_init (); #endif } /* Check the permission from the caller (via getpeercon) to nscd. Returns 0 if access is allowed, 1 if denied, and -1 on error. */ int nscd_request_avc_has_perm (int fd, request_type req) { /* Initialize to NULL so we know what to free in case of failure. */ security_context_t scon = NULL; security_context_t tcon = NULL; security_id_t ssid = NULL; security_id_t tsid = NULL; int rc = -1; if (getpeercon (fd, &scon) < 0) { dbg_log (_("Error getting context of socket peer")); goto out; } if (getcon (&tcon) < 0) { dbg_log (_("Error getting context of nscd")); goto out; } if (avc_context_to_sid (scon, &ssid) < 0 || avc_context_to_sid (tcon, &tsid) < 0) { dbg_log (_("Error getting sid from context")); goto out; } rc = avc_has_perm (ssid, tsid, SECCLASS_NSCD, perms[req], &aeref, NULL) < 0; out: if (scon) freecon (scon); if (tcon) freecon (tcon); if (ssid) sidput (ssid); if (tsid) sidput (tsid); return rc; } /* Wrapper to get AVC statistics. */ void nscd_avc_cache_stats (struct avc_cache_stats *cstats) { avc_cache_stats (cstats); } /* Print the AVC statistics to stdout. */ void nscd_avc_print_stats (struct avc_cache_stats *cstats) { printf (_("\nSELinux AVC Statistics:\n\n" "%15u entry lookups\n" "%15u entry hits\n" "%15u entry misses\n" "%15u entry discards\n" "%15u CAV lookups\n" "%15u CAV hits\n" "%15u CAV probes\n" "%15u CAV misses\n"), cstats->entry_lookups, cstats->entry_hits, cstats->entry_misses, cstats->entry_discards, cstats->cav_lookups, cstats->cav_hits, cstats->cav_probes, cstats->cav_misses); } /* Clean up the AVC before exiting. */ void nscd_avc_destroy (void) { avc_destroy (); #ifdef HAVE_LIBAUDIT audit_close (audit_fd); #endif } #endif /* HAVE_SELINUX */
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
You can’t perform that action at this time.