2004-09-16  Ulrich Drepper  <drepper@redhat.com>

	* configure.in: Add test for required SELinux features.
	* config.make.in: Add have-selinux entry.
	* config.h.in: Add HAVE_SELINUX entry.
	* nscd/Makefile (nscd-modules): Add selinux.
	(CFLAGS-selinux.c): Add -fpie.
	Define selinux-LIBS and use in link line.
	* nscd/connections.c (handle_request): Check access SELinux permissions
	before processing request.
	* nscd/nscd.c (main): Initialize selinux_enabled and stop avc thread.
	* nscd/nscd_stat.c: Transmit and print AVC statistics.
	* nscd/selinux.c: New file.
	* nscd/selinux.h: New file.

2004-09-16  Jakub Jelinek  <jakub@redhat.com>

	* nscd/nscd_helper.c (__nscd_unmap, get_mapping): Use __munmap
	instead of munmap.

	* nscd/Makefile (CFLAGS-aicache.c): Set to -fpie.

2004-09-16  Thorsten Kukuk  <kukuk@suse.de>

	* sysdeps/posix/getaddrinfo.c (gaih_inet): Check
	__nss_not_use_nscd_hosts variable if nscd should be used or not.

2004-09-16  Ulrich Drepper  <drepper@redhat.com>

	* nscd/nscd_proto.h: Define NSS_NSCD_RETRY.
	Add __nscd_getai prototype.
	* nss/getXXbyYY_r.c: Remode definition of NSS_NSCD_RETRY.
	* nscd/nscd-client.h: Remove __nscd_getai prototype.
	* nscd/nscd_getai.c: Include nscd_proto.h.

	* elf/ldd.bash.in: Add support for SELinux environments.
	Patch by Stephen Smalley <sds@epoch.ncsc.mil>.
This commit is contained in:
Ulrich Drepper 2004-09-17 00:04:18 +00:00
parent 2fff3d93b5
commit 74a30a5851
11 changed files with 577 additions and 2 deletions

View File

@ -1,3 +1,41 @@
2004-09-16 Ulrich Drepper <drepper@redhat.com>
* configure.in: Add test for required SELinux features.
* config.make.in: Add have-selinux entry.
* config.h.in: Add HAVE_SELINUX entry.
* nscd/Makefile (nscd-modules): Add selinux.
(CFLAGS-selinux.c): Add -fpie.
Define selinux-LIBS and use in link line.
* nscd/connections.c (handle_request): Check access SELinux permissions
before processing request.
* nscd/nscd.c (main): Initialize selinux_enabled and stop avc thread.
* nscd/nscd_stat.c: Transmit and print AVC statistics.
* nscd/selinux.c: New file.
* nscd/selinux.h: New file.
2004-09-16 Jakub Jelinek <jakub@redhat.com>
* nscd/nscd_helper.c (__nscd_unmap, get_mapping): Use __munmap
instead of munmap.
* nscd/Makefile (CFLAGS-aicache.c): Set to -fpie.
2004-09-16 Thorsten Kukuk <kukuk@suse.de>
* sysdeps/posix/getaddrinfo.c (gaih_inet): Check
__nss_not_use_nscd_hosts variable if nscd should be used or not.
2004-09-16 Ulrich Drepper <drepper@redhat.com>
* nscd/nscd_proto.h: Define NSS_NSCD_RETRY.
Add __nscd_getai prototype.
* nss/getXXbyYY_r.c: Remode definition of NSS_NSCD_RETRY.
* nscd/nscd-client.h: Remove __nscd_getai prototype.
* nscd/nscd_getai.c: Include nscd_proto.h.
* elf/ldd.bash.in: Add support for SELinux environments.
Patch by Stephen Smalley <sds@epoch.ncsc.mil>.
2004-09-16 Roland McGrath <roland@redhat.com>
* configure.in (--with-headers): Let argument contain a : separated

View File

@ -18,6 +18,9 @@
--with-elf. */
#undef HAVE_ELF
/* Define if building with SELinux support. Set by --with-selinux. */
#undef HAVE_SELINUX
/* Define if using XCOFF. Set by --with-xcoff. */
#undef HAVE_XCOFF

View File

