From: Luca Boccassi <[email protected]> libselinux is built in most distros, but it is seldomly needed at runtime (e.g.: it is not used by default on Debian/Ubuntu). In order to allow building small images from the same packages, switch it to runtime optional by using dlopen(), and gracefully fallback if the library is not found.
Use sd-dlopen to stamp the ELF binaries using the ELF dlopen metadata format as defined by: https://uapi-group.org/specifications/specs/elf_dlopen_metadata/ so that packaging tools for rpm/deb can automatically derive dependencies for it. --- lib/selinux-dlopen.c | 618 +++++++++++++++++++++++++++++++++ m4/selinux-selinux-h.m4 | 82 +++-- modules/selinux-h | 13 +- tests/test-selinux-selinux-h.c | 3 + 4 files changed, 686 insertions(+), 30 deletions(-) create mode 100644 lib/selinux-dlopen.c diff --git a/lib/selinux-dlopen.c b/lib/selinux-dlopen.c new file mode 100644 index 0000000000..8a3d4b8100 --- /dev/null +++ b/lib/selinux-dlopen.c @@ -0,0 +1,618 @@ +/* Load libselinux on demand. + Copyright (C) 2026 Free Software Foundation, Inc. + + This file 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. + + This file 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 this program. If not, see <https://www.gnu.org/licenses/>. */ + +#include <config.h> + +#include <dlfcn.h> +#include <errno.h> +#include <selinux/context.h> +#include <selinux/label.h> +#include <selinux/selinux.h> +#include <stddef.h> +#include <sys/stat.h> + +#include "glthread/once.h" +#include "sd-dlopen.h" + +SD_ELF_NOTE_DLOPEN ("selinux", + "Support for SELinux", + SD_ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED, + LIBSELINUX_SONAME); + +/* Gnulib redirects these names to wrappers that validate the returned + contexts. This file provides the underlying libselinux entry points. */ +#undef getfilecon +#undef getfilecon_raw +#undef lgetfilecon +#undef lgetfilecon_raw +#undef fgetfilecon +#undef fgetfilecon_raw + +extern int getfilecon (char const *, char **); +extern int getfilecon_raw (char const *, char **); +extern int lgetfilecon (char const *, char **); +extern int lgetfilecon_raw (char const *, char **); +extern int fgetfilecon (int, char **); +extern int fgetfilecon_raw (int, char **); + +/* Pointers to the libselinux functions resolved by load_libselinux. */ +struct selinux_operations +{ + __typeof__ (&is_selinux_enabled) is_selinux_enabled; + __typeof__ (&getcon) getcon; + __typeof__ (&getcon_raw) getcon_raw; + __typeof__ (&freecon) freecon; + __typeof__ (&getfscreatecon_raw) getfscreatecon_raw; + __typeof__ (&setfscreatecon) setfscreatecon; + __typeof__ (&setfscreatecon_raw) setfscreatecon_raw; + __typeof__ (&getfilecon) getfilecon; + __typeof__ (&getfilecon_raw) getfilecon_raw; + __typeof__ (&lgetfilecon) lgetfilecon; + __typeof__ (&lgetfilecon_raw) lgetfilecon_raw; + __typeof__ (&fgetfilecon) fgetfilecon; + __typeof__ (&fgetfilecon_raw) fgetfilecon_raw; + __typeof__ (&setfilecon) setfilecon; + __typeof__ (&lsetfilecon) lsetfilecon; + __typeof__ (&lsetfilecon_raw) lsetfilecon_raw; + __typeof__ (&fsetfilecon) fsetfilecon; + __typeof__ (&fsetfilecon_raw) fsetfilecon_raw; + __typeof__ (&setexeccon) setexeccon; + __typeof__ (&security_check_context) security_check_context; + __typeof__ (&security_compute_create) security_compute_create; + __typeof__ (&security_compute_create_raw) security_compute_create_raw; + __typeof__ (&string_to_security_class) string_to_security_class; +#if HAVE_DECL_MODE_TO_SECURITY_CLASS + __typeof__ (&mode_to_security_class) mode_to_security_class; +#endif +#if HAVE_SELINUX_LABEL_H + __typeof__ (&selabel_open) selabel_open; + __typeof__ (&selabel_lookup) selabel_lookup; + __typeof__ (&selabel_lookup_raw) selabel_lookup_raw; + __typeof__ (&selabel_close) selabel_close; + __typeof__ (&selinux_file_context_cmp) selinux_file_context_cmp; +#endif +#if HAVE_SELINUX_CONTEXT_H + __typeof__ (&context_new) context_new; + __typeof__ (&context_str) context_str; + __typeof__ (&context_free) context_free; + __typeof__ (&context_type_get) context_type_get; + __typeof__ (&context_type_set) context_type_set; + __typeof__ (&context_user_get) context_user_get; + __typeof__ (&context_user_set) context_user_set; + __typeof__ (&context_role_get) context_role_get; + __typeof__ (&context_role_set) context_role_set; + __typeof__ (&context_range_get) context_range_get; + __typeof__ (&context_range_set) context_range_set; +#endif +}; + +static struct selinux_operations selinux_ops; +static int load_status; +gl_once_define (static, load_once) + +/* Return a function pointer in HANDLE for SYMBOL. */ +static void * +symbol_address (void *handle, char const *symbol) +{ + void *address = dlsym (handle, symbol); + if (!address) + errno = ENOSYS; + return address; +} + +/* Load libselinux and resolve all required symbols. */ +static void +do_load_libselinux (void) +{ + void *handle; + int flags = RTLD_LAZY | RTLD_LOCAL; + +#ifdef RTLD_NODELETE + flags |= RTLD_NODELETE; +#endif + handle = dlopen (LIBSELINUX_SONAME, flags); + if (!handle) + { + load_status = -1; + return; + } + + selinux_ops.is_selinux_enabled = + symbol_address (handle, "is_selinux_enabled"); + if (!selinux_ops.is_selinux_enabled) + goto fail; + selinux_ops.getcon = symbol_address (handle, "getcon"); + if (!selinux_ops.getcon) + goto fail; + selinux_ops.getcon_raw = symbol_address (handle, "getcon_raw"); + if (!selinux_ops.getcon_raw) + goto fail; + selinux_ops.freecon = symbol_address (handle, "freecon"); + if (!selinux_ops.freecon) + goto fail; + selinux_ops.getfscreatecon_raw = + symbol_address (handle, "getfscreatecon_raw"); + if (!selinux_ops.getfscreatecon_raw) + goto fail; + selinux_ops.setfscreatecon = symbol_address (handle, "setfscreatecon"); + if (!selinux_ops.setfscreatecon) + goto fail; + selinux_ops.setfscreatecon_raw = + symbol_address (handle, "setfscreatecon_raw"); + if (!selinux_ops.setfscreatecon_raw) + goto fail; + selinux_ops.getfilecon = symbol_address (handle, "getfilecon"); + if (!selinux_ops.getfilecon) + goto fail; + selinux_ops.getfilecon_raw = symbol_address (handle, "getfilecon_raw"); + if (!selinux_ops.getfilecon_raw) + goto fail; + selinux_ops.lgetfilecon = symbol_address (handle, "lgetfilecon"); + if (!selinux_ops.lgetfilecon) + goto fail; + selinux_ops.lgetfilecon_raw = symbol_address (handle, "lgetfilecon_raw"); + if (!selinux_ops.lgetfilecon_raw) + goto fail; + selinux_ops.fgetfilecon = symbol_address (handle, "fgetfilecon"); + if (!selinux_ops.fgetfilecon) + goto fail; + selinux_ops.fgetfilecon_raw = symbol_address (handle, "fgetfilecon_raw"); + if (!selinux_ops.fgetfilecon_raw) + goto fail; + selinux_ops.setfilecon = symbol_address (handle, "setfilecon"); + if (!selinux_ops.setfilecon) + goto fail; + selinux_ops.lsetfilecon = symbol_address (handle, "lsetfilecon"); + if (!selinux_ops.lsetfilecon) + goto fail; + selinux_ops.lsetfilecon_raw = symbol_address (handle, "lsetfilecon_raw"); + if (!selinux_ops.lsetfilecon_raw) + goto fail; + selinux_ops.fsetfilecon = symbol_address (handle, "fsetfilecon"); + if (!selinux_ops.fsetfilecon) + goto fail; + selinux_ops.fsetfilecon_raw = symbol_address (handle, "fsetfilecon_raw"); + if (!selinux_ops.fsetfilecon_raw) + goto fail; + selinux_ops.setexeccon = symbol_address (handle, "setexeccon"); + if (!selinux_ops.setexeccon) + goto fail; + selinux_ops.security_check_context = + symbol_address (handle, "security_check_context"); + if (!selinux_ops.security_check_context) + goto fail; + selinux_ops.security_compute_create = + symbol_address (handle, "security_compute_create"); + if (!selinux_ops.security_compute_create) + goto fail; + selinux_ops.security_compute_create_raw = + symbol_address (handle, "security_compute_create_raw"); + if (!selinux_ops.security_compute_create_raw) + goto fail; + selinux_ops.string_to_security_class = + symbol_address (handle, "string_to_security_class"); + if (!selinux_ops.string_to_security_class) + goto fail; +#if HAVE_DECL_MODE_TO_SECURITY_CLASS + selinux_ops.mode_to_security_class = + dlsym (handle, "mode_to_security_class"); +#endif +#if HAVE_SELINUX_LABEL_H + selinux_ops.selabel_open = symbol_address (handle, "selabel_open"); + if (!selinux_ops.selabel_open) + goto fail; + selinux_ops.selabel_lookup = symbol_address (handle, "selabel_lookup"); + if (!selinux_ops.selabel_lookup) + goto fail; + selinux_ops.selabel_lookup_raw = + symbol_address (handle, "selabel_lookup_raw"); + if (!selinux_ops.selabel_lookup_raw) + goto fail; + selinux_ops.selabel_close = symbol_address (handle, "selabel_close"); + if (!selinux_ops.selabel_close) + goto fail; + selinux_ops.selinux_file_context_cmp = + symbol_address (handle, "selinux_file_context_cmp"); + if (!selinux_ops.selinux_file_context_cmp) + goto fail; +#endif +#if HAVE_SELINUX_CONTEXT_H + selinux_ops.context_new = symbol_address (handle, "context_new"); + if (!selinux_ops.context_new) + goto fail; + selinux_ops.context_str = symbol_address (handle, "context_str"); + if (!selinux_ops.context_str) + goto fail; + selinux_ops.context_free = symbol_address (handle, "context_free"); + if (!selinux_ops.context_free) + goto fail; + selinux_ops.context_type_get = symbol_address (handle, "context_type_get"); + if (!selinux_ops.context_type_get) + goto fail; + selinux_ops.context_type_set = symbol_address (handle, "context_type_set"); + if (!selinux_ops.context_type_set) + goto fail; + selinux_ops.context_user_get = symbol_address (handle, "context_user_get"); + if (!selinux_ops.context_user_get) + goto fail; + selinux_ops.context_user_set = symbol_address (handle, "context_user_set"); + if (!selinux_ops.context_user_set) + goto fail; + selinux_ops.context_role_get = symbol_address (handle, "context_role_get"); + if (!selinux_ops.context_role_get) + goto fail; + selinux_ops.context_role_set = symbol_address (handle, "context_role_set"); + if (!selinux_ops.context_role_set) + goto fail; + selinux_ops.context_range_get = + symbol_address (handle, "context_range_get"); + if (!selinux_ops.context_range_get) + goto fail; + selinux_ops.context_range_set = + symbol_address (handle, "context_range_set"); + if (!selinux_ops.context_range_set) + goto fail; +#endif + + return; + +fail: + dlclose (handle); + load_status = -1; +} + +/* Initialize the libselinux operations once. Return 0 on success. Return -1 + with errno set to ENOSYS on failure. */ +static int +load_libselinux (void) +{ + gl_once (load_once, do_load_libselinux); + if (load_status < 0) + { + errno = ENOSYS; + return -1; + } + return 0; +} + +#define LOAD_OR_RETURN(Failure) \ + do \ + { \ + if (load_libselinux () < 0) \ + return Failure; \ + } \ + while (false) + +extern int +is_selinux_enabled (void) +{ + return load_libselinux () < 0 ? 0 : selinux_ops.is_selinux_enabled (); +} + +extern int +getcon (char **con) +{ + LOAD_OR_RETURN (-1); + return selinux_ops.getcon (con); +} + +extern int +getcon_raw (char **con) +{ + LOAD_OR_RETURN (-1); + return selinux_ops.getcon_raw (con); +} + +extern void +freecon (char *con) +{ + if (con && load_libselinux () == 0) + selinux_ops.freecon (con); +} + +extern int +getfscreatecon_raw (char **con) +{ + LOAD_OR_RETURN (-1); + return selinux_ops.getfscreatecon_raw (con); +} + +extern int +setfscreatecon (char const *con) +{ + LOAD_OR_RETURN (-1); + return selinux_ops.setfscreatecon (con); +} + +extern int +setfscreatecon_raw (char const *con) +{ + LOAD_OR_RETURN (-1); + return selinux_ops.setfscreatecon_raw (con); +} + +extern int +getfilecon (char const *file, char **con) +{ + LOAD_OR_RETURN (-1); + return selinux_ops.getfilecon (file, con); +} + +extern int +getfilecon_raw (char const *file, char **con) +{ + LOAD_OR_RETURN (-1); + return selinux_ops.getfilecon_raw (file, con); +} + +extern int +lgetfilecon (char const *file, char **con) +{ + LOAD_OR_RETURN (-1); + return selinux_ops.lgetfilecon (file, con); +} + +extern int +lgetfilecon_raw (char const *file, char **con) +{ + LOAD_OR_RETURN (-1); + return selinux_ops.lgetfilecon_raw (file, con); +} + +extern int +fgetfilecon (int fd, char **con) +{ + LOAD_OR_RETURN (-1); + return selinux_ops.fgetfilecon (fd, con); +} + +extern int +fgetfilecon_raw (int fd, char **con) +{ + LOAD_OR_RETURN (-1); + return selinux_ops.fgetfilecon_raw (fd, con); +} + +extern int +setfilecon (char const *file, char const *con) +{ + LOAD_OR_RETURN (-1); + return selinux_ops.setfilecon (file, con); +} + +extern int +lsetfilecon (char const *file, char const *con) +{ + LOAD_OR_RETURN (-1); + return selinux_ops.lsetfilecon (file, con); +} + +extern int +lsetfilecon_raw (char const *file, char const *con) +{ + LOAD_OR_RETURN (-1); + return selinux_ops.lsetfilecon_raw (file, con); +} + +extern int +fsetfilecon (int fd, char const *con) +{ + LOAD_OR_RETURN (-1); + return selinux_ops.fsetfilecon (fd, con); +} + +extern int +fsetfilecon_raw (int fd, char const *con) +{ + LOAD_OR_RETURN (-1); + return selinux_ops.fsetfilecon_raw (fd, con); +} + +extern int +setexeccon (char const *con) +{ + LOAD_OR_RETURN (-1); + return selinux_ops.setexeccon (con); +} + +extern int +security_check_context (char const *con) +{ + LOAD_OR_RETURN (-1); + return selinux_ops.security_check_context (con); +} + +extern int +security_compute_create (char const *scon, char const *tcon, + security_class_t tclass, char **newcon) +{ + LOAD_OR_RETURN (-1); + return selinux_ops.security_compute_create (scon, tcon, tclass, newcon); +} + +extern int +security_compute_create_raw (char const *scon, char const *tcon, + security_class_t tclass, char **newcon) +{ + LOAD_OR_RETURN (-1); + return selinux_ops.security_compute_create_raw (scon, tcon, tclass, newcon); +} + +extern security_class_t +string_to_security_class (char const *name) +{ + LOAD_OR_RETURN (0); + return selinux_ops.string_to_security_class (name); +} + +#if HAVE_DECL_MODE_TO_SECURITY_CLASS +static security_class_t +mode_to_security_class_fallback (mode_t mode) +{ + char const *name; + if (S_ISREG (mode)) + name = "file"; + else if (S_ISDIR (mode)) + name = "dir"; + else if (S_ISCHR (mode)) + name = "chr_file"; + else if (S_ISBLK (mode)) + name = "blk_file"; + else if (S_ISFIFO (mode)) + name = "fifo_file"; + else if (S_ISLNK (mode)) + name = "lnk_file"; + else if (S_ISSOCK (mode)) + name = "sock_file"; + else + { + errno = EINVAL; + return 0; + } + + return selinux_ops.string_to_security_class (name); +} + +extern security_class_t +mode_to_security_class (mode_t mode) +{ + LOAD_OR_RETURN (0); + return (selinux_ops.mode_to_security_class + ? selinux_ops.mode_to_security_class (mode) + : mode_to_security_class_fallback (mode)); +} +#endif + +#if HAVE_SELINUX_LABEL_H +extern struct selabel_handle * +selabel_open (unsigned int backend, struct selinux_opt const *opts, + unsigned int nopts) +{ + LOAD_OR_RETURN (NULL); + return selinux_ops.selabel_open (backend, opts, nopts); +} + +extern int +selabel_lookup (struct selabel_handle *handle, char **con, + char const *key, int type) +{ + LOAD_OR_RETURN (-1); + return selinux_ops.selabel_lookup (handle, con, key, type); +} + +extern int +selabel_lookup_raw (struct selabel_handle *handle, char **con, + char const *key, int type) +{ + LOAD_OR_RETURN (-1); + return selinux_ops.selabel_lookup_raw (handle, con, key, type); +} + +extern void +selabel_close (struct selabel_handle *handle) +{ + if (handle && load_libselinux () == 0) + selinux_ops.selabel_close (handle); +} + +extern int +selinux_file_context_cmp (char const *a, char const *b) +{ + LOAD_OR_RETURN (-1); + return selinux_ops.selinux_file_context_cmp (a, b); +} +#endif + +#if HAVE_SELINUX_CONTEXT_H +extern context_t +context_new (char const *con) +{ + LOAD_OR_RETURN (NULL); + return selinux_ops.context_new (con); +} + +extern char const * +context_str (context_t con) +{ + LOAD_OR_RETURN (NULL); + return selinux_ops.context_str (con); +} + +extern void +context_free (context_t con) +{ + if (con && load_libselinux () == 0) + selinux_ops.context_free (con); +} + +extern char const * +context_type_get (context_t con) +{ + LOAD_OR_RETURN (NULL); + return selinux_ops.context_type_get (con); +} + +extern int +context_type_set (context_t con, char const *value) +{ + LOAD_OR_RETURN (-1); + return selinux_ops.context_type_set (con, value); +} + +extern char const * +context_user_get (context_t con) +{ + LOAD_OR_RETURN (NULL); + return selinux_ops.context_user_get (con); +} + +extern int +context_user_set (context_t con, char const *value) +{ + LOAD_OR_RETURN (-1); + return selinux_ops.context_user_set (con, value); +} + +extern char const * +context_role_get (context_t con) +{ + LOAD_OR_RETURN (NULL); + return selinux_ops.context_role_get (con); +} + +extern int +context_role_set (context_t con, char const *value) +{ + LOAD_OR_RETURN (-1); + return selinux_ops.context_role_set (con, value); +} + +extern char const * +context_range_get (context_t con) +{ + LOAD_OR_RETURN (NULL); + return selinux_ops.context_range_get (con); +} + +extern int +context_range_set (context_t con, char const *value) +{ + LOAD_OR_RETURN (-1); + return selinux_ops.context_range_set (con, value); +} +#endif + +#undef LOAD_OR_RETURN diff --git a/m4/selinux-selinux-h.m4 b/m4/selinux-selinux-h.m4 index c964ced072..b199b5895c 100644 --- a/m4/selinux-selinux-h.m4 +++ b/m4/selinux-selinux-h.m4 @@ -1,5 +1,5 @@ # selinux-selinux-h.m4 -# serial 12 -*- Autoconf -*- +# serial 14 -*- Autoconf -*- dnl Copyright (C) 2006-2007, 2009-2026 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -45,18 +45,18 @@ AC_DEFUN([gl_CHECK_HEADER_SELINUX_SELINUX_H], if test $ac_cv_header_selinux_selinux_h = yes; then USE_SELINUX_SELINUX_H=1 + AC_CHECK_DECLS([mode_to_security_class],,, + [[#include <selinux/selinux.h>]]) else USE_SELINUX_SELINUX_H=0 fi - case "$ac_cv_search_getfilecon_raw:$ac_cv_header_selinux_selinux_h" in - no:*) # already warned - ;; - *:no) - AC_MSG_WARN([libselinux was found but selinux/selinux.h is missing.]) + if test $ac_cv_header_selinux_selinux_h != yes; then + if test "$with_selinux" = yes; then + AC_MSG_WARN([selinux/selinux.h is missing.]) AC_MSG_WARN([AC_PACKAGE_NAME will be compiled without SELinux support.]) - ;; - esac + fi + fi else # Do as if <selinux/selinux.h> does not exist, even if # AC_CHECK_HEADERS_ONCE has already determined that it exists. @@ -70,7 +70,7 @@ AC_DEFUN([gl_CHECK_HEADER_SELINUX_SELINUX_H], AC_DEFUN([gl_LIBSELINUX], [ AC_REQUIRE([AC_CANONICAL_HOST]) - AC_REQUIRE([AC_CANONICAL_BUILD]) + AC_REQUIRE([gl_LIBDL]) AC_ARG_WITH([selinux], AS_HELP_STRING([[--without-selinux]], [do not use SELinux, even on systems with SELinux]), @@ -78,25 +78,53 @@ AC_DEFUN([gl_LIBSELINUX], LIB_SELINUX= if test "$with_selinux" != no; then - gl_saved_LIBS=$LIBS - dnl On Android, in Termux, prefer libandroid-selinux.so, because it - dnl defines many more API functions than /system/lib/libselinux.so. - AC_SEARCH_LIBS([getfilecon_raw], [android-selinux selinux], - [test "$ac_cv_search_getfilecon_raw" = "none required" || - LIB_SELINUX=$ac_cv_search_getfilecon_raw]) - LIBS=$gl_saved_LIBS - fi - AC_SUBST([LIB_SELINUX]) - - # Warn if SELinux is found but libselinux is absent; - if test "$ac_cv_search_getfilecon_raw" = no; then - if test "$host" = "$build" \ - && { test -d /sys/fs/selinux || test -d /selinux; }; then - AC_MSG_WARN([This system supports SELinux but libselinux is missing.]) - AC_MSG_WARN([AC_PACKAGE_NAME will be compiled without SELinux support.]) - fi - if test "$with_selinux" = maybe; then + if test "$HAVE_DLOPEN" = 0; then + if test "$with_selinux" = yes; then + AC_MSG_ERROR([SELinux support requires dlopen and dlsym]) + fi with_selinux=no + else + AC_CACHE_CHECK([for libselinux shared library name], + [gl_cv_lib_selinux_soname], + [gl_cv_lib_selinux_soname=no + gl_saved_LIBS=$LIBS + dnl On Android, in Termux, prefer libandroid-selinux because it + dnl defines many more API functions than the system libselinux. + AS_CASE([$host_os], + [*android*], [gl_selinux_libs='android-selinux selinux'], + [*], [gl_selinux_libs=selinux]) + for gl_selinux_lib in $gl_selinux_libs; do + LIBS="$gl_saved_LIBS -l$gl_selinux_lib" + AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[extern int getfilecon_raw (char const *, char **);]], + [[char *con; + return getfilecon_raw (".", &con);]])], + [AS_CASE([$gl_selinux_lib], + [android-selinux], + [gl_DLOPEN_SONAME([gl_selinux_soname], + [libandroid-selinux\.so[[.0-9]]*])], + [*], + [gl_DLOPEN_SONAME([gl_selinux_soname], + [libselinux\.so[[.0-9]]*])]) + AS_CASE([$gl_selinux_soname], + [libandroid-selinux.so* | libselinux.so*], + [gl_cv_lib_selinux_soname=$gl_selinux_soname])]) + AS_CASE([$gl_cv_lib_selinux_soname], + [libandroid-selinux.so* | libselinux.so*], [break]) + done + LIBS=$gl_saved_LIBS]) + AS_CASE([$gl_cv_lib_selinux_soname], + [libandroid-selinux.so* | libselinux.so*], + [AC_DEFINE_UNQUOTED([LIBSELINUX_SONAME], + ["$gl_cv_lib_selinux_soname"], + [libselinux shared object name]) + LIB_SELINUX=$LIBDL], + [*], + [AS_IF([test "$with_selinux" = yes], + [AC_MSG_ERROR([libselinux not found or unusable])]) + with_selinux=no]) fi fi + AC_SUBST([LIB_SELINUX]) ]) diff --git a/modules/selinux-h b/modules/selinux-h index 6db14db546..529ebda97d 100644 --- a/modules/selinux-h +++ b/modules/selinux-h @@ -1,8 +1,9 @@ Description: -SELinux-related headers for systems that lack them. +SELinux-related headers and a dynamically loaded implementation. Files: lib/getfilecon.c +lib/selinux-dlopen.c lib/se-context.in.h lib/se-label.in.h lib/se-selinux.in.h @@ -14,11 +15,16 @@ m4/selinux-label-h.m4 m4/selinux-selinux-h.m4 Depends-on: +bool errno-h -sys_types-h extern-inline gen-header +once +sd-dlopen +stddef-h streq +sys_stat-h +sys_types-h configure.ac: gl_HEADERS_SELINUX_SELINUX_H @@ -72,7 +78,7 @@ MOSTLYCLEANFILES += selinux/label.h selinux/label.h-t MOSTLYCLEANDIRS += selinux if GL_COND_OBJ_GETFILECON -lib_SOURCES += getfilecon.c +lib_SOURCES += getfilecon.c selinux-dlopen.c endif lib_SOURCES += se-context.in.h se-label.in.h se-selinux.in.h \ se-context.c se-label.c se-selinux.c @@ -84,6 +90,7 @@ Include: Link: $(LIB_SELINUX) +$(LIBTHREAD) License: LGPLv2+ diff --git a/tests/test-selinux-selinux-h.c b/tests/test-selinux-selinux-h.c index 57156726df..52d731f169 100644 --- a/tests/test-selinux-selinux-h.c +++ b/tests/test-selinux-selinux-h.c @@ -28,6 +28,9 @@ main () char *con; if (getcon (&con) == 0) freecon (con); +#if HAVE_DECL_MODE_TO_SECURITY_CLASS + (void) mode_to_security_class (0); +#endif return 0; } -- 2.47.3