@ -58,6 +58,7 @@ have-cpp-asm-debuginfo = @libc_cv_cpp_asm_debuginfo@
enable-check-abi = @enable_check_abi@
have-forced-unwind = @libc_cv_forced_unwind@
have-fpie = @libc_cv_fpie@
have-selinux = @have_selinux@
have-cc-with-libunwind = @libc_cv_cc_with_libunwind@
fno-unit-at-a-time = @fno_unit_at_a_time@
bind-now = @bindnow@

167
configure vendored
View File

@ -313,7 +313,7 @@ ac_includes_default="\
# include <unistd.h>
#endif"
ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS with_fp with_cvs enable_check_abi oldest_abi bindnow force_install all_warnings build build_cpu build_vendor build_os host host_cpu host_vendor host_os subdirs add_ons base_machine sysnames INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LN_S CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC OBJEXT BUILD_CC cross_compiling CPP CXX CXXFLAGS ac_ct_CXX AR OBJDUMP RANLIB ac_ct_RANLIB MIG AS LD PWD_P MAKE MSGFMT MAKEINFO SED AUTOCONF SYSINCLUDES libc_cv_gcc_static_libgcc BASH libc_cv_have_bash2 KSH libc_cv_have_ksh AWK PERL INSTALL_INFO BISON VERSIONING libc_cv_asm_protected_directive libc_cv_initfinit_array libc_cv_cc_with_libunwind libc_cv_z_nodelete libc_cv_z_nodlopen libc_cv_z_initfirst libc_cv_z_relro libc_cv_Bgroup libc_cv_libgcc_s_suffix libc_cv_as_needed ASFLAGS_config libc_cv_z_combreloc libc_cv_z_execstack libc_cv_fpie fno_unit_at_a_time libc_cv_have_initfini libc_cv_cpp_asm_debuginfo no_whole_archive exceptions LIBGD EGREP sizeof_long_double libc_cv_gcc_unwind_find_fde uname_sysname uname_release uname_version old_glibc_headers libc_cv_slibdir libc_cv_localedir libc_cv_sysconfdir libc_cv_rootsbindir libc_cv_forced_unwind use_ldconfig ldd_rewrite_script gnu_ld gnu_as elf xcoff static shared pic_default profile omitfp bounded static_nss nopic_initfini DEFINES linux_doors mach_interface_list VERSION RELEASE LIBOBJS LTLIBOBJS'
ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS with_fp with_cvs enable_check_abi oldest_abi bindnow force_install all_warnings build build_cpu build_vendor build_os host host_cpu host_vendor host_os subdirs add_ons base_machine sysnames INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LN_S CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC OBJEXT BUILD_CC cross_compiling CPP CXX CXXFLAGS ac_ct_CXX AR OBJDUMP RANLIB ac_ct_RANLIB MIG AS LD PWD_P MAKE MSGFMT MAKEINFO SED AUTOCONF SYSINCLUDES libc_cv_gcc_static_libgcc BASH libc_cv_have_bash2 KSH libc_cv_have_ksh AWK PERL INSTALL_INFO BISON VERSIONING libc_cv_asm_protected_directive libc_cv_initfinit_array libc_cv_cc_with_libunwind libc_cv_z_nodelete libc_cv_z_nodlopen libc_cv_z_initfirst libc_cv_z_relro libc_cv_Bgroup libc_cv_libgcc_s_suffix libc_cv_as_needed ASFLAGS_config libc_cv_z_combreloc libc_cv_z_execstack libc_cv_fpie fno_unit_at_a_time libc_cv_have_initfini libc_cv_cpp_asm_debuginfo no_whole_archive exceptions LIBGD have_selinux EGREP sizeof_long_double libc_cv_gcc_unwind_find_fde uname_sysname uname_release uname_version old_glibc_headers libc_cv_slibdir libc_cv_localedir libc_cv_sysconfdir libc_cv_rootsbindir libc_cv_forced_unwind use_ldconfig ldd_rewrite_script gnu_ld gnu_as elf xcoff static shared pic_default profile omitfp bounded static_nss nopic_initfini DEFINES linux_doors mach_interface_list VERSION RELEASE LIBOBJS LTLIBOBJS'
ac_subst_files=''
# Initialize some variables set by options.
@ -895,6 +895,7 @@ Optional Packages:
--with-fp if using floating-point hardware [default=yes]
--with-binutils=PATH specify location of binutils (as and ld)
--with-elf if using the ELF object format
--with-selinux if building with SELinux support
--with-xcoff if using the XCOFF object format
--without-cvs if CVS should not be used
--with-headers=PATH location of system headers to use (for example
@ -1485,6 +1486,14 @@ else
elf=no
fi;
# Check whether --with-selinux or --without-selinux was given.
if test "${with_selinux+set}" = set; then
withval="$with_selinux"
with_selinux=$withval
else
with_selinux=auto
fi;
# Check whether --with-xcoff or --without-xcoff was given.
if test "${with_xcoff+set}" = set; then
withval="$with_xcoff"
@ -6694,6 +6703,161 @@ echo "$as_me:$LINENO: result: $LIBGD" >&5
echo "${ECHO_T}$LIBGD" >&6
# SELinux detection
if test x$with_selinux = xno ; then
have_selinux=no;
else
# See if we have the SELinux library
echo "$as_me:$LINENO: checking for is_selinux_enabled in -lselinux" >&5
echo $ECHO_N "checking for is_selinux_enabled in -lselinux... $ECHO_C" >&6
if test "${ac_cv_lib_selinux_is_selinux_enabled+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
ac_check_lib_save_LIBS=$LIBS
LIBS="-lselinux $LIBS"
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
/* Override any gcc2 internal prototype to avoid an error. */
#ifdef __cplusplus
extern "C"
#endif
/* We use char because int might match the return type of a gcc2
builtin and then its argument prototype would still apply. */
char is_selinux_enabled ();
int
main ()
{
is_selinux_enabled ();
;
return 0;
}
_ACEOF
rm -f conftest.$ac_objext conftest$ac_exeext
if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
(eval $ac_link) 2>conftest.er1
ac_status=$?
grep -v '^ *+' conftest.er1 >conftest.err
rm -f conftest.er1
cat conftest.err >&5
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); } &&
{ ac_try='test -z "$ac_c_werror_flag"
|| test ! -s conftest.err'
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
(eval $ac_try) 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; } &&
{ ac_try='test -s conftest$ac_exeext'
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
(eval $ac_try) 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; }; then
ac_cv_lib_selinux_is_selinux_enabled=yes
else
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
ac_cv_lib_selinux_is_selinux_enabled=no
fi
rm -f conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
echo "$as_me:$LINENO: result: $ac_cv_lib_selinux_is_selinux_enabled" >&5
echo "${ECHO_T}$ac_cv_lib_selinux_is_selinux_enabled" >&6
if test $ac_cv_lib_selinux_is_selinux_enabled = yes; then
have_selinux=yes
else
have_selinux=no
fi
# See if we have the SELinux header with the NSCD permissions in it.
if test x$have_selinux = xyes ; then
echo "$as_me:$LINENO: checking for NSCD Flask permissions in selinux/av_permissions.h" >&5
echo $ECHO_N "checking for NSCD Flask permissions in selinux/av_permissions.h... $ECHO_C" >&6
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
#include <selinux/av_permissions.h>
int
main ()
{
#ifdef NSCD__SHMEMHOST
return 0;
#else
#error NSCD__SHMEMHOST not defined
#endif
;
return 0;
}
_ACEOF
rm -f conftest.$ac_objext
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
(eval $ac_compile) 2>conftest.er1
ac_status=$?
grep -v '^ *+' conftest.er1 >conftest.err
rm -f conftest.er1
cat conftest.err >&5
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); } &&
{ ac_try='test -z "$ac_c_werror_flag"
|| test ! -s conftest.err'
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
(eval $ac_try) 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; } &&
{ ac_try='test -s conftest.$ac_objext'
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
(eval $ac_try) 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; }; then
have_selinux=yes
else
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
have_selinux=no
fi
rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
echo "$as_me:$LINENO: result: $have_selinux" >&5
echo "${ECHO_T}$have_selinux" >&6
fi
if test x$with_selinux = xauto ; then
if test x$have_selinux = xno ; then
{ echo "$as_me:$LINENO: WARNING: Sufficiently new SELinux library not found" >&5
echo "$as_me: WARNING: Sufficiently new SELinux library not found" >&2;}
fi
else
if test x$have_selinux = xno ; then
{ { echo "$as_me:$LINENO: error: SELinux explicitly required, and SELinux library not found" >&5
echo "$as_me: error: SELinux explicitly required, and SELinux library not found" >&2;}
{ (exit 1); exit 1; }; }
fi
fi
fi
# Check if we're building with SELinux support.
if test "x$have_selinux" = xyes; then
cat >>confdefs.h <<\_ACEOF
#define HAVE_SELINUX 1
_ACEOF
fi
echo "$as_me:$LINENO: checking for egrep" >&5
echo $ECHO_N "checking for egrep... $ECHO_C" >&6
@ -8310,6 +8474,7 @@ s,@libc_cv_cpp_asm_debuginfo@,$libc_cv_cpp_asm_debuginfo,;t t
s,@no_whole_archive@,$no_whole_archive,;t t
s,@exceptions@,$exceptions,;t t
s,@LIBGD@,$LIBGD,;t t
s,@have_selinux@,$have_selinux,;t t
s,@EGREP@,$EGREP,;t t
s,@sizeof_long_double@,$sizeof_long_double,;t t
s,@libc_cv_gcc_unwind_find_fde@,$libc_cv_gcc_unwind_find_fde,;t t

View File

@ -51,6 +51,11 @@ otherlibs += $(nssobjdir)/libnss_files.a $(resolvobjdir)/libnss_dns.a \
$(resolvobjdir)/libresolv.a
endif
ifeq (yes,$(have-selinux))
nscd-modules += selinux
selinux-LIBS := -lselinux
endif
distribute := nscd.h nscd-client.h dbg_log.h \
$(addsuffix .c, $(filter-out xmalloc, $(nscd-modules))) \
nscd_nischeck.c TODO nscd.conf nscd.init nscd_proto.h \
@ -83,6 +88,7 @@ CFLAGS-xstrdup.c = -fpie
CFLAGS-mem.c = -fpie
CFLAGS-nscd_setup_thread.c = -fpie
CFLAGS-aicache.c = -fpie
CFLAGS-selinux.c = -fpie
$(objpfx)nscd: $(addprefix $(objpfx),$(nscd-modules:=.o))
$(LINK.o) -pie -Wl,-O1 \
@ -91,7 +97,7 @@ $(objpfx)nscd: $(addprefix $(objpfx),$(nscd-modules:=.o))
$(extra-B-$(@F:lib%.so=%).so) $(load-map-file) \
$(LDFLAGS) $(LDFLAGS-$(@F)) \
-L$(subst :, -L,$(rpath-link)) -Wl,-rpath-link=$(rpath-link) \
-o $@ $^ $(common-objpfx)libc_nonshared.a
-o $@ $^ $(selinux-LIBS) $(common-objpfx)libc_nonshared.a
endif
# This makes sure -DNOT_IN_libc is passed for all these modules.

View File

@ -41,6 +41,7 @@
#include "nscd.h"
#include "dbg_log.h"
#include "selinux.h"
/* Number of bytes of data we initially reserve for each hash table bucket. */
@ -592,6 +593,15 @@ cannot handle old request version %d; current version is %d"),
return;
}
/* Make the SELinux check before we go on to the standard checks. We
need to verify that the request type is valid, since it has not
yet been checked at this point. */
if (selinux_enabled
&& __builtin_expect (req->type, GETPWBYNAME) >= GETPWBYNAME
&& __builtin_expect (req->type, LASTREQ) < LASTREQ
&& nscd_request_avc_has_perm (fd, req->type) != 0)
return;
struct database_dyn *db = serv2db[req->type];
if ((__builtin_expect (req->type, GETPWBYNAME) >= GETPWBYNAME

View File

@ -44,6 +44,7 @@
#include "dbg_log.h"
#include "nscd.h"
#include "selinux.h"
#include "../nss/nsswitch.h"
#include <device-nrs.h>
@ -126,6 +127,9 @@ main (int argc, char **argv)
/* Set the text message domain. */
textdomain (PACKAGE);
/* Determine if the kernel has SELinux support. */
nscd_selinux_enabled (&selinux_enabled);
/* Parse and process arguments. */
argp_parse (&argp, argc, argv, 0, &remaining, NULL);
@ -244,6 +248,10 @@ main (int argc, char **argv)
signal (SIGTSTP, SIG_IGN);
}
/* Start the SELinux AVC. */
if (selinux_enabled)
nscd_avc_init ();
signal (SIGINT, termination_handler);
signal (SIGQUIT, termination_handler);
signal (SIGTERM, termination_handler);
@ -421,6 +429,10 @@ termination_handler (int signum)
// XXX async OK?
msync (dbs[cnt].head, dbs[cnt].memsize, MS_ASYNC);
/* Shutdown the SELinux AVC. */
if (selinux_enabled)
nscd_avc_destroy ();
_exit (EXIT_SUCCESS);
}

View File

@ -27,6 +27,10 @@
/* Interval in which we transfer retry to contact the NSCD. */
#define NSS_NSCD_RETRY 100
/* Type needed in the interfaces. */
struct nscd_ai_result;
/* Variables for communication between NSCD handler functions and NSS. */
extern int __nss_not_use_nscd_passwd attribute_hidden;
extern int __nss_not_use_nscd_group attribute_hidden;

View File

@ -29,6 +29,12 @@
#include "nscd.h"
#include "dbg_log.h"
#include "selinux.h"
#ifdef HAVE_SELINUX
# include <selinux/selinux.h>
# include <selinux/avc.h>
#endif /* HAVE_SELINUX */
/* We use this to make sure the receiver is the same. */
static const char compilation[21] = __DATE__ " " __TIME__;
@ -71,6 +77,9 @@ struct statdata
unsigned long int client_queued;
int ndbs;
struct dbstat dbs[lastdb];
#ifdef HAVE_SELINUX
struct avc_cache_stats cstats;
#endif /* HAVE_SELINUX */
};
@ -113,6 +122,9 @@ send_stats (int fd, struct database_dyn dbs[lastdb])
}
}
if (selinux_enabled)
nscd_avc_cache_stats (&data.cstats);
if (TEMP_FAILURE_RETRY (write (fd, &data, sizeof (data))) != sizeof (data))
{
char buf[256];
@ -276,6 +288,9 @@ receive_print_stats (void)
data.dbs[i].addfailed, check_file, dbnames[i]);
}
if (selinux_enabled)
nscd_avc_print_stats (&data.cstats);
close (fd);
exit (0);

266
nscd/selinux.c Normal file
View File

@ -0,0 +1,266 @@
/* SELinux access controls for nscd.
Copyright (C) 2004 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 <error.h>
#include <errno.h>
#include <libintl.h>
#include <pthread.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <syslog.h>
#include <selinux/av_permissions.h>
#include <selinux/avc.h>
#include <selinux/flask.h>
#include <selinux/selinux.h>
#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
};
/* 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;
/* 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 =
{
.func_log = dbg_log,
.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
};
/* 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"));
}
/* 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 ();
}
#endif /* HAVE_SELINUX */

55
nscd/selinux.h Normal file
View File

@ -0,0 +1,55 @@
/* Header for nscd SELinux access controls.
Copyright (C) 2004 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. */
#ifndef _SELINUX_H
#define _SELINUX_H 1
#include "nscd.h"
#ifdef HAVE_SELINUX
/* Global variable to tell if the kernel has SELinux support. */
extern int selinux_enabled;
/* Define this for AVC stat usage. */
struct avc_cache_stats;
/* Initialize the userspace AVC. */
extern void nscd_avc_init (void);
/* Destroy the userspace AVC. */
extern void nscd_avc_destroy (void);
/* Determine if we are running on an SELinux kernel. */
extern void nscd_selinux_enabled (int *selinux_enabled);
/* Check if the client has permission for the request type. */
extern int nscd_request_avc_has_perm (int fd, request_type req);
/* Initialize AVC statistic information. */
extern void nscd_avc_cache_stats (struct avc_cache_stats *cstats);
/* Display statistics on AVC usage. */
extern void nscd_avc_print_stats (struct avc_cache_stats *cstats);
#else
# define selinux_enabled 0
# define nscd_avc_init() (void) 0
# define nscd_avc_destroy() (void) 0
# define nscd_selinux_enabled(selinux_enabled) (void) 0
# define nscd_request_avc_has_perm(fd, req) 0
# define nscd_avc_cache_stats(cstats) (void) 0
# define nscd_avc_print_stats(cstats) (void) 0
#endif /* HAVE_SELINUX */
#endif /* _SELINUX_H */